DIRECTORY IO, Pipal, PipalInt, PipalOps, PipalReal, ProcessProps, RefTab, TerminalIO; PipalOpsImpl: CEDAR MONITOR IMPORTS IO, Pipal, PipalInt, PipalReal, ProcessProps, RefTab, TerminalIO EXPORTS PipalOps = BEGIN OPEN PipalOps; enumerateMethod: PUBLIC Pipal.Method _ Pipal.RegisterMethod["SimpleEnumerate"]; HasEnumerate: PUBLIC PROC [object: Pipal.Object] RETURNS [BOOL] = { RETURN [Pipal.ObjectMethod[object, enumerateMethod]#NIL OR PipalReal.HasEnumerate[object]]; }; Enumerate: PUBLIC EnumerateProc = { data: REF _ Pipal.ObjectMethod[object, enumerateMethod]; quit _ (IF data=NIL THEN IF PipalInt.HasEnumerate[object] THEN UseIntEnumerate ELSE UseRealEnumerate ELSE NARROW [data, REF EnumerateProc]^)[object, each]; }; UseIntEnumerate: EnumerateProc = { EachChild: PipalInt.EachChildProc = { quit _ each[child]; }; quit _ PipalInt.Enumerate[object, EachChild]; }; UseRealEnumerate: EnumerateProc = { EachChild: PipalReal.EachChildProc = { quit _ each[child]; }; transformation: PipalReal.Transformation _ PipalReal.CreateTransformation[]; quit _ PipalReal.Enumerate[object, EachChild, transformation]; PipalReal.DestroyTransformation[transformation]; }; CountChildren: PUBLIC PROC [object: Pipal.Object] RETURNS [count: NAT _ 0] = { EachChild: EachChildProc = {count _ count + 1}; [] _ Enumerate[object, EachChild]; }; NthChild: PUBLIC PROC [object: Pipal.Object, rank: NAT _ 0] RETURNS [nthChild: Pipal.Object _ NIL] = { EachChild: EachChildProc = { IF rank=0 THEN {nthChild _ child; quit _ TRUE} ELSE rank _ rank - 1; }; [] _ Enumerate[object, EachChild]; }; Recast: PUBLIC PROC [object: Pipal.Object] RETURNS [Pipal.Object] = { children: Pipal.Objects _ NIL; IF PipalInt.HasEnumerate[object] THEN { EachChild: PipalInt.EachChildProc = { children _ CONS [PipalInt.TransformObject[transformation, child], children]; }; [] _ PipalInt.Enumerate[object, EachChild]; } ELSE { EachChild: PipalReal.EachChildProc = { children _ CONS [PipalReal.TransformObject[transformation, child], children]; }; transformation: PipalReal.Transformation _ PipalReal.CreateTransformation[]; [] _ PipalReal.Enumerate[object, EachChild, transformation]; PipalReal.DestroyTransformation[transformation]; }; RETURN [IF children#NIL AND children.rest=NIL THEN children.first ELSE Pipal.CreateOverlay[children]]; -- optimization for when only one child }; HashByEnumeration: PUBLIC Pipal.HashProc = { Each: EachChildProc = {hash _ hash + Pipal.Hash[child] + 1}; hash _ Pipal.HashObjectClass[object]; [] _ Enumerate[object, Each]; }; hashCache: Pipal.ObjectCache _ Pipal.CreateObjectCache[]; CachedHashByEnumeration: PUBLIC Pipal.HashProc = { refHash: REF CARD _ NARROW [RefTab.Fetch[hashCache, object].val]; IF refHash#NIL THEN RETURN [refHash^]; hash _ HashByEnumeration[object]; [] _ RefTab.Store[hashCache, object, NEW [CARD _ hash]]; }; EqualByEnumeration: PUBLIC Pipal.EqualProc = { size: NAT _ CountChildren[object1]; IF CountChildren[object2]#size THEN RETURN [FALSE]; FOR i: NAT IN [0 .. size) DO IF NOT Pipal.Equal[NthChild[object1], NthChild[object2]] THEN RETURN [FALSE]; ENDLOOP; RETURN [TRUE]; }; EnumerateOverlay: EnumerateProc ~ { overlay: Pipal.Overlay _ NARROW [object]; FOR i: NAT IN [0 .. overlay.size) DO IF each[overlay[i]] THEN RETURN [TRUE]; ENDLOOP; }; EnumerateAnnotation: EnumerateProc ~ { annotation: Pipal.Annotation _ NARROW [object]; quit _ each[annotation.child]; }; EnumerateTransform: EnumerateProc = { transform: PipalInt.Transform _ NARROW [object]; quit _ each[transform.child]; }; EnumerateTranslation: EnumerateProc = { translation: PipalInt.Translation _ NARROW [object]; quit _ each[translation.child]; }; reachabilityCache: Pipal.ObjectCache _ Pipal.CreateObjectCache[]; Reachable: PUBLIC PROC [root, candidate: Pipal.Object] RETURNS [reached: BOOL] = { SELECT TRUE FROM root=candidate => RETURN [TRUE]; NOT HasEnumerate[root] => RETURN [FALSE]; ENDCASE => { count: NAT _ 0; IsChildAncestor: EachChildProc = {quit _ Reachable[child, candidate]}; FastCount: EachChildProc = {count _ count+1; IF count>1 THEN quit _ TRUE}; SELECT TRUE FROM Enumerate[root, FastCount] => { rootCache: RefTab.Ref _ NARROW [RefTab.Fetch[reachabilityCache, candidate].val]; IF rootCache=NIL THEN { rootCache _ RefTab.Create[mod: 3]; [] _ RefTab.Store[reachabilityCache, candidate, rootCache]; }; IF RefTab.Fetch[rootCache, root].found THEN RETURN [RefTab.Fetch[rootCache, root].val=$True]; reached _ Enumerate[root, IsChildAncestor]; [] _ RefTab.Store[rootCache, root, IF reached THEN $True ELSE $False]; }; count=1 => RETURN [Enumerate[root, IsChildAncestor]]; count=0 => RETURN [FALSE]; ENDCASE => ERROR; }; }; AnyReachable: PUBLIC PROC [root: Pipal.Object, table: RefTab.Ref] RETURNS [BOOL] = { EachOldNew: RefTab.EachPairAction = {quit _ Reachable[root, key]}; RETURN [RefTab.Pairs[table, EachOldNew]]; }; replaceMethod: PUBLIC Pipal.Method _ Pipal.RegisterMethod["Replace"]; Replace: PUBLIC ReplaceProc = { newParent _ (NARROW [Pipal.ObjectMethod[parent, replaceMethod], REF ReplaceProc]^)[parent, map]; }; ReplaceWithTable: PUBLIC PROC [oldRoot: Pipal.Object, table: ReplaceTable] = { Map: MapProc = { new _ RefTab.Fetch[table, old].val; IF new=NIL THEN new _ old; }; newRoot: Pipal.Object _ Replace[oldRoot, Map]; IF newRoot#oldRoot THEN [] _ RefTab.Store[table, oldRoot, newRoot]; }; ReplaceFromRecast: PUBLIC ReplaceProc = { newParent _ Replace[Recast[parent], map]; }; PrimitiveTable: PROC [table: ReplaceTable] RETURNS [primitive: ReplaceTable] = { FillPrimitive: RefTab.EachPairAction = { candidate: Pipal.Object _ key; IsAncesterOfSome: RefTab.EachPairAction = { quit _ candidate#key AND Reachable[candidate, key]; }; IF NOT RefTab.Pairs[table, IsAncesterOfSome] THEN [] _ RefTab.Store[primitive, candidate, val]; }; primitive _ RefTab.Create[]; [] _ RefTab.Pairs[table, FillPrimitive]; }; simpleReplace: BOOL _ TRUE; SimpleTransitiveReplace: PUBLIC PROC [root: Pipal.Object, table: ReplaceTable] = { ReplaceChildRecursive: EachChildProc = { TransitiveReplace[child, table]; }; IF RefTab.Fetch[table, root].val#NIL THEN RETURN; IF NOT AnyReachable[root, table] THEN RETURN; [] _ Enumerate[root, ReplaceChildRecursive]; ReplaceWithTable[root, table]; }; TransitiveReplace: PUBLIC PROC [root: Pipal.Object, table: ReplaceTable] = { IF simpleReplace THEN SimpleTransitiveReplace[root, table] ELSE FancyTransitiveReplace[root, table, PrimitiveTable[table]] }; FancyTransitiveReplace: PUBLIC PROC [root: Pipal.Object, table, primitive: ReplaceTable] = { ReplaceChildRecursive: EachChildProc = { FancyTransitiveReplace[child, table, primitive]; }; IF RefTab.Fetch[table, root].val#NIL THEN RETURN; IF NOT AnyReachable[root, primitive] THEN RETURN; [] _ Enumerate[root, ReplaceChildRecursive]; ReplaceWithTable[root, table]; }; ConcatPath: PUBLIC PROC [rootPath, childPath: Path] RETURNS [newPath: Path] = { IF rootPath=NIL THEN RETURN [childPath]; newPath _ CONS [rootPath.first, ConcatPath[rootPath.rest, childPath]]; }; ExtendPath: PUBLIC PROC [currentPath: Path, type: PathBitType, rank: NAT] RETURNS [newPath: Path] = { newPath _ ConcatPath[currentPath, LIST [[type, rank]]]; }; ApplyPathBit: PUBLIC PROC [root: Pipal.Object, pathBit: PathBit] RETURNS [child: Pipal.Object] = { SELECT pathBit.type FROM ops => child _ NthChild[root, pathBit.rank]; real => child _ PipalReal.NthChild[root, PipalReal.CreateTransformation[], pathBit.rank].nthChild; int => child _ PipalInt.NthChild[root, [], pathBit.rank].nthChild; ENDCASE => ERROR; }; ApplyPath: PUBLIC PROC [root: Pipal.Object, path: Path] RETURNS [child: Pipal.Object] = { child _ root; WHILE path#NIL DO child _ ApplyPathBit[child, path.first]; path _ path.rest; ENDLOOP; }; ApplyRealPath: PUBLIC PROC [root: Pipal.Object, path: Path, transformation: PipalReal.Transformation] RETURNS [trans: PipalReal.Transformation, child: Pipal.Object] = { trans _ transformation; child _ root; WHILE path#NIL DO IF path.first.type#real THEN ERROR; [trans, child] _ PipalReal.NthChild[child, trans, path.first.rank]; path _ path.rest; ENDLOOP; }; ApplyIntPath: PUBLIC PROC [root: Pipal.Object, path: Path, transformation: PipalInt.Transformation] RETURNS [trans: PipalInt.Transformation, child: Pipal.Object] = { trans _ transformation; child _ root; WHILE path#NIL DO IF path.first.type#real THEN ERROR; [trans, child] _ PipalInt.NthChild[child, trans, path.first.rank]; path _ path.rest; ENDLOOP; }; ReplaceInPathWithTable: PUBLIC PROC [root: Pipal.Object, path: Path, table: ReplaceTable] = { IF path=NIL THEN RETURN; ReplaceInPathWithTable[ApplyPathBit[root, path.first], path.rest, table]; ReplaceWithTable[root, table]; }; ReplaceInPath: PUBLIC PROC [root: Pipal.Object, path: Path, oldChild, newChild: Pipal.Object] RETURNS [table: ReplaceTable] = { table _ RefTab.Create[]; [] _ RefTab.Store[table, oldChild, newChild]; ReplaceInPathWithTable[root, path, table]; }; FindOpsPath: PUBLIC PROC [root, searched: Pipal.Object] RETURNS [path: Path, found: BOOL] = { count: NAT _ 0; Each: EachChildProc = { [path, found] _ FindOpsPath[child, searched]; IF found THEN { quit _ TRUE; path _ ConcatPath[ExtendPath[NIL, ops, count], path]; }; count _ count + 1; }; IF NOT Reachable[root, searched] THEN RETURN [NIL, FALSE]; IF root=searched THEN RETURN [NIL, TRUE]; found _ Enumerate[root, Each]; }; FindRealPath: PUBLIC PROC [rootTrans: PipalReal.Transformation, root: Pipal.Object, searchedTrans: PipalReal.Transformation, searched: Pipal.Object] RETURNS [path: Path, found: BOOL] = { count: NAT _ 0; Each: PipalReal.EachChildProc = { [path, found] _ FindRealPath[transformation, child, searchedTrans, searched]; IF found THEN { quit _ TRUE; path _ ConcatPath[ExtendPath[NIL, real, count], path]; }; count _ count + 1; }; IF NOT Reachable[root, searched] THEN RETURN [NIL, FALSE]; IF root=searched THEN RETURN [path, PipalReal.EqualTransformation[rootTrans, searchedTrans]]; found _ PipalReal.Enumerate[root, Each, rootTrans]; }; FindIntPath: PUBLIC PROC [rootTrans: PipalInt.Transformation, root: Pipal.Object, searchedTrans: PipalInt.Transformation, searched: Pipal.Object] RETURNS [path: Path, found: BOOL] = { count: NAT _ 0; Each: PipalInt.EachChildProc = { [path, found] _ FindIntPath[transformation, child, searchedTrans, searched]; IF found THEN { quit _ TRUE; path _ ConcatPath[ExtendPath[NIL, int, count], path]; }; count _ count + 1; }; IF NOT Reachable[root, searched] THEN RETURN [NIL, FALSE]; IF root=searched THEN RETURN [NIL, rootTrans=searchedTrans]; found _ PipalInt.Enumerate[root, Each, rootTrans]; }; DogData: TYPE = RECORD [dog: WatchDog, registrationData: REF]; eventTable: RefTab.Ref _ RefTab.Create[]; RegisterWatchDog: PUBLIC PROC [event: ATOM, dog: WatchDog, registrationData: REF _ NIL] = { dogDatas: LIST OF DogData _ NARROW [RefTab.Fetch[eventTable, event].val]; dogDatas _ CONS [[dog, registrationData], dogDatas]; [] _ RefTab.Store[eventTable, event, dogDatas]; }; ForgetWatchDog: PUBLIC PROC [event: ATOM, dog: WatchDog, registrationData: REF _ NIL, equal: PROC [REF, REF] RETURNS [BOOL] _ NIL] = { dogDatas: LIST OF DogData _ NARROW [RefTab.Fetch[eventTable, event].val]; new: LIST OF DogData _ NIL; WHILE dogDatas#NIL DO dd: DogData = dogDatas.first; same: BOOL _ dd.dog=dog AND (IF equal=NIL THEN dd.registrationData=registrationData ELSE equal[dd.registrationData, registrationData]); IF NOT same THEN new _ CONS [dogDatas.first, new]; dogDatas _ dogDatas.rest; ENDLOOP; [] _ RefTab.Store[eventTable, event, new]; }; Broadcast: PUBLIC PROC [event: ATOM, arg1, arg2, arg3: REF _ NIL] = { dogDatas: LIST OF DogData _ NARROW [RefTab.Fetch[eventTable, event].val]; WHILE dogDatas#NIL DO dd: DogData _ dogDatas.first; dd.dog[arg1, arg2, arg3, dd.registrationData]; dogDatas _ dogDatas.rest; ENDLOOP; }; replaceEvent: PUBLIC ATOM _ $Replace; ReplaceDogData: TYPE = REF ReplaceDogDataRec; ReplaceDogDataRec: TYPE = RECORD [root: Pipal.Object, dog: ReplaceWatchDog]; GenericReplaceWatchDog: WatchDog = { rdd: ReplaceDogData = NARROW [registrationData]; table: ReplaceTable = NARROW [arg1]; rdd.dog[rdd.root, table]; }; EqualReplaceDogData: PROC [ref1, ref2: REF] RETURNS [BOOL] = { rdd1: ReplaceDogData = NARROW [ref1]; rdd2: ReplaceDogData = NARROW [ref2]; RETURN [rdd1^=rdd2^]; }; RegisterReplaceWatchDog: PUBLIC PROC [root: Pipal.Object, dog: ReplaceWatchDog] = { rdd: ReplaceDogData = NEW [ReplaceDogDataRec _ [root, dog]]; RegisterWatchDog[replaceEvent, GenericReplaceWatchDog, rdd]; }; ForgetReplaceWatchDog: PUBLIC PROC [root: Pipal.Object, dog: ReplaceWatchDog] = { rdd: ReplaceDogData = NEW [ReplaceDogDataRec _ [root, dog]]; ForgetWatchDog[replaceEvent, GenericReplaceWatchDog, rdd, EqualReplaceDogData]; }; BroadcastReplace: PUBLIC PROC [table: ReplaceTable] = { Broadcast[replaceEvent, table]; }; ReplaceOverlay: ReplaceProc = { overlay: Pipal.Overlay _ NARROW [parent]; children: Pipal.Objects _ NIL; FOR i: NAT DECREASING IN [0 .. overlay.size) DO children _ CONS [map[overlay[i]], children]; ENDLOOP; newParent _ Pipal.CreateOverlay[children]; }; ReplaceIcon: ReplaceProc = { icon: Pipal.Icon _ NARROW [parent]; newParent _ Pipal.CreateIcon[map[icon.reference], map[icon.referent]]; }; ReplaceAnnotation: ReplaceProc = { annotation: Pipal.Annotation _ NARROW [parent]; newParent _ Pipal.CreateAnnotation[map[annotation.child], annotation.key, annotation.value]; }; ReplaceIntTransform: ReplaceProc = { transform: PipalInt.Transform _ NARROW [parent]; newParent _ PipalInt.TransformObject[transform.transformation, map[transform.child]]; }; ReplaceTranslation: ReplaceProc = { translation: PipalInt.Translation _ NARROW [parent]; newParent _ PipalInt.TransformObject[[translation.vector], map[translation.child]]; }; ReplaceOrient: ReplaceProc = { orient: PipalInt.Orient _ NARROW [parent]; newParent _ PipalInt.TransformObject[[PipalInt.zeroVector, orient.orientation], map[orient.child]]; }; ReplaceAbut: ReplaceProc = { abut: PipalInt.Abut _ NARROW [parent]; children: Pipal.Objects _ NIL; FOR i: NAT DECREASING IN [0 .. abut.size) DO children _ CONS [map[abut[i]], children]; ENDLOOP; newParent _ PipalInt.CreateAbut[abut.inX, children]; }; ReplaceRealTransform: ReplaceProc = { transform: PipalReal.Transform _ NARROW [parent]; newParent _ PipalReal.CreateTransform[transform.transformation, map[transform.child]]; }; Do: PUBLIC PROC [old: UndoRedo, message: Pipal.ROPE, oldState: REF] RETURNS [new: UndoRedo] = { event: Event = [message: message, state: oldState]; completeMessage: Pipal.ROPE _ IO.PutFR["Doing %g.\n", IO.rope[message]]; new _ old; IF old.redo#NIL THEN { event: Event = [message: old.redo.first.message, state: oldState]; new.undo _ CONS [event, new.undo]; FOR events: Events _ old.redo, events.rest UNTIL events=NIL DO events.first.message _ IF events.rest=NIL THEN completeMessage ELSE events.rest.first.message; new.undo _ CONS [events.first, new.undo]; ENDLOOP; new.redo _ NIL; }; TerminalIO.PutRope[completeMessage]; new.undo _ CONS [event, new.undo]; }; Undo: PUBLIC UndoRedoOp = { IF old.undo=NIL THEN ERROR Pipal.Error[$cantUndo] ELSE { event: Event _ old.undo.first; TerminalIO.PutF["Undoing %g.\n", IO.rope[event.message]]; new.undo _ old.undo.rest; newState _ event.state; event.state _ oldState; new.redo _ CONS [event, old.redo]; }; }; Redo: PUBLIC UndoRedoOp = { IF old.redo=NIL THEN ERROR Pipal.Error[$cantRedo] ELSE { event: Event _ old.redo.first; TerminalIO.PutF["Redoing %g.\n", IO.rope[event.message]]; new.redo _ old.redo.rest; newState _ event.state; event.state _ oldState; new.undo _ CONS [event, old.undo]; }; }; Reset: PUBLIC UndoRedoOp = { new _ old; newState _ oldState; WHILE new.undo#NIL DO [new, newState] _ Undo[new, newState] ENDLOOP; }; wDir: PUBLIC Pipal.ROPE _ NARROW [ProcessProps.GetProp[$WorkingDirectory]]; EnumerateIcon: EnumerateProc ~ { icon: Pipal.Icon _ NARROW [object]; quit _ each[icon.reference] OR each[icon.referent]; }; Pipal.PutClassMethod[Pipal.overlayClass, replaceMethod, NEW [ReplaceProc _ ReplaceOverlay]]; Pipal.PutClassMethod[Pipal.iconClass, replaceMethod, NEW [ReplaceProc _ ReplaceIcon]]; Pipal.PutClassMethod[Pipal.annotationClass, replaceMethod, NEW [ReplaceProc _ ReplaceAnnotation]]; Pipal.PutClassMethod[PipalInt.transformClass, replaceMethod, NEW [ReplaceProc _ ReplaceIntTransform]]; Pipal.PutClassMethod[PipalInt.translationClass, replaceMethod, NEW [ReplaceProc _ ReplaceTranslation]]; Pipal.PutClassMethod[PipalInt.orientClass, replaceMethod, NEW [ReplaceProc _ ReplaceOrient]]; Pipal.PutClassMethod[PipalInt.abutClass, replaceMethod, NEW [ReplaceProc _ ReplaceAbut]]; Pipal.PutClassMethod[PipalReal.transformClass, replaceMethod, NEW [ReplaceProc _ ReplaceRealTransform]]; Pipal.PutClassMethod[Pipal.iconClass, enumerateMethod, NEW [EnumerateProc _ EnumerateIcon]]; Pipal.PutClassMethod[Pipal.overlayClass, enumerateMethod, NEW [EnumerateProc _ EnumerateOverlay]]; Pipal.PutClassMethod[Pipal.annotationClass, enumerateMethod, NEW [EnumerateProc _ EnumerateAnnotation]]; Pipal.PutClassMethod[PipalInt.transformClass, enumerateMethod, NEW [EnumerateProc _ EnumerateTransform]]; Pipal.PutClassMethod[PipalInt.translationClass, enumerateMethod, NEW [EnumerateProc _ EnumerateTranslation]]; END. €PipalOpsImpl.mesa Copyright Σ 1988 by Xerox Corporation. All rights reserved. Bertrand Serlet May 26, 1988 1:47:01 pm PDT Louis Monier January 20, 1988 2:51:13 am PST Barth, January 29, 1988 6:23:15 pm PST Enumeration Enumeration Speed Up (Speed Up Only!) Transitive Closure Maps candidates to RefTabs mapping roots to $True or $False, but only when roots have 2 or more children. many children Replacement Path Events and Notification maps Events to LIST OF DogData Replacement Events Replacement for Primitive Classes unnecessary! unnecessary! unnecessary! unnecessary! Undo / Redo facilities Hacks Initialization speed ups! Κ/˜– "Cedar" stylešœ™Jšœ<™˜>Kšœ0˜0K˜K˜—š ž œœœœ œ ˜NJšž œ&˜/Jšœ"˜"K˜K˜—š žœœœœœœ˜fšž œ˜Jšœœœœ˜EJšœ˜—Jšœ"˜"K˜K˜—šžœœœœ˜EKšœœ˜šœœ˜'šž œ˜%Kšœ œ=˜LKšœ˜—Kšœ+˜+Kšœœ˜šž œ˜&Kšœ œ>˜MKšœ˜—KšœL˜LKšœ<˜K˜—šœ)˜)Jšœœœ™K˜—š žœœœ œ#œœ˜[Kšœ œœ œ'˜IKšœ œ%˜4Kšœ/˜/K˜—K™šžœœœ œ#œœ œœœœœœ˜†Kšœ œœ œ'˜IJšœœœ œ˜šœ œ˜Jšœ˜Jš œœœœœœ&œ/˜‡Jšœœœœ˜2Jšœ˜Jšœ˜—Kšœ*˜*K˜K˜—š ž œœœ œœœ˜EKšœ œœ œ'˜Išœ œ˜Jšœ˜Jšœ.˜.Jšœ˜Jšœ˜—K˜——™šœœœ ˜%K˜—Kšœœœ˜-šœœœ,˜LK˜—šžœ˜$Kšœœ˜0Kšœœ˜$Kšœ˜K˜K˜—š žœœœœœ˜>Kšœœ˜%Kšœœ˜%Kšœ˜K˜K˜—šžœœœ/˜SKšœœ#˜Kš œœ œœœ˜^Jšœ œ˜)Kšœ˜—Kšœ œ˜K˜—Kšœ$˜$Kšœ œ˜"K˜J˜—šžœœ˜Jšœ œœœ˜1šœ˜Jšœ˜Jšœ!œ˜9Jšœ˜Jšœ˜Jšœ˜Jšœ œ˜"J˜—J˜J˜—šžœœ˜Kšœ œœœ˜1šœ˜Jšœ˜Jšœ!œ˜9Jšœ˜Jšœ˜Jšœ˜Jšœ œ˜"K˜—J˜J˜—šžœœ˜J˜ Jšœ˜Jšœ œœ'œ˜DJ˜——™Jšœœœœ+˜K—™šž œ˜ Kšœœ ˜#Kšœœ˜3Kšœ˜K˜—Kšœ8œ!˜\Kšœ5œ˜VKšœ;œ$˜bKšœ=œ&˜fKšœ?œ%˜gKšœ:œ ˜]Kšœ8œ˜Yšœ>œ'˜hK˜—šœ7œ"˜\K˜—Kšœ ™ Kšœ:œ%˜bKšœ=œ(˜hKšœ?œ'˜išœAœ)˜mK˜——Jšœ˜—…—CX―