DIRECTORY GriffinDefs: FROM "GriffinDefs", Rope USING [ROPE, Equal], MenuDefs: FROM "MenuDefs", ObjectDefs: FROM "ObjectDefs", RealFns: FROM "RealFns", StyleDefs: FROM "StyleDefs", PointDefs: FROM "PointDefs", OpDefs: FROM "OpDefs", XFormDefs: FROM "XFormDefs", GriffinMemoryDefs: FROM "GriffinMemoryDefs", RefreshDefs: FROM "RefreshDefs", GriffinMenusInterface, RelationDefs: FROM "RelationDefs"; ObjectOps: CEDAR PROGRAM IMPORTS GriffinDefs, MenuDefs, ObjectDefs, Rope, GriffinMemoryDefs, RealFns, XFormDefs, PointDefs, RefreshDefs, RelationDefs EXPORTS GriffinDefs, OpDefs, GriffinMenusInterface = BEGIN OPEN ObjectDefs,PointDefs,GriffinMemoryDefs; xftype: {map,scale,scalex,scaley,rotate}; oltype: {top,bottom,up1,down1}; TL,BR: ScrPt; ROPE: TYPE = Rope.ROPE; MarkObject: ObjectProc = {RefreshDefs.MarkObject[obj]}; EraseAndSave: ObjectProc = {RefreshDefs.EraseAndSave[obj]}; OverallMBB: ObjectProc= BEGIN IF obj.tl[X]BR[X] THEN BR[X] _ obj.br[X]; IF obj.br[Y] >BR[Y] THEN BR[Y] _ obj.br[Y]; END; AnySelected: PROCEDURE RETURNS[BOOLEAN] = BEGIN anyselected: BOOLEAN _ FALSE; IsSelected: ObjectProc=BEGIN anyselected _ TRUE; END; ForAllSelectedDo[IsSelected]; RETURN[anyselected]; END; Delete: PUBLIC MenuDefs.MenuProc = BEGIN DeleteObjs: ObjectProc=BEGIN DeSelectObject[obj]; RefreshDefs.EraseAndSave[obj]; obj.deleted _ TRUE; END; IF AnySelected[] THEN BEGIN ExpungeObjects[]; ForAllSelectedDo[DeleteObjs]; RefreshDefs.RestoreScreen[]; END; END; Undo: PUBLIC MenuDefs.MenuProc = BEGIN Undelete: ObjectProc = BEGIN IF ~obj.deleted THEN RETURN; obj.deleted _ FALSE; IF obj.cluster # 0 THEN [] _ SelectCluster[obj.cluster] ELSE [] _ SelectObject[obj]; RefreshDefs.MarkObject[obj]; END; ForAllObjects[Undelete]; RefreshDefs.RestoreScreen[]; END; Transfer: PUBLIC MenuDefs.MenuProc = BEGIN view: View _ IF objectMenu.view=main THEN alternate ELSE main; token: ObjectHandle _ NIL; TransferObjs: ObjectProc=BEGIN RefreshDefs.EraseAndSave[obj]; IF (token _ ReturnSelectToken[obj]) # NIL THEN BEGIN RefreshDefs.EraseAndSave[token]; token.view _ view; END; obj.view _ view; END; IF ~AnySelected[] THEN GriffinDefs.UserMessage["Please make a selection"]; ForAllSelectedDo[TransferObjs]; RefreshDefs.RestoreScreen[]; END; SelObj: TYPE = RECORD[up,down: REF SelObj, item: ObjectHandle]; ChangeOverlap: PUBLIC MenuDefs.MenuProc = BEGIN string: ROPE _ MenuDefs.MenuString[item]; topObj,bottomObj: REF SelObj _ NIL; ptr,next: REF SelObj _ NIL; ListSelected: ObjectProc=BEGIN selObj: REF SelObj _CZone.NEW[SelObj]; selObj^ _ [up: NIL,down: topObj,item: obj]; IF bottomObj=NIL THEN bottomObj _ topObj _ selObj ELSE BEGIN topObj.up _ selObj; topObj _ selObj; END; END; Up: PROCEDURE=BEGIN selObj: REF SelObj _topObj; FOR selObj _ topObj, selObj.down UNTIL selObj=NIL DO FlipUpObject[selObj.item]; ENDLOOP; END; Down: PROCEDURE=BEGIN selObj: REF SelObj ; FOR selObj _ bottomObj, selObj.up UNTIL selObj=NIL DO FlipDownObject[selObj.item]; ENDLOOP; END; Bottom: PROCEDURE=BEGIN selObj: REF SelObj _topObj; FOR selObj _ topObj, selObj.down UNTIL selObj=NIL DO SinkObject[selObj.item]; ENDLOOP; END; Top: PROCEDURE=BEGIN selObj: REF SelObj ; FOR selObj _ bottomObj, selObj.up UNTIL selObj=NIL DO FloatObject[selObj.item]; ENDLOOP; END; IF ~AnySelected[] THEN GriffinDefs.UserMessage["Please make a selection"]; ForAllSelectedDo[ListSelected]; IF bottomObj=NIL THEN RETURN; --none found oltype _ SELECT TRUE FROM Rope.Equal[string,"Top",FALSE] => top, Rope.Equal[string,"Bottom",FALSE] => bottom, Rope.Equal[string,"Up One",FALSE] => up1, Rope.Equal[string,"Down One",FALSE] => down1, ENDCASE => ERROR; SELECT oltype FROM top => Top[]; bottom => Bottom[]; up1 => Up[]; down1 => Down[]; ENDCASE; ForAllSelectedDo[MarkObject]; RefreshDefs.RestoreScreen; ptr _ bottomObj; UNTIL ptr=NIL DO next _ptr.up; ptr.up _ NIL; ptr _ next; ENDLOOP; END; XForm: PUBLIC MenuDefs.MenuProc = BEGIN ENABLE XFormDefs.ProblemWithXForms => BEGIN IF Rope.Equal[string,"Singular transform",FALSE] THEN SIGNAL GriffinDefs.UserMessage["Transform will flatten picture"] ELSE SIGNAL GriffinDefs.UserMessage["ProblemWith Transform"]; END; string: ROPE _ MenuDefs.MenuString[item]; cps: PointDefs.ObjPtSequence _ ReadCPs[]; matrix: XFormDefs.XFMDescriptor _ CZone.NEW[XFormDefs.XFormMatrix]; clusterRelation: RelationDefs.Relation; MoveObjs: ObjectProc=BEGIN MoveObject[obj,ObjToScr[cps[0]],ObjToScr[cps[1]]]; END; CopyObjs: ObjectProc=TRUSTED BEGIN OPEN RelationDefs; newobj: ObjectHandle; newcluster: ClusterID; IF NOT obj.selected OR NOT Visible[obj] THEN RETURN; newobj _ CopyObject[obj]; IF obj.cluster # 0 THEN BEGIN IF Right[clusterRelation,obj.cluster] = notFound THEN BEGIN newcluster _ GetNextClusterID[]; AddPair[clusterRelation, obj.cluster,newcluster]; END ELSE newcluster _ Right[clusterRelation,obj.cluster]; RefreshDefs.EraseAndSave[ReturnSelectToken[obj]]; newobj.cluster _ newcluster; END ELSE BEGIN [] _ SelectObject[newobj]; RefreshDefs.EraseAndSave[ReturnSelectToken[obj]]; DeSelectObject[obj]; END; END; SelectNewClusters: PROCEDURE[leftPart, rightPart: CARDINAL] = BEGIN [] _ SelectCluster[rightPart]; DeSelectCluster[leftPart]; END; XFormObjs: ObjectProc=BEGIN ObjectDefs.XFormObject[obj,matrix]; END; IF cps=NIL OR cps.length <=1 THEN BEGIN GriffinDefs.UserMessage["All transforms need at least two points"]; RETURN; END; IF ~AnySelected[] THEN GriffinDefs.UserMessage["Please make a selection"]; XFormDefs.InitXForms[matrix]; xftype _ SELECT TRUE FROM Rope.Equal[string,"Map",FALSE] => map, Rope.Equal[string,"Scale",FALSE] => scale, Rope.Equal[string,"ScaleX",FALSE] => scalex, Rope.Equal[string,"ScaleY",FALSE] => scaley, Rope.Equal[string,"Rotate",FALSE] => rotate, ENDCASE => ERROR; SELECT xftype FROM map => Map[matrix]; scale => Scale[matrix,both]; scalex => Scale[matrix,xonly]; scaley => Scale[matrix,yonly]; rotate => Rotate[matrix]; ENDCASE; RefreshDefs.EraseAndSaveAllCPs[]; DeleteAllCPs[]; IF MenuDefs.IsSelected[copy] THEN TRUSTED BEGIN clusterRelation _ RelationDefs.CreateRelation[]; ForAllObjectsThroughObject[CopyObjs, GetTopPictureObj[]]; RelationDefs.ForAllPairs[clusterRelation,SelectNewClusters]; RelationDefs.DestroyRelation[clusterRelation]; END ELSE ForAllSelectedDo[ EraseAndSave]; IF cps.length=2 AND xftype=map THEN BEGIN ForAllSelectedDo[MoveObjs]; END ELSE BEGIN ForAllSelectedDo[XFormObjs]; END; ForAllSelectedDo[ MarkObject]; RefreshDefs.RestoreScreen[]; END; Toggle: PUBLIC MenuDefs.MenuProc = BEGIN OPEN MenuDefs; IF IsSelected[item] THEN Deselect[item] ELSE Select[item]; END; Rotate: PROCEDURE[matrix: XFormDefs.XFMDescriptor] = BEGIN OPEN XFormDefs; cps: PointDefs.ObjPtSequence _ ReadCPs[]; npts: INTEGER _ (IF cps=NIL THEN 0 ELSE cps.length); dorig: ObjPt _ cps[0]; negdorig: ObjPt _ [-cps[0][X],-cps[0][Y]]; dx,dy,theta: REAL; IF npts>3 THEN GriffinDefs.UserMessage["Only 2 and 3 point rotate is valid"]; dx _ cps[1][X]-cps[0][X]; dy _ cps[1][Y]-cps[0][Y]; theta _ RealFns.ArcTan[dy,dx]; IF npts>=3 THEN BEGIN theta1: REAL; dx _ cps[2][X]-cps[0][X]; dy _ cps[2][Y]-cps[0][Y]; theta1 _ RealFns.ArcTan[dy,dx]; theta _ theta1-theta; END; Translate[dorig,matrix]; Rotate[theta,z,matrix]; Translate[negdorig,matrix]; END; Scale: PROCEDURE[matrix: XFormDefs.XFMDescriptor,direction: {both,xonly,yonly}] = BEGIN OPEN XFormDefs; cps: PointDefs.ObjPtSequence _ ReadCPs[]; npts: INTEGER _ (IF cps=NIL THEN 0 ELSE cps.length); sx,sy: REAL; dorig: ObjPt _ cps[0]; tl,br: ObjPt; negdorig: ObjPt _ [-cps[0][X],-cps[0][Y]]; dx1,dy1,dx2,dy2: REAL; IF npts>3 THEN GriffinDefs.UserMessage["Only 2 and 3 point scale is valid"]; IF npts=2 THEN BEGIN TL _ [77777B,77777B]; --init for OverallMBB BR _ [0,0]; ForAllSelectedDo[OverallMBB]; tl _ ScrToObj[TL]; br _ ScrToObj[BR]; dx1 _ br[X]-tl[X]; dy1 _ tl[Y]-br[Y]; --object space dx2 _ ABS[cps[1][X]-cps[0][X]]; dy2 _ ABS[cps[1][Y]-cps[0][Y]]; END ELSE BEGIN dx2 _ cps[2][X]-cps[0][X]; dy2 _ cps[2][Y]-cps[0][Y]; dx1 _ cps[1][X]-cps[0][X]; dy1 _ cps[1][Y]-cps[0][Y]; END; Translate[dorig,matrix]; SELECT direction FROM both => BEGIN IF dx1=0 OR dy1=0 THEN GriffinDefs.UserMessage["Transform will flatten picture"]; sx _ dx2/dx1; sy _ dy2/dy1; Scale[[sx,sy],matrix]; END; xonly => BEGIN IF dx1=0 THEN GriffinDefs.UserMessage["Transform will flatten picture"]; sx _ dx2/dx1; Scale[[sx,1],matrix]; END; yonly => BEGIN IF dy1=0 THEN GriffinDefs.UserMessage["Transform will flatten picture"]; sy _ dy2/dy1; Scale[[1,sy],matrix]; END; ENDCASE; Translate[negdorig,matrix]; END; Map: PROCEDURE[matrix: XFormDefs.XFMDescriptor] = BEGIN OPEN XFormDefs; cps: PointDefs.ObjPtSequence _ ReadCPs[]; npts: INTEGER _ (IF cps=NIL THEN 0 ELSE cps.length); pts: PointDefs.ObjPtSequence; dorig: ObjPt _ cps[0]; negdorig: ObjPt _ [-cps[0][X],-cps[0][Y]]; IF npts>6 THEN GriffinDefs.UserMessage["Maximum of 6 points for map"]; SELECT npts FROM =3 => BEGIN pts _ CZone.NEW[ObjPtSequenceRec[4]]; pts[0] _ cps[0]; pts[1] _ cps[1]; pts[2] _ cps[0]; pts[3] _ cps[2]; npts _ 4; END; =4 => pts _ cps; =5 => BEGIN pts _ CZone.NEW[ObjPtSequenceRec[6]]; pts[0] _ cps[0]; pts[1] _ cps[1]; pts[2] _ cps[2]; pts[3] _ cps[0]; pts[4] _ cps[3]; pts[5] _ cps[4]; npts _ 6; END; ENDCASE=> pts _ cps; Translate[dorig,matrix]; SELECT npts FROM =4 => XForm4Pts[pts,matrix]; >=6 => XForm6Pts[pts,matrix]; ENDCASE; Translate[negdorig,matrix]; END; Cluster: PUBLIC MenuDefs.MenuProc = BEGIN id: ClusterID _ GetNextClusterID[]; called: BOOLEAN _ FALSE; token: ObjectHandle _ NIL; clu: ObjectProc=BEGIN obj.cluster _ id; called _ TRUE; IF token # NIL THEN token _ DeleteObject[token]; token _ ReturnSelectToken[obj]; RefreshDefs.EraseAndSave[token]; END; IF ~AnySelected[] THEN GriffinDefs.UserMessage["Please make a selection"]; ForAllSelectedDo[clu]; IF called THEN BEGIN GriffinDefs.ShowUserMessage["New cluster made"]; RefreshDefs.RestoreScreen[]; END; END; UnCluster: PUBLIC MenuDefs.MenuProc = BEGIN called: BOOLEAN _ FALSE; ctoken: ObjectHandle; clu: ObjectProc=BEGIN select: ObjectHandle; IF obj.cluster IN [0..OpenCluster] THEN RETURN; obj.cluster _ 0; called _ TRUE; IF (ctoken _ ReturnSelectToken[obj]) # NIL THEN BEGIN RefreshDefs.EraseAndSave[ctoken]; RETURN; END; obj.selected _ FALSE; select _ SelectObject[obj]; RefreshDefs.MarkObject[select]; END; IF ~AnySelected[] THEN GriffinDefs.UserMessage["Please make a selection"]; ForAllSelectedDo[clu]; IF called THEN GriffinDefs.ShowUserMessage["Cluster unmade"]; END; DeselectAll: PUBLIC MenuDefs.MenuProc = BEGIN DS: ObjectProc = BEGIN RefreshDefs.EraseAndSave[ReturnSelectToken[obj]]; DeSelectObject[obj]; END; ObjectDefs.ForAllSelectedDo[DS]; RefreshDefs.RestoreScreen[]; END; SelectAll: PUBLIC MenuDefs.MenuProc = BEGIN OPEN ObjectDefs; SelectObjs: ObjectProc=BEGIN token: ObjectHandle _ IF obj.cluster = 0 THEN SelectObject[obj] ELSE SelectCluster[obj.cluster]; IF token#NIL THEN RefreshDefs.MarkObject[token]; END; ForAllVisibleObjects[SelectObjs]; RefreshDefs.RestoreScreen[]; END; CopyObjects: PUBLIC PROCEDURE[Down,Up: ScrPt] = BEGIN OPEN ObjectDefs; new: ObjectHandle _ GetObjectHandle[Down]; selected: BOOLEAN; id: ClusterID _ 0; co: ObjectProc = BEGIN IF selected THEN BEGIN RefreshDefs.EraseAndSave[ReturnSelectToken[obj]]; IF id = 0 THEN DeSelectObject[obj]; END; obj _ CopyObject[obj] ; obj.cluster _ id; MoveObject[obj,Down,Up]; RefreshDefs.MarkObject[obj]; IF selected AND id = 0 THEN [] _ SelectObject[obj]; END; IF new=NIL THEN RETURN; selected _ new.selected; IF new.objectType=menu OR new.objectType=token OR new.cluster=OpenCluster THEN RETURN; IF ABS[Down[X]-Up[X]]<1 AND ABS[Down[Y]-Up[Y]]<1 THEN RETURN; IF new.cluster=0 THEN [] _ co[new] -- not a clustered object ELSE BEGIN id _ GetNextClusterID[]; ForAllInCluster[new.cluster,co]; IF selected THEN BEGIN DeSelectCluster[new.cluster]; [] _ SelectCluster[id]; END; END; RefreshDefs.RestoreScreen[]; END; MoveObjects: PUBLIC PROCEDURE[Down,Up: ScrPt] = BEGIN object: ObjectDefs.ObjectHandle _ ObjectDefs.GetObjectHandle[Down] ; move: ObjectProc = BEGIN RefreshDefs.EraseAndSave[obj]; ObjectDefs.MoveObject[obj,Down,Up]; RefreshDefs.MarkObject[obj]; END; IF object=NIL THEN RETURN; IF ABS[Down[X]-Up[X]]<1 AND ABS[Down[Y]-Up[Y]]<1 THEN RETURN; IF object.cluster=OpenCluster THEN RETURN; --unfortuneate IF object.cluster=0 THEN [] _ move[object] ELSE ForAllInCluster[object.cluster,move]; RefreshDefs.RestoreScreen[]; END; PlaceControlPoint: PUBLIC PROCEDURE[pt: ScrPt] = BEGIN top: ObjectHandle _ GetObjectHandle[pt]; IF top=NIL OR top.objectType#menu THEN ObjectDefs.AddToken[pt, CP] END; DeleteControlPoint: PUBLIC PROCEDURE[Down,Up: ScrPt] = BEGIN OPEN ObjectDefs; DelCP: ObjectProc = TRUSTED BEGIN IF obj=NIL THEN RETURN; WITH obj SELECT FROM token=> IF tokenType = CP THEN BEGIN RefreshDefs.EraseAndSave[obj]; []_DeleteObject[obj]; END; ENDCASE; END; IF NOT ForAllInBoxDo[Down, Up, DelCP] THEN ForObjectPointedAtDo[Down, Up, DelCP]; RefreshDefs.RestoreScreen[]; END; DeselectObjects: PUBLIC PROCEDURE[Down,Up: ScrPt] = BEGIN Desel: ObjectProc = BEGIN IF obj=NIL OR obj.objectType=token OR obj.objectType=menu THEN RETURN; IF obj.cluster = 0 THEN [] _ DS[obj] ELSE ForAllInCluster[obj.cluster, DS]; END; DS: ObjectProc = BEGIN RefreshDefs.EraseAndSave[ReturnSelectToken[obj]]; DeSelectObject[obj]; END; IF NOT ForAllPictureObjectsInBoxDo[Down, Up, Desel] THEN ForObjectPointedAtDo[Down, Up, Desel]; RefreshDefs.RestoreScreen[]; END; SelectObjects: PUBLIC PROCEDURE[Down,Up: ScrPt] = BEGIN OPEN ObjectDefs,RefreshDefs; Sel: ObjectProc = BEGIN IF obj=NIL OR obj.objectType=token OR obj.objectType=menu OR obj.cluster=OpenCluster THEN RETURN; [] _ S[obj]; END; S: ObjectProc = BEGIN obj _ IF obj.cluster = 0 THEN SelectObject[obj] ELSE SelectCluster[obj.cluster]; IF obj#NIL THEN MarkObject[obj]; END; IF NOT ForAllPictureObjectsInBoxDo[Down, Up, Sel] THEN ForObjectPointedAtDo[Down, Up, Sel]; RefreshDefs.RestoreScreen[]; END; ForObjectPointedAtDo: PROCEDURE[Down,Up: ScrPt,proc: ObjectProc] = BEGIN upObj,downObj: ObjectHandle; upObj _ GetObjectHandle[Up]; IF upObj=NIL THEN RETURN; downObj _ GetObjectHandle[Down]; IF upObj=downObj OR downObj=NIL THEN [] _ proc[upObj] ; END; objectMenu, xformMenu, overlapMenu: MenuDefs.MenuHandle_NIL; copy: MenuDefs.MenuItemHandle_NIL; ToggleObjectMenu: PUBLIC PROC = { IF objectMenu.visible THEN MenuDefs.HideMenu[objectMenu] ELSE MenuDefs.ShowMenu[objectMenu]; RefreshDefs.RestoreScreen[]; }; ToggleTransformMenu: PUBLIC PROC = { IF xformMenu.visible THEN MenuDefs.HideMenu[xformMenu] ELSE MenuDefs.ShowMenu[xformMenu]; RefreshDefs.RestoreScreen[]; }; ToggleOverlapMenu: PUBLIC PROC = { IF overlapMenu.visible THEN MenuDefs.HideMenu[overlapMenu] ELSE MenuDefs.ShowMenu[overlapMenu]; RefreshDefs.RestoreScreen[]; }; StartObjectMenus: PUBLIC PROC = { objectMenu _ MenuDefs.CreateMenu[horizontal, [100,600], NIL]; []_MenuDefs.AddMenuItem[objectMenu,"Delete",Delete]; []_MenuDefs.AddMenuItem[objectMenu,"Undo",Undo]; []_MenuDefs.AddMenuItem[objectMenu,"Select all",SelectAll]; []_MenuDefs.AddMenuItem[objectMenu,"Deselect all",DeselectAll]; []_MenuDefs.AddMenuItem[objectMenu,"Cluster",Cluster]; []_MenuDefs.AddMenuItem[objectMenu,"Uncluster",UnCluster]; []_MenuDefs.AddMenuItem[objectMenu,"Transfer",Transfer]; xformMenu _ MenuDefs.CreateMenu[vertical, [400,400], NIL]; []_MenuDefs.AddMenuItem[xformMenu,"Map",XForm]; []_MenuDefs.AddMenuItem[xformMenu,"Scale",XForm]; []_MenuDefs.AddMenuItem[xformMenu,"ScaleX",XForm]; []_MenuDefs.AddMenuItem[xformMenu,"ScaleY",XForm]; []_MenuDefs.AddMenuItem[xformMenu,"Rotate",XForm]; copy _ MenuDefs.AddMenuItem[xformMenu,"Use Copy",Toggle]; overlapMenu _ MenuDefs.CreateMenu[vertical, [200,250], NIL]; []_MenuDefs.AddMenuItem[overlapMenu,"Top",ChangeOverlap]; []_MenuDefs.AddMenuItem[overlapMenu,"Bottom",ChangeOverlap]; []_MenuDefs.AddMenuItem[overlapMenu,"Up One",ChangeOverlap]; []_MenuDefs.AddMenuItem[overlapMenu,"Down One",ChangeOverlap]; }; END. ºCompiler ObjectOps/n;bind griffin;griffin mstone November 10, 1980 5:29 PM Last Edited by: Stone, July 6, 1985 4:20:34 pm PDT make a list of all items affected. Work in different order for different cases selects new clusters formed after XForm with copy will use the selection will mirror. Imagine a pinned point and a new point scale max dimension into 2 pt span assume 3 points 0,1 NOP, 2 is a move, which is done above make a translated copy of indicated object or set, given xy,xy clusters are selected below. click doesn't got thru move/refresh stuff click doesn't got thru move/refresh stuff get the token, may return NIL if already selected if clustered, will select whole cluster Ê&˜J˜Jšœ)™)Jšœ!™!Jšœ2™2J˜šÏk ˜ Jšœ œ˜ Jšœœœ ˜Jšœ œ ˜Jšœ œ˜Jšœ œ ˜Jšœ œ ˜Jšœ œ ˜Jšœœ ˜Jšœ œ ˜Jšœœ˜,Jšœ œ˜ J˜Jšœœ˜"—J˜šœ ˜Jšœu˜|Jšœ.˜5—Jšœœ(˜2J˜)J˜Jšœœ˜ Jšœœœ˜J˜7J˜;J˜JšÏn œ ˜Jš˜Jšœ œœœ˜*Jšœ œœœ˜*Jšœ œœœ˜+Jšœ œœœ˜+Jšœ˜J˜Jšž œ œœœ˜)Jš˜Jšœ œœ˜šž œ ˜Jšœœ˜Jšœ˜—J˜Jšœ˜Jšœ˜J˜J˜Jšœœ˜"Jš˜šž œ ˜J˜J˜Jšœœ˜Jšœ˜—šœœœ˜J˜J˜J˜Jšœ˜—Jšœ˜J˜Jšœœ˜ Jš˜šœ˜Jšœœœ˜Jšœœ˜šœœ ˜7Jšœ˜—J˜Jšœ˜—J˜J˜Jšœ˜J˜Jšœ œ˜$Jš˜Jšœœœ œ˜?Jšœœ˜šž œ ˜J˜šœ$˜)šœ˜ J˜ J˜Jšœ˜——J˜Jšœ˜—Jšœœ4˜JJ˜J˜Jšœ˜J˜Jšœœœ œ˜?J˜Jšœœ˜)Jš˜Jšœœ˜)Jšœœ œ˜#Jšœ œ œ˜J˜šž œ ˜Jšœœœ ˜&Jšœœ˜+Jšœ œœ˜1Jšœœ&œ˜4Jšœ˜—šžœ œ˜Jšœœ˜šœœœ˜4J˜Jšœ˜—Jšœ˜—šžœ œ˜Jšœœ ˜šœœœ˜5J˜Jšœ˜—Jšœ˜—šžœ œ˜Jšœœ˜šœœœ˜4J˜Jšœ˜—Jšœ˜—šžœ œ˜Jšœœ ˜šœœœ˜5J˜Jšœ˜—Jšœ˜—JšœO™OJšœœ4˜JJ˜Jš œ œœœÏc ˜*šœ œœ˜Jšœœ ˜&Jšœœ ˜,Jšœœ ˜)Jšœœ ˜-Jšœœ˜—šœ˜J˜ J˜J˜ J˜Jšœ˜ —J˜J˜J˜J˜šœœ˜J˜ Jšœ œ˜ J˜ Jšœ˜—Jšœ˜J˜Jšœœ˜!š˜šœ ˜+šœ(œ˜5Jšœ:˜@—Jšœœ2˜=Jšœ˜——˜Jšœœ˜)J˜)Jšœ(œ˜CJ˜'šžœ ˜J˜2Jšœ˜—šœœœ˜#Jšœ˜J˜J˜Jš œœœœœœ˜4J˜šœ˜Jš˜šœ/˜1šœ˜ J˜ J˜1Jš˜——Jšœ1˜5Jšœ1˜1J˜Jš˜šœ˜ J˜Jšœ1˜1J˜Jšœ˜——Jšœ˜—šžœ œœ˜=Jšœ˜Jšœ1™1J˜J˜Jšœ˜—J˜šž œ ˜J˜#Jšœ˜—J˜š œœœœ˜'J˜CJšœ˜Jšœ˜—Jšœœ4˜JJ˜J˜šœ œœ˜Jšœœ ˜&Jšœœ ˜*Jšœœ ˜,Jšœœ ˜,Jšœœ ˜,Jšœœ˜—šœ˜J˜J˜J˜J˜J˜Jšœ˜ —J˜J˜!J˜Jšœ™šœ˜!Jšœ˜ J˜0J˜9J˜˜LJšœ"™"šœœ˜JšœŸ˜,Jšœ ˜ J˜Jšœœ˜Jšœœ˜J˜JšœŸ˜!Jšœœ˜Jšœœ˜Jš˜—Jšœ™šœ˜ J˜J˜J˜J˜Jšœ˜—J˜šœ ˜šœ˜ Jšœœœ;˜QJ˜ J˜ J˜Jšœ˜—šœ ˜Jšœœ;˜HJ˜ J˜Jšœ˜—šœ ˜Jšœœ;˜HJ˜ J˜Jšœ˜—Jšœ˜—J˜Jšœ˜J˜Jšžœ œ$˜2Jšœœ ˜J˜)Jš œœœœœœ ˜4J˜J˜J˜*Jšœœ8˜FJšœ˜šœ)™)šœ˜ Jšœ œ˜%J˜J˜J˜J˜J˜ Jšœ˜—J˜šœ˜ Jšœ œ˜%J˜J˜J˜J˜J˜J˜J˜ Jšœ˜—Jšœ ˜—J˜šœ˜J˜J˜Jšœ˜—J˜Jšœ˜J˜Jšœ œ˜#Jš˜J˜#Jšœœœ˜Jšœœ˜šœ˜J˜Jšœ œ˜šœ ˜Jšœ˜!—Jšœ˜J˜ Jšœ˜—Jšœœ4˜JJ˜šœœ˜J˜0J˜Jšœ˜—Jšœ˜J˜Jšœ œ˜%Jš˜Jšœœœ˜J˜šœ˜J˜Jšœ œœœ˜/J˜Jšœ œ˜šœ%œœ˜0Jš˜J˜!Jšœ˜Jšœ˜—Jšœœ˜J˜J˜Jšœ˜—Jšœœ4˜JJ˜Jšœœ/˜=Jšœ˜J˜Jšœ œ˜'Jš˜šœ˜Jšœ1˜1J˜Jšœ˜—Jšœœ˜ J˜Jšœ˜J˜Jšœ œ˜%Jšœœ ˜šœ˜šœœ˜)Jšœ˜Jšœ˜ —Jšœœœ ˜1Jšœ˜—J˜!J˜Jšœ˜J˜Jšœ>™>Jšž œœ œ˜0Jšœœ ˜J˜*Jšœ œ˜J˜šœ˜šœ œ˜Jšœ1˜1Jšœœ˜#Jšœ˜—J˜J˜J˜J˜šœ œœ˜3Jšœ™—Jšœ˜—Jšœœœœ˜J˜šœœœ˜IJšœœ˜ —Jšœ)™)Jš œœœœœœ˜=šœ˜JšœŸ˜+šœ˜ J˜J˜ šœ œ˜J˜J˜Jšœ˜—Jšœ˜——J˜Jšœ˜J˜Jšž œœ œ˜0Jš˜J˜Dšœ˜J˜J˜#J˜Jšœ˜—Jšœœœœ˜Jšœ)™)Jš œœœœœœ˜=JšœœœŸ˜9Jšœœœ&˜UJ˜Jšœ˜J˜Jšžœœ œ ˜0Jš˜J˜(Jš œœœœœ˜BJšœ˜J˜Jšžœœ œ˜6Jšœœ ˜šœ ˜!Jšœœœœ˜Jšœœ˜˜šœ œœ˜J˜J˜—Jšœ˜—Jšœ˜Jšœ˜—šœœ ˜*J˜&—J˜Jšœ˜J˜Jšžœœ œ˜3Jš˜šœ˜Jš œœœœœœ˜Gšœœœ˜$Jšœœ˜&—Jšœ˜—šœ˜Jšœ1˜1J˜Jšœ˜—šœœ-˜3Jšœ'˜+—J˜Jšœ˜J˜Jšž œœ œ˜1Jšœœ˜"šœ˜š œœœœœ˜TJšœœ˜ —J˜ Jšœ˜—šœ˜šœœœ˜/Jšœ˜ Jšœ1™1Jšœ'™'—Jšœœœ˜ Jšœ˜—šœœ+˜1Jšœ%˜)—J˜Jšœ˜J˜Jšžœ œ#˜BJšœ˜J˜J˜Jšœœœœ˜J˜ Jšœœ œœ˜7Jšœ˜J˜Jšœ8œ˜J˜J˜—Jšœ˜J˜J˜—…—>.U