DIRECTORY BasicTime, BrineIO, CedarProcess, FileStream, FS, ImagerTransformation, IO, Pipal, PipalInt, PipalIO, PipalOps, PipalReal, Process, RefTab, RefTabExtras, Rope, SymTab; PipalIOImpl: CEDAR PROGRAM IMPORTS BasicTime, BrineIO, CedarProcess, FileStream, FS, ImagerTransformation, IO, Pipal, PipalInt, PipalOps, Process, RefTab, RefTabExtras, Rope, SymTab EXPORTS PipalIO = BEGIN OPEN BrineIO, PipalIO; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Object: TYPE = Pipal.Object; classRegistry: SymTab.Ref _ SymTab.Create[]; ClassData: TYPE = REF ClassDataRec; ClassDataRec: TYPE = RECORD [read: ClassReadProc, write: ClassWriteProc]; RegisterClass: PUBLIC PROC [class: Pipal.Class, read: ClassReadProc, write: ClassWriteProc] = { data: ClassData _ NEW [ClassDataRec _ [read, write]]; IF write=NIL OR read=NIL THEN ERROR; -- if only one NIL then invariant for object write/read is broken [] _ SymTab.Store[classRegistry, Pipal.ClassName[class], data]; }; ReadIntVector: PUBLIC PROC [stream: STREAM] RETURNS [vector: PipalInt.Vector] = { vector.x _ ReadInt[stream]; vector.y _ ReadInt[stream]; }; WriteIntVector: PUBLIC PROC [stream: STREAM, vector: PipalInt.Vector] = { WriteInt[stream, vector.x]; WriteInt[stream, vector.y]; }; ReadIntRectangle: PUBLIC PROC [stream: STREAM] RETURNS [rectangle: PipalInt.Rectangle] = { rectangle.base _ ReadIntVector[stream]; rectangle.size _ ReadIntVector[stream]; }; WriteIntRectangle: PUBLIC PROC [stream: STREAM, rectangle: PipalInt.Rectangle] = { WriteIntVector[stream, rectangle.base]; WriteIntVector[stream, rectangle.size]; }; ReadOrientation: PUBLIC PROC [stream: STREAM] RETURNS [orientation: PipalInt.Orientation] = { aux: [ORD[FIRST[PipalInt.Orientation]] .. ORD[LAST[PipalInt.Orientation]]] _ NAT [ReadInt[stream]]; orientation _ LOOPHOLE [aux]; }; WriteOrientation: PUBLIC PROC [stream: STREAM, orientation: PipalInt.Orientation] = { WriteInt[stream, ORD [orientation]]; }; ReadIntTransformation: PUBLIC PROC [stream: STREAM] RETURNS [transformation: PipalInt.Transformation] = { transformation.translation _ ReadIntVector[stream]; transformation.orientation _ ReadOrientation[stream]; }; WriteIntTransformation: PUBLIC PROC [stream: STREAM, transformation: PipalInt.Transformation] = { WriteIntVector[stream, transformation.translation]; WriteOrientation[stream, transformation.orientation]; }; ReadRealVector: PUBLIC PROC [stream: STREAM] RETURNS [vector: PipalReal.Vector] = { vector.x _ ReadReal[stream]; vector.y _ ReadReal[stream]; }; WriteRealVector: PUBLIC PROC [stream: STREAM, vector: PipalReal.Vector] = { WriteReal[stream, vector.x]; WriteReal[stream, vector.y]; }; ReadRealRectangle: PUBLIC PROC [stream: STREAM] RETURNS [rectangle: PipalReal.Rectangle] = { rectangle.base _ ReadRealVector[stream]; rectangle.size _ ReadRealVector[stream]; }; WriteRealRectangle: PUBLIC PROC [stream: STREAM, rectangle: PipalReal.Rectangle] = { WriteRealVector[stream, rectangle.base]; WriteRealVector[stream, rectangle.size]; }; ReadRealTransformation: PUBLIC PROC [stream: STREAM] RETURNS [transformation: PipalReal.Transformation] = { a: REAL _ ReadReal[stream]; b: REAL _ ReadReal[stream]; c: REAL _ ReadReal[stream]; d: REAL _ ReadReal[stream]; e: REAL _ ReadReal[stream]; f: REAL _ ReadReal[stream]; transformation _ ImagerTransformation.Create[a, b, c, d, e, f]; }; WriteRealTransformation: PUBLIC PROC [stream: STREAM, transformation: PipalReal.Transformation] = { WriteReal[stream, transformation.a]; WriteReal[stream, transformation.b]; WriteReal[stream, transformation.c]; WriteReal[stream, transformation.d]; WriteReal[stream, transformation.e]; WriteReal[stream, transformation.f]; }; ReadObject: PUBLIC PROC [stream: STREAM] RETURNS [object: Object] = { objects: RefTab.Ref _ GetRefTab[stream, $PipalIOObjectsTable, RefTabExtras.EqualRope, RefTabExtras.HashRope]; objectID: ROPE _ ReadID[stream]; IF Rope.Fetch[objectID]#'O THEN ERROR; object _ NARROW [RefTab.Fetch[objects, objectID].val]; IF object=NIL THEN { className: Pipal.ROPE _ ReadRope[stream]; classData: ClassData _ NARROW [SymTab.Fetch[classRegistry, className].val]; bbox: PipalInt.Rectangle _ ReadIntRectangle[stream]; abutBox: PipalInt.Rectangle _ ReadIntRectangle[stream]; CedarProcess.CheckAbort[]; Process.Yield[]; object _ classData.read[stream]; IF PipalInt.BBox[object, []]#bbox THEN ERROR; IF PipalInt.AbutBox[object]#abutBox THEN ERROR; IF NOT RefTab.Insert[objects, objectID, object] THEN ERROR; }; }; WriteObject: PUBLIC PROC [stream: STREAM, object: Object] = { objects: RefTab.Ref _ GetRefTab[stream, $PipalIOObjectsTable]; objectID: ROPE _ NARROW [RefTab.Fetch[objects, object].val]; IF objectID=NIL THEN { className: Pipal.ROPE = Pipal.ClassName[Pipal.ObjectClass[object]]; classData: ClassData _ NARROW [SymTab.Fetch[classRegistry, className].val]; CedarProcess.CheckAbort[]; Process.Yield[]; objectID _ MakeID["O", RefTab.GetSize[objects]]; IF NOT RefTab.Insert[objects, object, objectID] THEN ERROR; WriteID[stream, objectID]; WriteRope[stream, className]; WriteIntRectangle[stream, PipalInt.BBox[object, []]]; WriteIntRectangle[stream, PipalInt.AbutBox[object]]; classData.write[stream, object]; } ELSE WriteID[stream, objectID]; }; FileInfo: PUBLIC PROC [fileName: Pipal.ROPE, wantedCreatedTime: BasicTime.GMT _ BasicTime.nullGMT] RETURNS [creationTime: BasicTime.GMT _ BasicTime.nullGMT] = { creationTime _ FS.FileInfo[name: Rope.Cat[fileName, ".pipal"], wantedCreatedTime: wantedCreatedTime ! ANY => GOTO Fails].created; EXITS Fails => RETURN [BasicTime.nullGMT]; }; OpenFileStream: PROC [fileName: ROPE] RETURNS [stream: STREAM, creationTime: BasicTime.GMT] = { fileHandle: FS.OpenFile _ FS.Create[name: Rope.Cat[fileName, ".pipal"]]; creationTime _ FS.GetInfo[fileHandle].created; stream _ FileStream.StreamFromOpenFile[openFile: fileHandle, accessRights: $write]; }; RestoreObject: PUBLIC PROC [fileName: ROPE, wantedCreatedTime: BasicTime.GMT _ BasicTime.nullGMT] RETURNS [object: Object] = { stream: STREAM _ FS.StreamOpen[fileName: Rope.Cat[fileName, ".pipal"], wantedCreatedTime: wantedCreatedTime]; object _ ReadObject[stream]; IO.Close[stream]; }; SaveObject: PUBLIC PROC [fileName: ROPE, object: Object] RETURNS [creationTime: BasicTime.GMT] = { stream: STREAM; [stream, creationTime] _ OpenFileStream[fileName]; WriteObject[stream, object]; IO.Close[stream]; }; directoryClass: PUBLIC Pipal.Class _ Pipal.RegisterClass[name: "Directory", type: CODE [DirectoryRec]]; DescribeDirectory: Pipal.DescribeProc = { directory: Directory _ NARROW [object]; Pipal.PutIndent[out, indent, cr]; IO.PutF[out, "Directory %g: %g nodes", IO.rope[directory.name], IO.int[SymTab.GetSize[directory.table]]]; }; EnumerateIntDirectory: PipalInt.EnumerateProc = { directory: Directory _ NARROW [object]; quit _ each[transformation, directory.child]; }; EnumerateDirectory: PipalOps.EnumerateProc = { EachPair: SymTab.EachPairAction = {quit _ each[val]}; directory: Directory _ NARROW [object]; quit _ each[directory.child] OR SymTab.Pairs[directory.table, EachPair]; }; CreateDirectory: PUBLIC PROC [name: Pipal.ROPE, child: Pipal.Object, table: SymTab.Ref] RETURNS [directory: Directory] = { directory _ NEW [DirectoryRec _ [name: name, child: child, table: table]]; }; ReplaceDirectory: PipalOps.ReplaceProc = { EachPair: SymTab.EachPairAction = {[] _ SymTab.Store[table, key, map[val]]}; directory: Directory _ NARROW [parent]; table: SymTab.Ref _ SymTab.Create[(SymTab.GetSize[directory.table]/2)*2+1]; [] _ SymTab.Pairs[directory.table, EachPair]; newParent _ CreateDirectory[directory.name, map[directory.child], table]; }; WriteDirectory: ClassWriteProc = { EachPair: SymTab.EachPairAction = { WriteRope[stream, key]; WriteObject[stream, val]; }; directory: Directory _ NARROW [object]; WriteRope[stream, directory.name]; WriteObject[stream, directory.child]; WriteInt[stream, SymTab.GetSize[directory.table]]; [] _ SymTab.Pairs[directory.table, EachPair]; }; ReadDirectory: ClassReadProc = { name: Pipal.ROPE _ ReadRope[stream]; child: Pipal.Object _ ReadObject[stream]; size: INT _ ReadInt[stream]; table: SymTab.Ref _ SymTab.Create[(size/2)*2+1]; THROUGH [0 .. size) DO name: Pipal.ROPE _ ReadRope[stream]; object: Pipal.Object _ ReadObject[stream]; [] _ SymTab.Store[table, name, object]; ENDLOOP; IF SymTab.GetSize[table]#size THEN ERROR; object _ CreateDirectory[name, child, table]; }; FetchInDirectory: PUBLIC PROC [directory: Directory, name: Pipal.ROPE] RETURNS [object: Pipal.Object _ NIL] = { object _ SymTab.Fetch[directory.table, name].val; }; DirectoryAndShortName: PUBLIC PROC [name: Pipal.ROPE] RETURNS [directory, shortName: Pipal.ROPE _ NIL] = { index: INT _ Rope.Find[name, "."]; IF index<0 OR index=Rope.Length[name]-1 THEN RETURN; directory _ Rope.Substr[name, 0, index]; shortName _ Rope.Substr[name, index+1]; }; importClass: PUBLIC Pipal.Class _ Pipal.RegisterClass[name: "Import", type: CODE [ImportRec]]; FileName: PROC [name: Pipal.ROPE, isDirectory: BOOL] RETURNS [fileName: Pipal.ROPE] = { fileName _ IF isDirectory THEN Rope.Cat[DirectoryAndShortName[name].directory, ".directory"] ELSE name; }; DescribeImport: Pipal.DescribeProc = { import: Import _ NARROW [object]; Pipal.PutIndent[out, indent, cr]; IO.PutF[ out, "Import of %g (%g%g %g)", IO.rope[import.name], IO.rope[IF import.isDirectory THEN "dir " ELSE NIL], IO.int[IF import.creationTime=BasicTime.nullGMT THEN 0 ELSE BasicTime.ToNSTime[import.creationTime]], IO.rope[IF import.referee=NIL THEN NIL ELSE "bound"] ]; }; EnumerateIntImport: PipalInt.EnumerateProc = { import: Import _ NARROW [object]; IF import.referee=NIL THEN BindImport[import]; quit _ each[ transformation, IF import.isDirectory THEN FetchInDirectory[NARROW [import.referee], DirectoryAndShortName[import.name].shortName] ELSE import.referee ]; }; EnumerateOpsImport: PipalOps.EnumerateProc = { import: Import _ NARROW [object]; IF import.referee=NIL THEN BindImport[import]; quit _ each[import.referee]; }; BindImport: PROC [import: Import] = { object: Pipal.Object _ RestoreObject[FileName[import.name, import.isDirectory], import.creationTime]; import.referee _ object; IF import.isDirectory AND NOT ISTYPE [object, Directory] THEN ERROR; }; CreateTimedImport: PUBLIC PROC [name: Pipal.ROPE, isDirectory: BOOL _ FALSE, creationTime: BasicTime.GMT] RETURNS [import: Import] = { import _ NEW [ImportRec _ [name: name, isDirectory: isDirectory, creationTime: creationTime]]; }; CreateRefereedImport: PUBLIC PROC [name: Pipal.ROPE, isDirectory: BOOL _ FALSE, referee: Pipal.Object] RETURNS [import: Import] = { IF isDirectory AND NOT ISTYPE [referee, Directory] THEN ERROR; import _ NEW [ImportRec _ [name: name, isDirectory: isDirectory, referee: referee]]; }; EnumerateObjectImports: PUBLIC PROC [object: Pipal.Object, each: EachImportProc] RETURNS [quit: BOOL _ FALSE] = { Each: PipalOps.EachChildProc = {quit _ EnumerateObjectImports[child, each]}; WITH object SELECT FROM import: Import => quit _ each[import]; ENDCASE => IF PipalOps.HasEnumerate[object] THEN quit _ PipalOps.Enumerate[object, Each]; }; ReplaceImport: PipalOps.ReplaceProc = { import: Import _ NARROW [parent]; IF import.referee=NIL THEN BindImport[import]; newParent _ CreateRefereedImport[import.name, import.isDirectory, map[import.referee]]; }; savedImports: RefTab.Ref _ RefTab.Create[]; WriteImport: ClassWriteProc = { import: Import _ NARROW [object]; SELECT TRUE FROM import.creationTime#BasicTime.nullGMT => {}; RefTab.Fetch[savedImports, import.referee].found => { refNS: REF CARD _ NARROW [RefTab.Fetch[savedImports, import.referee].val]; import.creationTime _ BasicTime.FromNSTime[refNS^]; }; ENDCASE => { fileName: ROPE _ FileName[import.name, import.isDirectory]; stream: STREAM; creationTime: BasicTime.GMT; [stream, creationTime] _ OpenFileStream[fileName]; [] _ RefTab.Store[savedImports, object, NEW [CARD _ BasicTime.ToNSTime[creationTime]]]; WriteObject[stream, import.referee]; IO.Close[stream]; import.creationTime _ creationTime; }; WriteRope[stream, import.name]; WriteBool[stream, import.isDirectory]; WriteGMT[stream, import.creationTime]; }; ReadImport: ClassReadProc = { name: Pipal.ROPE _ ReadRope[stream]; isDirectory: BOOL _ ReadBool[stream]; creationTime: BasicTime.GMT _ ReadGMT[stream]; object _ CreateTimedImport[name, isDirectory, creationTime]; }; Fetch: PUBLIC PROC [name: Pipal.ROPE] RETURNS [object: Pipal.Object _ NIL] = { creationTime: BasicTime.GMT _ FileInfo[name]; IF creationTime#BasicTime.nullGMT THEN RETURN [CreateTimedImport[name, FALSE, creationTime]]; creationTime _ FileInfo[FileName[name, TRUE]]; IF creationTime#BasicTime.nullGMT THEN RETURN [CreateTimedImport[name, TRUE, creationTime]]; }; ReadObjects: PUBLIC PROC [stream: STREAM] RETURNS [objects: Pipal.Objects _ NIL] = { size: NAT = ReadInt[stream]; THROUGH [0 .. size) DO objects _ CONS [ReadObject[stream], objects] ENDLOOP; RETURN [Pipal.Reverse[objects]]; }; ReadOverlay: ClassReadProc = { object _ Pipal.CreateOverlay[ReadObjects[stream]]; }; WriteOverlay: ClassWriteProc = { overlay: Pipal.Overlay _ NARROW [object]; WriteInt[stream, overlay.size]; FOR i: NAT IN [0 .. overlay.size) DO WriteObject[stream, overlay[i]] ENDLOOP; }; ReadIcon: ClassReadProc = { reference: Pipal.Object _ ReadObject[stream]; referent: Pipal.Object _ ReadObject[stream]; object _ Pipal.CreateIcon[reference, referent]; }; WriteIcon: ClassWriteProc = { icon: Pipal.Icon _ NARROW [object]; WriteObject[stream, icon.reference]; WriteObject[stream, icon.referent]; }; ReadAnnotation: ClassReadProc = { key: ATOM _ ReadAtom[stream]; valueKey: ATOM _ ReadAtom[stream]; value: REF _ SELECT valueKey FROM $Null => NIL, $Atom => ReadAtom[stream], $Rope => ReadRope[stream], $Ropes => ReadRopes[stream], $Rectangle => NEW [PipalInt.Rectangle _ ReadIntRectangle[stream]], ENDCASE => ERROR; object _ Pipal.CreateAnnotation[ReadObject[stream], key, value]; }; WriteAnnotation: ClassWriteProc = { annotation: Pipal.Annotation _ NARROW [object]; WriteAtom[stream, annotation.key]; IF annotation.value=NIL THEN WriteAtom[stream, $Null] ELSE WITH annotation.value SELECT FROM atom: ATOM => { WriteAtom[stream, $Atom]; WriteAtom[stream, atom]; }; rope: Pipal.ROPE => { WriteAtom[stream, $Rope]; WriteRope[stream, rope]; }; ropes: LIST OF Pipal.ROPE => { WriteAtom[stream, $Ropes]; WriteRopes[stream, ropes]; }; refRect: REF PipalInt.Rectangle => { WriteAtom[stream, $Rectangle]; WriteIntRectangle[stream, refRect^]; }; ENDCASE => ERROR; WriteObject[stream, annotation.child]; }; ReadTransform: ClassReadProc = { transformation: PipalInt.Transformation _ ReadIntTransformation[stream]; object _ PipalInt.TransformObject[transformation, ReadObject[stream]]; }; WriteTransform: ClassWriteProc = { trans: PipalInt.Transformation; sub: Pipal.Object _ NIL; IF PipalInt.CountChildren[object]#1 THEN ERROR; [trans, sub] _ PipalInt.NthChild[object]; WriteIntTransformation[stream, trans]; WriteObject[stream, sub]; }; ReadAbut: ClassReadProc = { inX: BOOL = ReadBool[stream]; object _ PipalInt.CreateAbut[inX, ReadObjects[stream]]; }; WriteAbut: ClassWriteProc = { abut: PipalInt.Abut _ NARROW [object]; WriteBool[stream, abut.inX]; WriteInt[stream, abut.size]; FOR i: NAT IN [0 .. abut.size) DO WriteObject[stream, abut[i]] ENDLOOP; }; Pipal.PutClassMethod[directoryClass, Pipal.describeMethod, NEW [Pipal.DescribeProc _ DescribeDirectory]]; Pipal.PutClassMethod[directoryClass, PipalInt.enumerateMethod, NEW [PipalInt.EnumerateProc _ EnumerateIntDirectory]]; Pipal.PutClassMethod[directoryClass, PipalOps.enumerateMethod, NEW [PipalOps.EnumerateProc _ EnumerateDirectory]]; Pipal.PutClassMethod[directoryClass, PipalOps.replaceMethod, NEW [PipalOps.ReplaceProc _ ReplaceDirectory]]; RegisterClass[directoryClass, ReadDirectory, WriteDirectory]; Pipal.PutClassMethod[importClass, Pipal.describeMethod, NEW [Pipal.DescribeProc _ DescribeImport]]; Pipal.PutClassMethod[importClass, PipalInt.enumerateMethod, NEW [PipalInt.EnumerateProc _ EnumerateIntImport]]; Pipal.PutClassMethod[importClass, PipalOps.enumerateMethod, NEW [PipalOps.EnumerateProc _ EnumerateOpsImport]]; Pipal.PutClassMethod[importClass, PipalOps.replaceMethod, NEW [PipalOps.ReplaceProc _ ReplaceImport]]; RegisterClass[importClass, ReadImport, WriteImport]; RegisterClass[Pipal.overlayClass, ReadOverlay, WriteOverlay]; RegisterClass[Pipal.iconClass, ReadIcon, WriteIcon]; RegisterClass[Pipal.annotationClass, ReadAnnotation, WriteAnnotation]; RegisterClass[PipalInt.transformClass, ReadTransform, WriteTransform]; RegisterClass[PipalInt.translationClass, ReadTransform, WriteTransform]; RegisterClass[PipalInt.orientClass, ReadTransform, WriteTransform]; RegisterClass[PipalInt.abutClass, ReadAbut, WriteAbut]; END. rPipalIOImpl.mesa Copyright Σ 1988 by Xerox Corporation. All rights reversed. Created by Bertrand Serlet, May 2, 1988 6:06:45 pm PDT Bertrand Serlet, May 13, 1988 2:04:22 pm PDT Prerequisites Class Registration PipalInt Data Types PipalReal Data Types Object Class IO Utilities Pipal Files Directory Imports Invariants for imports are quite complex. But several observations makes that mess manageable: - when isDirectory is TRUE, only the IntEnumeration and the Replacement act funny, the referee and creationTime are exactly like any regular object, although they refer to the directory itself. - there is a strict ordering for all imports of the same name (and the same isDirectory) by decreasing creationTime. When the creationTime is nullGMT, the referee has to be present, and only one such import can exist. It means Now[] and is more recent than any creationTime. maps all import referees saved or being saved (a REF creationTime). This avoids saving twice the same import. Imports + Directories Utility Overlay Icon Annotation All Transformations Abut Directory Initialization Import Initialization Initialization Κn˜– "Cedar" stylešœ™Icodešœ<™˜>Kšœ œœ%˜<šœ œœ˜Kšœœ.˜CKšœœ.˜KKšœ˜Kšœ˜Kšœ0˜0Kšœœ*œœ˜;Kšœ˜Kšœ˜Kšœ5˜5Kšœ4˜4Kšœ ˜ K˜—Kšœ˜K˜——™ šžœœœœœœœ˜ KšœœUœœ˜Kšœ œ˜*K˜K˜—š žœœ œœ œœ˜_Kšœ œ œ,˜HKšœœ˜.KšœS˜SK˜K˜—š ž œœœ œœœ˜~KšœœœZ˜mKšœ˜Kšœ˜K˜K˜—š ž œœœ œœœ˜bKšœœ˜Kšœ2˜2Kšœ˜Kšœ˜K˜K™——™ šœœ<œ˜gK˜—šžœ˜)Kšœœ ˜'Kšœ!˜!Kšœ%œœ'˜iK˜K˜—šžœ˜1Kšœœ ˜'Kšœ-˜-K˜K˜—šžœ˜.Kšžœ-˜5Kšœœ ˜'Kšœœ)˜HK˜K˜—š žœœœœ*œ˜zKšœ œ;˜JK˜K™—šžœ˜*KšžœD˜LKšœœ ˜'KšœK˜KKšœ-˜-KšœI˜IK˜K˜—šžœ˜"šžœ˜#Kšœ˜Kšœ˜K˜—Kšœœ ˜'Kšœ"˜"Kšœ%˜%Kšœ2˜2Kšœ-˜-K˜K˜—šž œ˜ Kšœ œ˜$Kšœ)˜)Kšœœ˜Kšœ0˜0šœ ˜Kšœ œ˜$Kšœ*˜*Kšœ'˜'Kšœ˜—Kšœœœ˜)Kšœ-˜-Kšœ˜K˜—š žœœœ$œœœ˜oKšœ1˜1K˜K™—šžœœœœœœœ˜jKšœœ˜"Kšœ œœœ˜4Kšœ(˜(Kšœ'˜'K˜——™bodyšœ_™_Mšœœ§™ΑšΟy”™”M™——šœ œ9œ˜^K˜—š žœœœœœœ˜Wšœ œ ˜Jšœ?˜CJšœ˜ —J˜J˜—šžœ˜&Kšœœ ˜!Kšœ!˜!šœ˜Kšœ˜Kšœ˜Kš œœœœœ˜5Kšœœ'œœ+˜fKš œœœœœœ ˜4Kšœ˜—K˜K˜—šžœ˜.Kšœœ ˜!Kšœœœ˜.šœ ˜ Kšœ˜šœ˜KšœœA˜]Kšœ˜—Kšœ˜—K˜K˜—šžœ˜.Kšœœ ˜!Kšœœœ˜.Kšœ˜K˜K˜—šž œœ˜%Jšœe˜eJšœ˜Jš œœœœœœ˜DJ˜J˜—šžœœœœœœœœ˜†Kšœ œR˜^K˜—K˜šžœœœœœœœ˜ƒJš œ œœœœœ˜>Kšœ œH˜TJ˜K˜—š žœœœ.œœœ˜qJšžœH˜Lšœœ˜Jšœ&˜&šœœ˜,Jšœ)˜-——J˜J˜—šž œ˜'Kšœœ ˜!Kšœœœ˜.KšœW˜WK˜K˜—˜+Kšœn™n—šž œ˜Kšœœ ˜!šœœ˜Kšœ,˜,šœ5˜5Jšœœœœ2˜JKšœ3˜3K˜—šœ˜ Kšœ œ-˜;Kšœœ˜Kšœœ˜Kšœ2˜2Kšœ(œœ&˜WKšœ$˜$Kšœ˜Kšœ#˜#K˜——Kšœ˜Kšœ&˜&Kšœ&˜&K˜K˜—šž œ˜Kšœ œ˜$Kšœ œ˜%Kšœœ˜.Kšœ<˜