DIRECTORY GGAlign, GGCaret, GGError, GGGravity, GGInterfaceTypes, GGModelTypes, GGObjects, GGSelect, GGVector; GGAlignImpl: CEDAR PROGRAM IMPORTS GGCaret, GGGravity, GGObjects, GGSelect, GGVector EXPORTS GGAlign = BEGIN Angle: TYPE = GGModelTypes.Angle; Edge: TYPE = GGModelTypes.Edge; EntityGenerator: TYPE = GGObjects.EntityGenerator; FeatureData: TYPE = REF FeatureDataObj; FeatureDataObj: TYPE = GGGravity.FeatureDataObj; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; Joint: TYPE = GGModelTypes.Joint; JointGenerator: TYPE = GGObjects.JointGenerator; Line: TYPE = GGModelTypes.Line; ObjectBag: TYPE = GGGravity.ObjectBag; Outline: TYPE = GGModelTypes.Outline; Point: TYPE = GGModelTypes.Point; Scene: TYPE = GGModelTypes.Scene; ScalarButtonClient: TYPE = GGInterfaceTypes.ScalarButtonClient; SegAndIndex: TYPE = GGObjects.SegAndIndex; SegmentGenerator: TYPE = GGObjects.SegmentGenerator; SelectionClass: TYPE = GGInterfaceTypes.SelectionClass; Sequence: TYPE = GGModelTypes.Sequence; SymmetryGroup: TYPE = GGGravity.SymmetryGroup; Traj: TYPE = GGModelTypes.Traj; TrajGenerator: TYPE = GGObjects.TrajGenerator; Vector: TYPE = GGModelTypes.Vector; Triggers: TYPE = {joint, segment, symmetryGroup, coordFrame}; JointFireRule: PRIVATE PROC [point: Point, jointNum: NAT, traj: Traj, objectBag: ObjectBag, gargoyleData: GargoyleData] = { firstButton: ScalarButtonClient; firstButton _ gargoyleData.hitTest.slopeButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN GGGravity.JointAddSlopeLine[ degrees: thisButton.value, direction: GGVector.VectorFromAngle[thisButton.value], point: point, jointNum: jointNum, traj: traj, objectBag: objectBag]; ENDLOOP; firstButton _ gargoyleData.hitTest.radiusButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN GGGravity.JointAddCircle[ radius: thisButton.value, point: point, jointNum: jointNum, traj: traj, objectBag: objectBag]; ENDLOOP; }; SegmentFireRule: PRIVATE PROC [segNum: NAT, traj: Traj, objectBag: ObjectBag, gargoyleData: GargoyleData] = { firstButton: ScalarButtonClient; firstButton _ gargoyleData.hitTest.distanceButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN GGGravity.SegmentAddDistanceLines[ distance: thisButton.value, segNum: segNum, traj: traj, objectBag: objectBag]; ENDLOOP; }; SymmetryFireRule: PRIVATE PROC [group: SymmetryGroup, entity: REF ANY, objectBag: ObjectBag, gargoyleData: GargoyleData] = { }; CoordinateFrameFireRule: PRIVATE PROC [objectBag: ObjectBag, gargoyleData: GargoyleData] = { }; TrajectoryFireRule: PRIVATE PROC [hotTraj: Traj, objectBag: ObjectBag, gargoyleData: GargoyleData] = { jointGen: JointGenerator; segGen: SegmentGenerator; point: Point; jointGen _ GGObjects.JointsInTraj[hotTraj]; FOR i: INT _ GGObjects.NextJoint[jointGen], GGObjects.NextJoint[jointGen] UNTIL i = -1 DO point _ GGObjects.FetchJointPos[hotTraj, i]; JointFireRule[point, i, hotTraj, objectBag, gargoyleData]; ENDLOOP; segGen _ GGObjects.SegmentsInTraj[hotTraj]; FOR next: SegAndIndex _ GGObjects.NextSegmentAndIndex[segGen], GGObjects.NextSegmentAndIndex[segGen] UNTIL next.seg = NIL DO SegmentFireRule[next.index, hotTraj, objectBag, gargoyleData]; ENDLOOP; }; SequenceFireRule: PRIVATE PROC [hotSeq: Sequence, objectBag: ObjectBag, gargoyleData: GargoyleData] = { jointGen: JointGenerator; segGen: SegmentGenerator; point: Point; jointGen _ GGObjects.JointsInSequence[hotSeq]; FOR i: INT _ GGObjects.NextJoint[jointGen], GGObjects.NextJoint[jointGen] UNTIL i = -1 DO point _ GGObjects.FetchJointPos[hotSeq.traj, i]; JointFireRule[point, i, hotSeq.traj, objectBag, gargoyleData]; ENDLOOP; segGen _ GGObjects.SegmentsInSequence[hotSeq]; FOR next: SegAndIndex _ GGObjects.NextSegmentAndIndex[segGen], GGObjects.NextSegmentAndIndex[segGen] UNTIL next.seg = NIL DO SegmentFireRule[next.index, hotSeq.traj, objectBag, gargoyleData]; ENDLOOP; }; FilterSequenceExceptClass: PRIVATE PROC [seq: Sequence, gargoyleData: GargoyleData, objectBag: ObjectBag, exceptClass: SelectionClass] = { jointGen: JointGenerator; segGen: SegmentGenerator; joint: Joint; jointGen _ GGObjects.JointsInSequence[seq]; FOR i: INT _ GGObjects.NextJoint[jointGen], GGObjects.NextJoint[jointGen] UNTIL i = -1 DO joint _ GGObjects.FetchJoint[seq.traj, i]; IF GGSelect.IsSelected[joint, gargoyleData, exceptClass] THEN LOOP; JointFireRule[joint.point, i, seq.traj, objectBag, gargoyleData]; ENDLOOP; segGen _ GGObjects.SegmentsInSequence[seq]; FOR next: SegAndIndex _ GGObjects.NextSegmentAndIndex[segGen], GGObjects.NextSegmentAndIndex[segGen] UNTIL next.seg = NIL DO IF GGSelect.IsSelected[next.seg, gargoyleData, exceptClass] THEN LOOP; joint _ GGObjects.FetchJoint[seq.traj, next.index]; IF GGSelect.IsSelected[joint, gargoyleData, exceptClass] THEN LOOP; joint _ GGObjects.FetchJoint[seq.traj, GGObjects.FollowingJoint[seq.traj, next.index]]; IF GGSelect.IsSelected[joint, gargoyleData, exceptClass] THEN LOOP; SegmentFireRule[next.index, seq.traj, objectBag, gargoyleData]; ENDLOOP; }; FilterSelectedTriggers: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag, selectClass: SelectionClass] = { selectGen: EntityGenerator; trajGen: TrajGenerator; selectGen _ GGSelect.SelectedEntities[gargoyleData, selectClass]; FOR entity: REF ANY _ GGObjects.NextEntity[selectGen], GGObjects.NextEntity[selectGen] UNTIL entity = NIL DO WITH entity SELECT FROM hotOutline: Outline => { trajGen _ GGObjects.TrajsInOutline[hotOutline]; FOR hotTraj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL hotTraj = NIL DO TrajectoryFireRule[hotTraj, objectBag, gargoyleData]; ENDLOOP; }; hotSeq: Sequence => SequenceFireRule[hotSeq, objectBag, gargoyleData]; ENDCASE => ERROR; ENDLOOP; }; FilterSelectedTriggersExcept: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag, selectClass: SelectionClass, exceptTraj: Traj] = { selectGen: EntityGenerator; trajGen: TrajGenerator; selectGen _ GGSelect.SelectedEntities[gargoyleData, selectClass]; FOR entity: REF ANY _ GGObjects.NextEntity[selectGen], GGObjects.NextEntity[selectGen] UNTIL entity = NIL DO WITH entity SELECT FROM hotOutline: Outline => { trajGen _ GGObjects.TrajsInOutline[hotOutline]; FOR hotTraj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL hotTraj = NIL DO IF hotTraj = exceptTraj THEN LOOP; TrajectoryFireRule[hotTraj, objectBag, gargoyleData]; ENDLOOP; }; hotSeq: Sequence => { IF hotSeq.traj = exceptTraj THEN LOOP; SequenceFireRule[hotSeq, objectBag, gargoyleData]; }; ENDCASE => ERROR; ENDLOOP; }; FilterSelectedTriggersExceptClass: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag, selectClass, except: SelectionClass] = { selectGen: EntityGenerator; trajGen: TrajGenerator; selectGen _ GGSelect.SelectedEntities[gargoyleData, selectClass]; FOR entity: REF ANY _ GGObjects.NextEntity[selectGen], GGObjects.NextEntity[selectGen] UNTIL entity = NIL DO WITH entity SELECT FROM selOutline: Outline => { IF GGSelect.IsSelected[selOutline, gargoyleData, except] THEN LOOP; trajGen _ GGObjects.TrajsInOutline[selOutline]; FOR selTraj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL selTraj = NIL DO TrajectoryFireRule[selTraj, objectBag, gargoyleData]; ENDLOOP; }; selSeq: Sequence => FilterSequenceExceptClass[selSeq, gargoyleData, objectBag, except]; ENDCASE => ERROR; ENDLOOP; }; FilterUnSelectedPiecesNotHot: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag, selectClass: SelectionClass] = { selectedGen: EntityGenerator; union, diff, seq, whole: Sequence; selectedGen _ GGSelect.SelectedEntities[gargoyleData, selectClass]; FOR selected: REF ANY _ GGObjects.NextEntity[selectedGen], GGObjects.NextEntity[selectedGen] UNTIL selected = NIL DO IF NOT ISTYPE[selected, Sequence] THEN LOOP; seq _ NARROW[selected]; IF GGSelect.IsSelectedInPart[seq, gargoyleData, hot] THEN LOOP; whole _ GGObjects.CreateCompleteSequence[seq.traj]; [union, diff] _ GGObjects.CombineSequences[whole, seq]; IF NOT GGObjects.IsEmptySequence[diff] THEN SequenceFireRule[diff, objectBag, gargoyleData]; ENDLOOP; }; SensitiveTrajectories: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag] = { trajGen: TrajGenerator; trajGen _ GGObjects.TrajsInScene[gargoyleData.scene]; FOR traj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj = NIL DO GGGravity.AddTrajectory[traj, objectBag]; ENDLOOP; }; SensitiveSelectedTrajectories: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag, selectClass: SelectionClass] = { trajGen: TrajGenerator; trajGen _ GGObjects.TrajsInScene[gargoyleData.scene]; FOR traj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj = NIL DO IF GGSelect.IsSelectedInPart[traj, gargoyleData, selectClass] THEN GGGravity.AddTrajectory[traj, objectBag]; ENDLOOP; }; SensitiveTrajectoriesExcept: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag, exceptTraj: Traj] = { trajGen: TrajGenerator; trajGen _ GGObjects.TrajsInScene[gargoyleData.scene]; FOR traj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj = NIL DO IF traj = exceptTraj THEN LOOP; GGGravity.AddTrajectory[traj, objectBag]; ENDLOOP; }; SensitiveTrajectoriesNotSelected: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag] = { trajGen: TrajGenerator; trajGen _ GGObjects.TrajsInScene[gargoyleData.scene]; FOR traj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj = NIL DO IF GGSelect.IsSelectedInPart[traj, gargoyleData, normal] THEN LOOP; GGGravity.AddTrajectory[traj, objectBag]; ENDLOOP; }; SensitiveUnSelectedPieces: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag, selectClass: SelectionClass] = { selectedGen: EntityGenerator; diff, seq, whole: Sequence; selectedGen _ GGSelect.SelectedEntities[gargoyleData, selectClass]; FOR selected: REF ANY _ GGObjects.NextEntity[selectedGen], GGObjects.NextEntity[selectedGen] UNTIL selected = NIL DO IF NOT ISTYPE[selected, Sequence] THEN LOOP; seq _ NARROW[selected]; IF GGSelect.IsSelectedInPart[seq, gargoyleData, hot] THEN LOOP; whole _ GGObjects.CreateCompleteSequence[seq.traj]; [----, diff] _ GGObjects.CombineSequences[whole, seq]; IF NOT GGObjects.IsEmptySequence[diff] THEN GGGravity.AddSequence[diff, objectBag]; ENDLOOP; }; SelectPointMode: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag] = { FilterSelectedTriggers[gargoyleData, objectBag, hot]; SensitiveTrajectories[gargoyleData, objectBag]; }; AddMode: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag] = { caretTraj: Traj; caretSeq: Sequence; jointNum: NAT; [caretTraj, ----, ----, jointNum, ----] _ GGCaret.GetChair[gargoyleData.caret]; FilterSelectedTriggersExcept[gargoyleData, objectBag, hot, caretTraj]; IF caretTraj # NIL THEN { IF jointNum = 0 THEN caretSeq _ GGObjects.CreateSimpleSequence[caretTraj, 1, GGObjects.HiJoint[caretTraj]] ELSE IF jointNum = GGObjects.HiJoint[caretTraj] THEN caretSeq _ GGObjects.CreateSimpleSequence[caretTraj, 0, GGObjects.HiJoint[caretTraj] - 1] ELSE ERROR; SequenceFireRule[caretSeq, objectBag, gargoyleData]; }; SensitiveTrajectoriesExcept[gargoyleData, objectBag, caretTraj]; IF caretTraj # NIL THEN GGGravity.AddSequence[caretSeq, objectBag]; }; DragMode: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag] = { FilterSelectedTriggersExceptClass[gargoyleData, objectBag, hot, normal]; FilterUnSelectedPiecesNotHot[gargoyleData, objectBag, normal]; SensitiveTrajectoriesNotSelected[gargoyleData, objectBag]; SensitiveUnSelectedPieces[gargoyleData, objectBag, normal]; }; DragStartUpMode: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag] = { FilterSelectedTriggers[gargoyleData, objectBag, normal]; FilterSelectedTriggers[gargoyleData, objectBag, hot]; SensitiveSelectedTrajectories[gargoyleData, objectBag, normal]; SensitiveSelectedTrajectories[gargoyleData, objectBag, hot]; }; SelectTrajectoryMode: PRIVATE PROC [gargoyleData: GargoyleData, objectBag: ObjectBag] = { SensitiveTrajectories[gargoyleData, objectBag]; }; AddItemsForAction: PUBLIC PROC [gargoyleData: GargoyleData, objectBag: ObjectBag, action: ATOM] = { SELECT action FROM $SelectPoint => SelectPointMode[gargoyleData, objectBag]; $Add => AddMode[gargoyleData, objectBag]; $Drag => DragMode[gargoyleData, objectBag]; $DragStartUp => DragStartUpMode[gargoyleData, objectBag]; $SelectTrajectory => SelectTrajectoryMode[gargoyleData, objectBag]; ENDCASE => ERROR; }; END. ΎGGAlignImpl.mesa Created by Eric Bier on June 5, 1985 3:41:39 pm PDT. Last edited by Bier on November 7, 1985 9:44:08 pm PST. Trigger Classes and Firing Rules Alignment requires identifying a set of alignment objects which can be snapped-to using the Gravity functions described in GGGravity.mesa. Almost all alignment objects are derived from a set of trigger objects, by a set of Firing Rules. For instance, if we draw horizontal lines thru all of the vertices of a trajectory, the vertices are the trigger objects, the horizontal lines are the alignment objects, and the rule "compute a horizontal line passing through each vertex x" is the firing rule. Different trigger classes and different firing rules are appropriate under different circumstances. Our decision in Gargoyle is to let the user choose the firing rules manually, via menus. The same firing rules are applied under all circumstances. The set of trigger objects, however, depends on which action is being performed. AddItemsForAction associates a different atom for each situation requiring a different set of trigger objects. These atoms include $Drag $SelectPoint $Add and $SetupDrag. Joint Firing Rules: SlopeLine, Circle, Vector Segment Firing Rules: FourAngleLines, ColinearLine Symmetry Firing Rules: SymmetryAddLines, SymmetryAddPoints Coordinate Frame Firing Rules: AddPoint AddXLine AddYLine SlopeLine Circle Vector (not yet implemented) Parallel Lines at Given Distance NotYetImplemented. NotYetImplemented. Special Rules for efficiency. Joints as triggers. Segments as triggers. Joints as triggers. Segments as triggers. Filtering Triggers. Which triggers are active depends on which action is being performed. However, there is a commonality between actions. Often, the active triggers are those that are in a particular selected set. Or are of a particular type, e.g. Joint, Anchor, Segment, Symmetry, or coordinate frame. These procedures try to capture that commonality. Joints as triggers. Segments as triggers. selectClass vertices and segments are triggers. Add selected vertices and segments symmetry groups not yet implemented. selectClass vertices and segments are triggers. Add selected vertices and segments symmetry groups not yet implemented. SelectClass vertices and segments are triggers. Add selected vertices and segments, except those selected with the except class. symmetry groups not yet implemented. What we really want is to find the intersection of two sets: Not selected and not hot. Sensitive. Procedures to choose which vertices and segments should themselves be gravity sensitive. This filter is special since it ignores the menu settings (and hot objects) in determining fire rules. Only the trajectories themselves are added to the objectBag. All unselected trajectories (no part is selected) are added to the objectBag. What we really want is to find the intersection of two sets: Not selected and not hot. The appropriate objectBags for different editing actions. Triggers are: 1) All hot vertices, segments, symmetry groups. Sensitive trajectories are: 1) All. Triggers. Sensitive. Triggers are: 1) All hot vertices, segments, symmetry groups, except the caret trajectory. 2) All parts of the caret trajectory, except the segment being added. Sensitive trajectories are: 1) All trajectories except the caret trajectory. 2) All parts of the caret trajectory, except the segment being added. Triggers. Sensitive. Triggers are: 1) All hot vertices, segments, symmetry groups (except those being dragged). 2) All unselected pieces of selected trajectories. Sensitive: 1) All unselected trajectories. 2) All unselected pieces of selected trajectories. Triggers: All hot vertices, segments, symmetry groups (except those being dragged) should trigger alignment lines. The "not hot" clause is added to avoid duplication. Sensitive. Triggers are: 1) All selected vertices, segments, and symmetry groups. 2) All hot vertices, segments, symmetry groups. Sensitive: 1) All selected vertices, segments. 2) All hot vertices, segments. Warning: If an object is both selected and hot, this procedure may let it trigger twice. Triggers: These are the objects about to be dragged. We want to make it easy to pick them up with the caret. We may also want to select their alignment lines. We also may want the caret to begin on an alignment line triggered by specially designated hot objects. Sensitive: Triggers are: none Sensitive: 1) All vertices and segments. The one procedure to call. Κ —˜Ihead1™J™4J™7J˜šΟk ˜ Jšœ˜J˜J˜J˜ J˜Jšœ ˜ J˜ J˜ Jšœ ˜ —J˜šœ œ˜Jšœ2˜9Jšœ ˜—Jš˜J˜Jšœœ˜!Jšœœ˜Jšœœ˜2Jšœ œœ˜'Jšœœ˜0Jšœœ!˜3Jšœœ˜!Jšœœ˜0Jšœœ˜Jšœ œ˜&Jšœ œ˜%Jšœœ˜!Jšœœ˜!Jšœœ'˜?Jšœ œ˜*Jšœœ˜4Jšœœ#˜7Jšœ œ˜'Jšœœ˜.Jšœœ˜Jšœœ˜.Jšœœ˜#K™ Ibodyšœ(ΟiœŠžœ‘™σLšœΝΟnœš™ψL™Jšœ œ/˜=J˜JšœŸ™.IprocšœΟb™3Mšœ #™;Jšœ ™9J™šŸ œœœœC˜{Mšœ ˜ šŸ ™ Mšœ0˜0šœ?œœ˜[šœ˜šœ˜Jšœ˜Jšœ6˜6Jšœ ˜ Jšœ˜Jšœ ˜ Jšœ˜———Jšœ˜—šŸ™Mšœ1˜1šœ?œœ˜[šœ˜šœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ ˜ Jšœ˜———Jšœ˜—JšŸ™J˜J˜—šŸœœœ œC˜mMšœ ˜ š  ™ Mšœ3˜3šœ?œœ˜[šœ˜šœ Ÿœ˜"Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜———Jšœ˜—J˜J˜—š Ÿœœœ œœ7˜|J™J˜J˜—šŸœœœ7˜\J™J˜J˜—J™J™šŸœœœF˜fJ˜J˜˜ Mšœ™—Mšœ+˜+šœœ@œ˜YMšœ,˜,Mš  œ-˜:—šœ˜J™—Jšœ+˜+šœbœ œ˜|Jš œ/˜>—Jšœ˜J˜J˜—šŸœœœI˜gJ˜J˜˜ M™—Mšœ.˜.šœœ@œ˜YMšœ0˜0Mš  œ1˜>—šœ˜J™—Jšœ.˜.šœbœ œ˜|Jš œ3˜B—Jšœ˜J˜J˜—J™J™ζJ˜šŸœœœc˜ŠJ˜J˜J˜ M™Mšœ œ˜+šœœ@œ˜YMšœ œ ˜*Mšœ7œœ˜CMš  œ œ ˜A—Mšœ˜J™Jšœ œ˜+šœbœ œ˜|Mšœ:œœ˜FMšœ œ˜3Mšœ7œœ˜CMšœ œ  œ˜WMšœ7œœ˜CJš œ  œ ˜?—Jšœ˜J˜J˜J˜—šŸœœœT˜xJšœ/™/Jšœ˜J˜J™"Jšœ œ  œ˜Aš œ œœDœ œ˜lJšœœ˜˜J˜/šœJœ œ˜cJšŸœ#˜5—Jšœ˜J˜—JšœŸœ"˜FJšœœ˜—Jšœ˜J™$J˜J˜—šŸœœœf˜Jšœ/™/Jšœ˜J˜J™"JšœA˜Aš œ œœDœ œ˜lJšœœ˜˜J˜/šœJœ œ˜cJšœœœ˜"Jš œ#˜5—Jšœ˜J˜—šœ˜Jšœœœ˜&Jš œ"˜2J˜—Jšœœ˜—Jšœ˜J™$J˜J˜—šŸ!œœœ\˜‹J™/Jšœ˜J˜JšœP™PJšœA˜Aš œ œœDœ œ˜lJšœœ˜˜Jšœ7œœ˜CJ˜/šœJœ œ˜cJš œ#˜5—Jšœ˜J˜—šœ˜Jš œ*˜C—Jšœœ˜—Jšœ˜J™$J˜J˜—šŸœœœT˜~J˜Jšœ"˜"JšœC˜Cš œ œœHœ œ˜tJš œœœœœ˜,Jšœœ ˜šœ3œœ˜?J™W—Jšœ3˜3Jšœ7˜7Jšœœ!œ œ ˜\—Jšœ˜˜J˜——J™J™dJ˜šŸ Πbn œœœ7˜ZJšœ˜Jšœ  œ˜5šœGœœ˜]Jšœ   œ˜)—Jšœ˜J˜J˜—š‘œœœT˜Jšœ˜Jšœ  œ˜5šœGœœ˜]Jšœ<œ œ˜l—Jšœ˜J˜J˜—šŸœœœI˜rJšœ€™€Jšœ˜Jšœ  œ˜5šœGœœ˜]Jšœœœ˜Jš œ˜)—Jšœ˜J˜J˜—šŸ œœœ7˜eJšœM™MJšœ˜Jšœ  œ˜5šœGœœ˜]Jšœ7œœ˜CJš œ˜)—Jšœ˜J˜—J˜š  ŸœœœT˜{J˜Jšœ˜JšœC˜Cš œ œœHœ œ˜tJš œœœœœ˜,Jšœœ ˜šœ3œœ˜?J™W—Jšœ3˜3Jšœ6˜6Jšœœ!œ œ˜S—Jšœ˜˜J˜——J™9J™šŸœœœ7˜TJ™J™0J™™J™ —š œ˜5J™ —Jš œ˜/J˜J˜—šŸœœœ7˜LJ™J™MJ™FJ™J™1J™FJšœ˜J˜šœ œ˜J™ —Jšœ Οcœ’œ ’œ)˜OJš œ*˜Fšœ œœ˜šœ˜JšœU˜U—šœœ)˜4JšœY˜Y—Jšœœ˜ Jš œ$˜4J˜J™ —Jš œ%˜@Jšœ œœ   œ˜CJ˜J˜—šŸœœœ7˜MJ™J™MJ™3J™ J™ ™3J™ —š !œ œ œ˜HJ™h—š œ œ˜>J™3J™ —Jš  œ˜:Jš œ œ˜;J˜J˜—šŸœœœ7˜TJ™J™9J™0J™ J™$J™ J™YJ™ š œ œ˜8J™–—š œ œ˜5J™g—J™ Jš œ"˜?Jš œ˜