DIRECTORY Basics USING [ByteBlt], Random USING [Create, NextInt, RandomStream], RefText USING [AppendChar, AppendRope, New], Rope USING [Equal, Find, FromRefText, Length, ROPE], YggDID USING [DID, ValidateDID], YggDummyRPC USING [unencrypted], YggEnvironment USING [Outcome, TransID], YggIndex USING [], YggNav USING [ErrorDesc, LinkList], YggRep USING [AccurateGMT, AccurateGMTRep, Attribute, Bits, BitsRep, BytesFromBits, BytesToBits, date, DocType, float, int, lastReservedDocType, rope, shortRope, SetSizeOfBits, TypedPrimitiveElement, uninterpretedBytes, VDoc, VolatizeFromDID], YggTransaction USING [Check, Create, Finish]; YggNavImpl: CEDAR MONITOR IMPORTS Basics, Random, RefText, Rope, YggDID, YggRep, YggTransaction EXPORTS YggDID, YggNav ~ BEGIN ROPE: TYPE = Rope.ROPE; Error: PUBLIC ERROR [error: YggNav.ErrorDesc] = CODE; RootPath: PUBLIC ROPE _ "/tregonsee"; RootPathToRoots: PUBLIC ROPE _ "/tregonsee"; randomCharStream: Random.RandomStream; DID: PUBLIC TYPE ~ REF DIDRep; DIDRep: PUBLIC TYPE ~ ROPE; StartTransaction: PUBLIC PROC RETURNS [trans: YggEnvironment.TransID] ~ { trans _ YggTransaction.Create[conversation: YggDummyRPC.unencrypted, createLocalWorker: TRUE]; }; EndTransaction: PUBLIC PROC [trans: YggEnvironment.TransID, commit: BOOL] RETURNS [ok: BOOL _ TRUE] ~ { outcome: YggEnvironment.Outcome; [outcome: outcome] _ YggTransaction.Finish[conversation: YggDummyRPC.unencrypted, transID: trans, requestedOutcome: IF commit THEN commit ELSE abort, continue: FALSE]; IF outcome = commit THEN RETURN [TRUE] ELSE RETURN [FALSE]; }; CheckTransaction: PUBLIC PROC [trans: YggEnvironment.TransID] RETURNS [ok: BOOL _ TRUE] ~ { outcome: YggEnvironment.Outcome; [outcome: outcome] _ YggTransaction.Check[transID: trans]; IF outcome = unknown THEN RETURN [TRUE] ELSE RETURN [FALSE]; }; GetRoots: PUBLIC PROC RETURNS [roots: LIST OF DID] ~ { enumProc: PROC [localName, symbolicName: ROPE] RETURNS [continue: BOOL _ TRUE] = { did: DID; did _ NEW[DIDRep]; did^ _ symbolicName; roots _ CONS[did, roots]; }; EnumerateSymbolicLinksInDirectory [directory: RootPathToRoots, proc: enumProc]; }; AddRoot: PUBLIC PROC [did: DID] RETURNS [ok: BOOL] ~ { tries: INT _ 0; nameSize: INT _ 4; unixdid: REF TEXT ~ UnixStringFromRope[did^]; name1: CARD ~ LOOPHOLE[unixdid, CARD]+UNITS[TEXT[0]]; IF ~YggDID.ValidateDID[did] THEN RETURN [FALSE]; DO sl: INT; symname: REF TEXT _ RefText.New[nameSize]; unixSymname: REF TEXT _ NIL; name2: CARD; FOR charNo: INT IN [0..nameSize) DO [] _ RefText.AppendChar[to: symname, from: Random.NextInt[] + 'a]; ENDLOOP; unixSymname _ UnixStringFromRope[""]; name2 _ LOOPHOLE[unixSymname, CARD]+UNITS[TEXT[0]]; sl _ Symlink[name1, name2]; IF sl = 0 THEN EXIT; tries _ tries + 1; IF tries MOD 250 = 0 THEN nameSize _ MIN[50, nameSize + 1]; ENDLOOP; }; RemoveRoot: PUBLIC PROC [did: DID] RETURNS [ok: BOOL] ~ { enumProc: PROC [localName, symbolicName: ROPE] RETURNS [continue: BOOL _ TRUE] = { IF Rope.Equal[did^, symbolicName] THEN { nameToDelete _ localName; continue _ FALSE; }; }; nameToDelete: ROPE _ NIL; EnumerateSymbolicLinksInDirectory [directory: RootPathToRoots, proc: enumProc]; IF nameToDelete # NIL THEN { unixNameToDelete: REF TEXT ~ UnixStringFromRope[nameToDelete]; [] _ Unlink[LOOPHOLE[unixNameToDelete, CARD]+UNITS[TEXT[0]]]; }; }; GetTypeOfContents: PUBLIC PROC [trans: YggEnvironment.TransID, did: YggDID.DID] RETURNS [YggRep.DocType] ~ { document: YggRep.VDoc; document _ YggRep.VolatizeFromDID[trans, did]; RETURN[document.contents.docType]; }; GetUninterpretedContents: PUBLIC UNSAFE PROC [trans: YggEnvironment.TransID, did: DID, firstByte: CARD, byteCount: CARD, to: LONG POINTER] RETURNS [bytesMoved: CARD] ~ { document: YggRep.VDoc; document _ YggRep.VolatizeFromDID[trans, did]; IF document.contents.docType # YggRep.uninterpretedBytes AND document.contents.docType <= YggRep.lastReservedDocType THEN ERROR Error[[$invalidReservedType, "Attempt to access a TypedPrimitiveElement with reserved type as uninterpreted"]]; YggRep.BytesFromBits[bits: document.contents.bits, startByte: firstByte, block: [base: LOOPHOLE[to], startIndex: 0, count: byteCount]]; }; GetContents: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] RETURNS [contents: YggRep.TypedPrimitiveElement] ~ { document: YggRep.VDoc; document _ YggRep.VolatizeFromDID[trans, did]; RETURN[document.contents]; }; SetUninterpretedContents: PUBLIC UNSAFE PROC [trans: YggEnvironment.TransID, did: YggDID.DID, firstByte: CARD, byteCount: CARD, from: LONG POINTER] RETURNS [bytesMoved: CARD] ~ { document: YggRep.VDoc; newRef: BOOL; newBits: YggRep.Bits; document _ YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]]; IF document.contents.docType # YggRep.uninterpretedBytes AND document.contents.docType <= YggRep.lastReservedDocType THEN ERROR Error[[$invalidReservedType, "Attempt to set a TypedPrimitiveElement with reserved type as uninterpreted"]]; [newRef: newRef, newBits: newBits] _ YggRep.BytesToBits[bits: document.contents.bits, startByte: firstByte, block: [base: LOOPHOLE[from], startIndex: 0, count: byteCount]]; IF newRef THEN document.contents.bits _ newBits; RETURN[byteCount]; }; SetContents: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, contents: YggRep.TypedPrimitiveElement] ~ { document: YggRep.VDoc; document _ YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]]; document.contents _ contents; }; SetSize: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, size: CARD] ~ { document: YggRep.VDoc; newRef: BOOL; newBits: YggRep.Bits; document _ YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]]; IF document.contents.docType # YggRep.uninterpretedBytes AND document.contents.docType <= YggRep.lastReservedDocType THEN ERROR Error[[$invalidReservedType, "Attempt to set a TypedPrimitiveElement with reserved type as uninterpreted"]]; [newRef: newRef, newBits: newBits] _ YggRep.SetSizeOfBits[bits: document.contents.bits, size: size]; IF newRef THEN document.contents.bits _ newBits; }; GetProperty: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, propertyName: ROPE] RETURNS [propertyExists: BOOL, property: YggRep.Attribute] ~ { }; GetAllProperties: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] RETURNS [properties: LIST OF YggRep.Attribute] ~ { }; ListAllProperties: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] RETURNS [propertyNames: LIST OF ROPE] ~ { }; SetProperty: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, propertyName: ROPE, property: YggRep.Attribute] ~ { }; ConstructIntTPE: PUBLIC PROC [int: INT32] RETURNS [property: YggRep.TypedPrimitiveElement] ~ { ri: REF INT32; ri _ NEW[INT32 _ int]; property _ [YggRep.int, ri]; }; ConstructFloatTPE: PUBLIC PROC [float: REAL32] RETURNS [property: YggRep.TypedPrimitiveElement] ~ { rReal: REF REAL32; rReal _ NEW[REAL32 _ float]; property _ [YggRep.float, rReal]; }; ConstructDateTPE: PUBLIC PROC [date: YggRep.AccurateGMTRep] RETURNS [property: YggRep.TypedPrimitiveElement] ~ { rAccurateGMT: YggRep.AccurateGMT; rAccurateGMT _ NEW[YggRep.AccurateGMTRep _ date]; property _ [YggRep.date, rAccurateGMT]; }; ConstructShortRopeTPE: PUBLIC PROC [rope: ROPE] RETURNS [property: YggRep.TypedPrimitiveElement] ~ { IF Rope.Find[rope, "\000"] = -1 THEN { property _ [YggRep.shortRope, rope]; } ELSE ERROR Error[[$shortRopeWithNulls, "Rope has nulls"]]; }; ConstructRopeTPE: PUBLIC PROC [rope: ROPE] RETURNS [property: YggRep.TypedPrimitiveElement] ~ { property _ [YggRep.rope, rope]; }; ConstructUninterpretedBytesTPE: PUBLIC PROC [docType: YggRep.DocType, bytes: LONG POINTER, size: CARD] RETURNS [property: YggRep.TypedPrimitiveElement] ~ { nBytes: CARD; rBits: REF YggRep.BitsRep; IF docType # YggRep.uninterpretedBytes AND docType <= YggRep.lastReservedDocType THEN ERROR Error[[$invalidReservedType, "Attempt to create a TypedPrimitiveElement with reserved type"]]; rBits _ NEW[YggRep.BitsRep[size]]; rBits.validBytes _ size; TRUSTED {nBytes _ Basics.ByteBlt[ from: [blockPointer: bytes, startIndex: 0, stopIndexPlusOne: size], to: [blockPointer: LOOPHOLE[rBits, POINTER] + SIZE[YggRep.BitsRep[0]], startIndex: 0, stopIndexPlusOne: size]]; }; IF nBytes # size THEN ERROR; property _ [docType, rBits]; }; GetTypedOutlinks: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, linkType: ROPE] RETURNS [LIST OF DID _ NIL] ~ { }; GetAllOutlinks: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] RETURNS [LIST OF YggNav.LinkList _ NIL] ~ { }; GetTypedInlinks: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, linkType: ROPE] RETURNS [LIST OF DID _ NIL] ~ { }; GetAllInlinks: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] RETURNS [LIST OF YggNav.LinkList _ NIL] ~ { }; SnapLink: PUBLIC PROC [trans: YggEnvironment.TransID, fromDID: DID, toDID: DID, linkType: ROPE] RETURNS [linkDID: DID _ NIL] ~ { }; GetDefaultContainer: PUBLIC PROC [trans: YggEnvironment.TransID] RETURNS [DID _ NIL] ~ { }; SetDefaultContainer: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] ~ { }; AddToContainer: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, containerDID: DID] ~ { }; RemoveFromContainer: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, containerDID: DID] RETURNS [ok: BOOL _ TRUE] ~ { }; GetObjectsInContainer: PUBLIC PROC [trans: YggEnvironment.TransID, containerDID: DID] RETURNS [LIST OF DID _ NIL] ~ { }; AddContainerToContainer: PUBLIC PROC [trans: YggEnvironment.TransID, subcontainerDID: DID, containerDID: DID] ~ { }; RemoveContainerFromContainer: PUBLIC PROC [trans: YggEnvironment.TransID, subcontainerDID: DID, containerDID: DID] RETURNS [ok: BOOL _ TRUE] ~ { }; GetContainersInContainer: PUBLIC PROC [trans: YggEnvironment.TransID, containerDID: DID] RETURNS [LIST OF DID _ NIL] ~ { }; CreateObject: PUBLIC PROC [trans: YggEnvironment.TransID, containerDID: DID] RETURNS [did: DID _ NIL] ~ { }; RemoveObject: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] ~ { }; CreateIndex: PUBLIC PROC [trans: YggEnvironment.TransID, containerDID: DID, pattern: ROPE] RETURNS [did: DID _ NIL] ~ { }; ListIndexPatterns: PUBLIC PROC [trans: YggEnvironment.TransID, containerDID: DID] RETURNS [patterns: LIST OF ROPE _ NIL] ~ { }; RemoveIndex: PUBLIC PROC [trans: YggEnvironment.TransID, containerDID: DID, pattern: ROPE] RETURNS [ok: BOOL _ TRUE] ~ { }; DIR: TYPE ~ PACKED RECORD [ ddFd: INT, ddLoc: INT, ddSize: INT, ddBbase: INT, ddEntno: INT, ddBsize: INT, ddBuf: LONG POINTER TO ARRAY [0..0] OF CHAR ]; direct: TYPE ~ PACKED RECORD [ dFileno: CARD32, dReclen: CARD16, dNamlen: CARD16, dName: LONG POINTER TO ARRAY [0..0] OF CHAR ]; UnixStringFromRope: PROC [rope: ROPE] RETURNS [REF TEXT] ~ { len: INT _ rope.Length[]; rtn: REF TEXT _ RefText.New[len+1]; [] _ RefText.AppendRope[to: rtn, from: rope]; [] _ RefText.AppendChar[to: rtn, from: '\000]; RETURN[rtn]; }; EnumerateSymbolicLinksInDirectory: PROC [directory: ROPE, proc: PROC [localName, symbolicName: ROPE] RETURNS [continue: BOOL _ TRUE]] ~ { dirStream: LONG POINTER TO DIR; cont: BOOL; unixDirName: REF TEXT ~ UnixStringFromRope[directory]; dirStream _ Opendir[LOOPHOLE[unixDirName, CARD]+UNITS[TEXT[0]]]; IF dirStream # NIL THEN { symLinkBuff: REF TEXT _ RefText.New[256]; symLinkResult: REF TEXT _ RefText.New[1024]; resetLen: INT; [] _ RefText.AppendRope[to: symLinkBuff, from: directory]; [] _ RefText.AppendChar[to: symLinkBuff, from: '/]; resetLen _ symLinkBuff.length; DO dirp: LONG POINTER TO direct; cc: INT; symLinkName: ROPE; localName: ROPE; localNameLength: INT; dirp _ Readdir[dirStream]; IF dirp = NIL THEN EXIT; symLinkBuff.length _ resetLen; TRUSTED { localNameLength _ dirp.dNamlen; FOR charNo: INT IN [0..localNameLength] DO [] _ RefText.AppendChar[to: symLinkBuff, from: dirp.dName[charNo]]; ENDLOOP; }; [] _ RefText.AppendChar[to: symLinkBuff, from: '\000]; cc _ Readlink[path: LOOPHOLE[symLinkBuff, CARD] +UNITS[TEXT[0]], buf: LOOPHOLE[symLinkResult, CARD]+UNITS[TEXT[0]], bufsiz: 1023]; IF cc <= 0 THEN LOOP; symLinkResult.length _ cc; symLinkName _ Rope.FromRefText[s: symLinkResult, start: 0, len: cc]; localName _ Rope.FromRefText[s: symLinkBuff, start: 0, len: resetLen + localNameLength]; cont _ proc[localName, symLinkName]; IF ~cont THEN EXIT; ENDLOOP; [] _ Closedir[dirStream]; }; }; Symlink: PROC [name1: CARD, name2: CARD] RETURNS [INT] ~ TRUSTED MACHINE CODE { "symlink" }; Opendir: PROC [name: CARD] RETURNS [LONG POINTER TO DIR] ~ TRUSTED MACHINE CODE { "opendir" }; Readdir: PROC [LONG POINTER TO DIR] RETURNS [LONG POINTER TO direct] ~ TRUSTED MACHINE CODE { "readdir" }; Closedir: PROC [LONG POINTER TO DIR] RETURNS [trash: INT] ~ TRUSTED MACHINE CODE { "closedir" }; Readlink: PROC [path: CARD, buf: CARD, bufsiz: INT] RETURNS [cc: INT] ~ TRUSTED MACHINE CODE { "readlink" }; Unlink: PROC [path: CARD] RETURNS [cc: INT] ~ TRUSTED MACHINE CODE { "unlink" }; randomCharStream _ Random.Create[range: 26]; END. jYggNavImpl.mesa Copyright Σ 1988 by Xerox Corporation. All rights reserved. Bob Hagmann May 3, 1988 9:51:35 am PDT Top level navigational interface for Yggdrasil. Types, variables, and constants For Phase 0, the DIDRep is just a string that names a directory (without the trailing /). Transactions Note: none of the root operations operate under transaction control Start up a new transaction. Commit or abort a transaction. Check on a transaction. If it has been aborted, ok is FALSE. Root objects Note: none of the root operations operate under transaction (or any other!) control Get all the root objects for the service. Add a root object. If the DID does not exist, FALSE will be returned. Remove a root object. If the DID is not a root object, FALSE will be returned. Object contents Get the contents of the object with the specified did. Errors: $invalidDID, $invalidTrans Get the contents of the object with the specified did. The contents must not be a well known interpreted type (e. g., int, date, float, ...) Errors: $invalidDID, $invalidTrans, $invalidReservedType Get the contents of the object with the specified did. Errors: $invalidDID, $invalidTrans Set the contents of the object with the specified did. The object is grown if needed. Errors: $invalidDID, $invalidTrans Set the contents of the object with the specified did. The object is grown if needed. Errors: $invalidDID, $invalidTrans Set the contents of the object with the specified did. The object is grown if needed. Errors: $invalidDID, $invalidTrans, Object property manipulation Get the named property of the object with the specified did. If the property does not exist, [FALSE, [NIL, NIL]] is returned. Errors: $invalidDID, $invalidTrans Get all the properties of the object with the specified did. If no properties exist, NIL is returned. Errors: $invalidDID, $invalidTrans Get all the property names of the object with the specified did. If no properties exist, NIL is returned. Errors: $invalidDID, $invalidTrans Set the contents of the object with the specified did. The object is grown if needed. Errors: $invalidDID, $invalidTrans Object property construction Note: all of these procedures copy data. Construct a YggRep.TypedPrimitiveElement for a 32 bit integer. Errors: $invalidDID, $invalidTrans Construct a YggRep.TypedPrimitiveElement for a 32 bit real. Construct a YggRep.TypedPrimitiveElement for a date. Construct a YggRep.TypedPrimitiveElement for a ROPE that is short (less than a few disk pages preferred) and contains no nulls. Errors: $shortRopeWithNulls Construct a YggRep.TypedPrimitiveElement for a ROPE that is long (more than a disk page preferred) and may contain no nulls. Construct a YggRep.TypedPrimitiveElement for an array of bytes. Errors: $$invalidReservedType Links Get the did's of all the outlinks for this object with "link type" propertyName. Errors: $invalidDID, $invalidTrans Get the did's of all the outlinks for this object. Errors: $invalidDID, $invalidTrans Get the did's of all the inlinks for this object with "link type" propertyName. Errors: $invalidDID, $invalidTrans Get the did's of all the inlinks for this object. Errors: $invalidDID, $invalidTrans Construct a link between the two dids. Errors: $invalidDID, $invalidTrans Containers Get the default container for this transaction. Errors: $invalidDID, $invalidTrans Set the default container for this transaction. Errors: $invalidDID, $invalidTrans Add the object to the container. Errors: $invalidDID, $invalidTrans Remove the object from the container. Errors: $invalidDID, $invalidTrans Get the did's of all the objects in this container. containerDID of NIL means use the default container. Errors: $invalidDID, $invalidTrans Add the subcontainer to the container. Errors: $invalidDID, $invalidTrans Remove the subcontainer from the container. Errors: $invalidDID, $invalidTrans Get the did's of all the containers in this container. containerDID of NIL means use the default container. Errors: $invalidDID, $invalidTrans Object creation and destruction Make up a new object in the specified container. The default container for the transaction is used if containerDID is NIL. Errors: $invalidDID, $invalidTrans Remove a object. Any links pointing to this object are also removed. This is a recursive process (if the links are really objects). Errors: $invalidDID, $invalidTrans Indices Index all properties in the container whose property name matches the pattern. Errors: $invalidDID, $invalidTrans Remove a pattern from a container. The pattern must exactly match an existing pattern. Errors: $invalidDID, $invalidTrans Remove a pattern from a container. The pattern must exactly match an existing pattern. Errors: $invalidDID, $invalidTrans Utilities From dir.h: typedef struct _dirdesc { int dd_fd; long dd_loc; long dd_size; long dd_bbase; long dd_entno; long dd_bsize; char *dd_buf; } DIR; struct direct { u_long d_fileno; /* file number of entry */ u_short d_reclen; /* length of this record */ u_short d_namlen; /* length of string in d_name */ char d_name[MAXNAMLEN + 1]; /* name (up to MAXNAMLEN + 1) */ }; Unix system calls Initialization Κ8˜codešœ™Kšœ<™˜EKšœ˜šœ˜K˜—head™Icode0šœœœ˜M˜KšΟnœœœœ˜5K˜Kšœ  œ˜%Kšœ œ˜,K˜Kšœ&˜&K˜Kšœœœœ˜šœœœœ˜K™Y—K˜—™ K™CK™šŸœœœœ$˜IK™KšœXœ˜^K˜K™—šŸœœœ)œœœœ˜gK™Kšœ ˜ Kš œtœœœœ˜§Kšœœœœœœœ˜;Kšœ˜K™—š Ÿœœœ!œ œ˜[Kšœ1Οoœœ™=Kšœ ˜ Kšœ:˜:Kšœœœœœœœ˜™>K™"Kšœœœ˜Kšœœœ˜Kšœ˜K˜K™—š Ÿœœœ œœ-˜cKšœ;™;Kšœœœ˜Kšœœœ ˜Kšœ!˜!K˜K™—šŸœœœœ-˜pKšœ4™4Kšœ!˜!Kšœœ˜1Kšœ'˜'K˜K™—š Ÿœœœœœ-˜dKšœ/œL™K™šœœ˜&Kšœ$˜$K˜—Kšœœœ0˜;K˜K™—š Ÿœœœœœ-˜_Kšœ/œI™|Kšœ˜K˜K™—šŸœœœ"œœœœ-˜›Kšœ?™?K™Kšœœ˜ Kšœœ˜KšœVœ_˜ΊKšœœ˜"Kšœ˜šœ˜!KšœD˜DKšœœœœ=˜oK˜—Kšœœœ˜Kšœ˜K˜——™šŸœœœ&œ œœœœœœ˜wKšœP™PK™"K˜K™—šŸœœœ&œœœœœ˜qKšœ2™2K™"K˜K™—šŸœœœ&œ œœœœœœ˜vKšœO™OK™"K˜K™—šŸ œœœ&œœœœœ˜pKšœ1™1K™"K˜K™—šŸœœœ*œ œ œœ œœ˜€K™&K™"K˜——™ š Ÿœœœ!œœœ˜XKšœ/™/K™"K˜K™—šŸœœœ&œ˜NKšœ/™/K™"K˜K™—š Ÿœœœ&œœ˜\K™ K™"K˜K™—šŸœœœ&œœœœœ˜{K™%K™"K˜K™—šŸœœœ/œœœœœœ˜uKšœ5  œœ!™iK™"K˜K™—š Ÿœœœ2œœ˜qK™&K™"K˜K™—šŸœœœ2œœœœœ˜K™+K™"K˜K™—šŸœœœ/œœœœœœ˜xKšœ8  œœ!™lK™"K˜——™šŸ œœœ/œœœœ˜iKšœg  œœ™{K™"K˜K™—šŸ œœœ&œ˜GKšœ‡™‡K™"K˜K™——™šŸ œœœ/œ œœœœ˜wKšœN™NK™"K˜K™—šŸœœœ/œœ œœœœ˜|KšœW™WK™"K˜K™—šŸ œœœ/œ œœœœ˜xKšœW™WK™"K˜——™ ™ Kšœξ™ξ—K˜šœœœœ˜Kšœœ˜ Kšœœ˜ Kšœœ˜ Kšœ œ˜ Kšœ œ˜ Kšœ œ˜ Kšœœœœ˜+Kšœ˜K˜—šœœœœ˜Kšœ œ˜Kšœ œ˜Kšœ œ˜Kšœœœœ˜+Kšœ˜—K˜š Ÿœœœœœœ˜