DIRECTORY AdobeIO USING [LocalAndDomain], AdobeOps USING [ARSystemHandle], ARAccess USING [ARStorage, DataTable, ErrorCode], Convert USING [RopeFromCard], IO USING [Close, EndOfStream, Error, GetChar, STREAM], PFS USING [AbsoluteName, Close, Error, ErrorDesc, Open, OpenFile, PATH, PathFromRope, StreamFromOpenFile], RefText USING [AppendChar, ObtainScratch, ReleaseScratch], Rope USING [Cat, Concat, FromRefText, Length, ROPE, Text]; ARAccessImpl: CEDAR MONITOR --LOCKS session USING session: Session IMPORTS AdobeIO, Convert, IO, RefText, Rope, PFS --Auth, Courier, MSegment, NSDataStream, NSFile, NSName, NSString, --Process, Stream, String EXPORTS ARAccess = BEGIN OPEN ARAccess; Session: TYPE = AdobeOps.ARSystemHandle; ARHandle: TYPE = REF ARObject; ARObject: PUBLIC TYPE = RECORD [ password: CARDINAL ¬ ARPassword, fH: PFS.OpenFile ¬ NIL, --NSFile.Handle ¬ NSFile.nullHandle, sH: IO.STREAM ¬ NIL, name: Rope.ROPE ¬ NIL, --NSFile.String ¬ NSFile.nullString, number: CARDINAL ¬ LAST[CARDINAL], checkedOut: BOOLEAN ¬ FALSE]; CommandType: TYPE = {get, examine, checkout, checkin, submit, null}; SessionPassword: CARDINAL = 567B; ARPassword: CARDINAL = 234B; maxFileName: CARDINAL = 100; maxDigits: CARDINAL = 5; -- constant length of an AR filename secondsToWaitForCheckedOutAR: CARD --Process.Seconds-- = 0; Error: PUBLIC ERROR [session: Session, why: ErrorCode] = CODE; GetAR: PUBLIC PROCEDURE [session: Session, arNumber: CARDINAL] RETURNS [arH: ARHandle] = BEGIN getAR: PROC = { arH ¬ NEW[ARObject ¬ [ fH: OpenFileHandleOnAR[session, arNumber], number: arNumber]]; }; CatchErrors[session, getAR, get]; RETURN[arH] END; OpenFileHandleOnAR: PROCEDURE [ session: Session, arNumber: CARDINAL] RETURNS [fH: PFS.OpenFile --NSFile.Handle--] = { arFileName: Rope.ROPE ¬ NIL; --[maxFileName]; dH: PFS.PATH ¬ OpenSubDirectory[session, arNumber]; fH ¬ PFS.Open[ name: PFS.AbsoluteName[ARNumberToFileName[arNumber], dH]]; -- CloseFile[@dH, session] -- }; FreeAR: PUBLIC PROCEDURE [session: Session, arH: ARHandle] RETURNS [nil: ARHandle] = { IF arH.checkedOut THEN ERROR Error[session, youMustFirstCheckIn]; CloseFile[arH--@arH.fH--, session]; RETURN[NIL]; }; ExamineAR: PUBLIC PROCEDURE [session: Session, arH: ARHandle] RETURNS [to: ARAccess.ARStorage] = { Sink: PROC [source: ARHandle] = { ENABLE UNWIND => IO.Close[source.sH]; to ¬ CopyAR[session: session, from: source ! UNWIND => IO.Close[source.sH]]; }; examineAR: PROC = { Sink[arH]; CloseFile[arH, session]; }; CatchErrors[session, examineAR, examine] }; CatchErrors: PROCEDURE [session: Session, proc: PROC, type: CommandType] = BEGIN ENABLE { PFS.Error => PFSError[session, error]; IO.Error => ERROR Error[session, communicationError] }; proc[]; END; PFSError: PROC [session: Session, error: PFS.ErrorDesc] = BEGIN SELECT error.group FROM bug => SELECT error.code FROM $inconsistent => ERROR Error[session, unknown]; ENDCASE => ERROR Error[session, unknown]; environment => SELECT error.code FROM $accessDenied => ERROR Error[session, accessDenied]; $quotaExceeded => ERROR Error[session, directoryFull]; $volumeFull => Error[session, fileServerFull]; ENDCASE => ERROR Error[session, authError]; client => SELECT error.code FROM $unkownFile =>ERROR Error[session, arNotFound]; ENDCASE => ERROR Error[session, unknown]; user => SELECT error.code FROM $versionSpecified => Error[session, invalidARNumber]; ENDCASE => ERROR Error[session, communicationError]; ENDCASE => ERROR Error[session, communicationError]; END; ARNumberToFileName: PROCEDURE [number: CARDINAL--, name: Rope.ROPE--] RETURNS [PFS.PATH] = { temp: Rope.ROPE ¬ NIL; --[maxFileName]; temp ¬ temp.Concat[Convert.RopeFromCard[number, 10, FALSE]]; FOR i: CARDINAL IN [0..maxDigits - temp.Length) DO temp ¬ Rope.Concat["0", temp]; ENDLOOP; temp ¬ temp.Concat[".AR"]; RETURN[PFS.PathFromRope[temp]] }; AddPairToTable: PROCEDURE [arS: ARAccess.ARStorage, field, value: Rope.ROPE] RETURNS [newARS: ARAccess.ARStorage ¬ NIL] = { oldLen: CARD ¬ IF arS # NIL THEN arS.index ELSE 0; newARS ¬ NEW[ARAccess.DataTable[oldLen + 1]]; FOR i: CARD IN [0..oldLen) DO newARS[i] ¬ arS[i]; ENDLOOP; newARS[oldLen] ¬ [field, value]; newARS.index ¬ oldLen + 1; }; AppendChar: PUBLIC PROCEDURE [r: Rope.ROPE, c: CHAR] RETURNS [Rope.ROPE] = { scratch: REF TEXT = RefText.ObtainScratch[3]; result: Rope.Text = Rope.FromRefText[RefText.AppendChar[scratch, c]]; RefText.ReleaseScratch[scratch]; RETURN[r.Concat[result]]; }; CopyAR: PROC [session: Session, from: ARHandle] RETURNS [to: ARAccess.ARStorage] = { field, value: Rope.ROPE ¬ NIL; c: CHAR; { ENABLE IO.EndOfStream => { IO.Close[from.sH]; IF (field # NIL) THEN to ¬ AddPairToTable[to, field, value]; GOTO done; }; from.sH ¬ PFS.StreamFromOpenFile[from.fH]; DO c ¬ IO.GetChar[from.sH ! IO.EndOfStream => {IO.Close[from.sH]; GOTO done}]; WHILE c # ': DO IF c = '' THEN c ¬ IO.GetChar[from.sH]; field ¬ AppendChar[field, c]; c ¬ IO.GetChar[from.sH]; ENDLOOP; c ¬ IO.GetChar[from.sH]; c ¬ IO.GetChar[from.sH]; WHILE c # ('J - 75B) DO IF c = '' THEN c ¬ IO.GetChar[from.sH]; value ¬ AppendChar[value, c]; c ¬ IO.GetChar[from.sH]; ENDLOOP; c ¬ IO.GetChar[from.sH]; to ¬ AddPairToTable[to, field, value]; field ¬ value ¬ NIL; ENDLOOP; EXITS done => {}; } }; CloseFile: PROC [arH: ARHandle --fH: REF NSFile.Handle--, session: Session] = { IF arH.fH # NIL THEN { PFS.Close[arH.fH ! PFS.Error => CONTINUE]; arH.fH ¬ NIL } }; OpenSubDirectory: PROCEDURE [session: Session, arNumber: CARDINAL] RETURNS [dH: PFS.PATH --NSFile.Handle--] = { pathRope: Rope.ROPE ¬ NIL; pathRope ¬ Rope.Cat[ AdobeIO.LocalAndDomain[session.host], "-XNS:/", session.directory, "/"]; RETURN[PFS.PathFromRope[pathRope]] -- ** for now ** -- }; END... 24-Jul-87 17:31:11 - rlc - fix NSDataStream catch phrases 6 Copyright Σ 1984, 1985, 1991, 1992 by Xerox Corporation. All rights reserved. File: ARAccessImpl.mesa - last edit: BJD 15-Jul-85 12:58:26 RSF 25-Sep-85 14:19:36 Pam 10-Jan-85 17:10:44 JCS 2-Aug-85 15:52:29 rlc 24-Jul-87 17:31:11 Philip James, March 20, 1991 5:04 pm PST Auth USING [CopyIdentity, FreeIdentity, IdentityHandle], Courier USING [Error, ErrorCode], Environment USING [Block, bytesPerPage], MSegment USING [Address, Create, Handle, Kill], NSAssignedTypes USING [tText], NSDataStream USING [ Abort, Aborted, Handle, SinkStream, Source, SourceStream], NSFile USING [ Attribute, AttributesRecord, ChangeControls, ClearAttributes, Close, Error, ErrorRecord, fullAccess, GetAttributes, Handle, ID, Logoff, LogonDirect, nullHandle, nullID, nullSession, nullString, Open, OpenByName, Probe, readAccess, Reference, Retrieve, Selections, ServiceRecord, Session, Source, Store, String], NSName USING [ClearName, CopyNameFields, String], NSString USING [ CopyString, FreeString, String, StringFromMesaString, SubString], Process USING [Abort, Detach, Pause, Seconds, SecondsToTicks], Stream USING [ Block, CompletionCode, defaultInputOptions, Delete, EndOfStream, Handle, SubSequenceType], String USING [AppendChar, AppendLongNumber, AppendString]; -- -- -- -- -- -- -- TYPES & CONSTANTS : -- -- -- -- -- -- -- Session: TYPE = REF SessionObject; SessionObject: PUBLIC TYPE = MONITORED RECORD [ sessionPassword: CARDINAL _ SessionPassword, z: UNCOUNTED ZONE _ NIL, nsFileSession: NSFile.Session _ NSFile.nullSession, referenceToARs: NSFile.Reference _ [ fileID: NSFile.nullID, service: NIL], dirH: NSFile.Handle _ NSFile.nullHandle, userId: Auth.IdentityHandle _ NIL, buffer: MSegment.Handle _ NIL, probingProcess: PROCESS _ NIL, sessionError: BOOLEAN _ FALSE]; parentID: NSFile.ID _ NSFile.nullID, -- -- -- -- -- -- -- PUBLIC PROCEDURES : -- -- -- -- -- -- -- Create: PUBLIC PROCEDURE [ zone: UNCOUNTED ZONE, arLocation: NSFile.Reference] RETURNS [session: Session] = BEGIN session _ NEW[ SessionObject _ [ z: zone, referenceToARs: [ fileID: arLocation.fileID, service: NEW[ NSFile.ServiceRecord _ [ systemElement: arLocation.service.systemElement]]]]]; NSName.CopyNameFields[ z: zone, source: @arLocation.service.name, destination: @session.referenceToARs.service.name]; END; Destroy: PUBLIC PROCEDURE [session: Session] = BEGIN z: UNCOUNTED ZONE; Logoff[session]; z _ session.z; --wait to extract z til here in case session=NIL IF session.userId # NIL THEN Auth.FreeIdentity[identityPtr: @session.userId, z: session.z]; IF session.referenceToARs.service # NIL THEN { NSName.ClearName[z, @session.referenceToARs.service.name]; z.FREE[@session.referenceToARs.service]}; z.FREE[@session] END; Logon: PUBLIC PROCEDURE [ session: Session, user: Auth.IdentityHandle] = BEGIN ValidateSession[session]; IF session.userId # NIL THEN Auth.FreeIdentity[identityPtr: @session.userId, z: session.z]; session.userId _ Auth.CopyIdentity[identity: user, z: session.z]; END; Logoff: PUBLIC PROCEDURE [session: Session] = BEGIN ValidateSession[session]; IF session.nsFileSession # NSFile.nullSession THEN IF session.probingProcess # NIL THEN ERROR Error[session, currentlyCheckedOut] ELSE CloseFileSession[session]; END; Holds open file handle within open file session; fH _ NSFile.OpenByName[ directory: dH, path: ARNumberToFileName[arNumber, arFileName], session: session.nsFileSession, controls: [ lock: share, access: NSFile.readAccess, timeout: secondsToWaitForCheckedOutAR]]; ** with current impl of OpenSubDirectory, for now don't close; ValidateSession[session]; ValidateAR[arH, session]; session.z.FREE[@arH]; ExamineAR: PUBLIC PROCEDURE [session: Session, arH: ARHandle, to: ARAccess.ARStorage] = BEGIN Sink: PROC [source: NSDataStream.SourceStream] = BEGIN BEGIN ENABLE { NSDataStream.Aborted => CONTINUE; UNWIND => Stream.Delete[source]}; [] _ CopyAR[ session: session, from: source, to: to ! UNWIND => NSDataStream.Abort[ source ! NSDataStream.Aborted => CONTINUE]]; END; Stream.Delete[source ! NSDataStream.Aborted => CONTINUE] END; examineAR: PROC = { NSFile.Retrieve[arH.fH, [proc[Sink]], session.nsFileSession]; CloseFile[arH --@arH.fH--, session]; }; ValidateAR[arH, session]; CatchErrors[session, examineAR, examine] END; CheckOutAR: PUBLIC PROCEDURE [ session: Session, arH: ARHandle, to: ARAccess.ARStorage --Stream.Handle--] = { Sink: PROC [source: NSDataStream.SourceStream] = BEGIN BEGIN ENABLE { NSDataStream.Aborted => CONTINUE; UNWIND => Stream.Delete[source]}; [] _ CopyAR[ session: session, from: source, to: to ! UNWIND => NSDataStream.Abort[ source ! NSDataStream.Aborted => CONTINUE]]; END; Stream.Delete[source ! NSDataStream.Aborted => CONTINUE] END; checkOutAR: PROC = { attributesRecord: NSFile.AttributesRecord; selections: NSFile.Selections _ NSFile.Selections[ interpreted: [parentID: TRUE, name: TRUE]]; NSFile.ChangeControls[ file: arH.fH, session: session.nsFileSession, controlSelections: [lock: TRUE, access: TRUE], controls: [lock: exclusive, access: NSFile.fullAccess]]; NSFile.Retrieve[arH.fH, [proc[Sink]], session.nsFileSession]; NSFile.GetAttributes[ arH.fH, selections, @attributesRecord, session.nsFileSession]; arH.parentID _ attributesRecord.parentID; arH.name _ NSString.CopyString[ session.z, attributesRecord.name]; NSFile.ClearAttributes[@attributesRecord]; }; ValidateAR[arH, session]; CatchErrors[session, checkOutAR, checkout]; arH.checkedOut _ TRUE; }; CheckInAR: PUBLIC PROCEDURE [ session: Session, arH: ARHandle, from: Stream.Handle] = BEGIN Source: PROC [sink: NSDataStream.SinkStream] = BEGIN BEGIN ENABLE { UNWIND => Stream.Delete[sink]; NSDataStream.Aborted => CONTINUE}; [] _ CopyAR[ session: session, from: from, to: sink ! UNWIND => NSDataStream.Abort[sink! NSDataStream.Aborted => CONTINUE]] END; Stream.Delete[sink ! NSDataStream.Aborted => CONTINUE] END; checkInAR: PROC = { arAttr: ARRAY [0..2) OF NSFile.Attribute _ [ [name[arH.name]], [type[NSAssignedTypes.tText]]]; idAttr: ARRAY [0..1) OF NSFile.Attribute _ [ [fileID[arH.parentID]]]; fH, dH: NSFile.Handle _ NSFile.nullHandle; dH _ NSFile.Open[ attributes: DESCRIPTOR[idAttr], session: session.nsFileSession]; fH _ NSFile.Store[ -- stores new version directory: dH, source: [proc[Source]], attributes: DESCRIPTOR[arAttr], session: session.nsFileSession]; CloseFile[@dH, session]; CloseFile[@arH.fH, session]; CloseFile[@fH, session]; NSString.FreeString[session.z, arH.name]; }; ValidateAR[arH, session]; IF ~arH.checkedOut THEN ERROR Error[session, notCheckedOut]; CatchErrors[session, checkInAR, checkin]; arH.checkedOut _ FALSE; END; AbortCheckOut: PUBLIC PROCEDURE [session: Session, arH: ARHandle] = BEGIN ValidateSession[session]; ValidateAR[arH, session]; IF ~arH.checkedOut THEN ERROR Error[session, notCheckedOut]; CloseFile[@arH.fH, session]; KillProbingProcess[session]; NSString.FreeString[session.z, arH.name]; arH.name _ NSFile.nullString; arH.checkedOut _ FALSE; END; SubmitAR: PUBLIC PROCEDURE [ session: Session, arNumber: LONG CARDINAL, from: Stream.Handle] = BEGIN Source: PROC [sink: NSDataStream.SinkStream] = BEGIN BEGIN ENABLE { UNWIND => Stream.Delete[sink]; NSDataStream.Aborted => CONTINUE}; [] _ CopyAR[ session: session, from: from, to: sink ! UNWIND => NSDataStream.Abort[sink ! NSDataStream.Aborted => CONTINUE]] END; Stream.Delete[sink ! NSDataStream.Aborted => CONTINUE] END; submitAR: PROC = { fileName: Rope.ROPE _ [maxFileName]; fH, dH: NSFile.Handle _ NSFile.nullHandle; a: ARRAY [0..2) OF NSFile.Attribute _ [ [name[ARNumberToFileName[arNumber, fileName]]], [ type[NSAssignedTypes.tText]]]; dH _ OpenSubDirectory[session, arNumber]; fH _ NSFile.Store[ -- stores new version directory: dH, source: [proc[Source]], attributes: DESCRIPTOR[a], session: session.nsFileSession]; ** with current impl of OpenSubDirectory, for now don't close; CloseFile[@dH, session]; CloseFile[@fH, session]}; CatchErrors[session, submitAR, submit]; END; -- -- -- -- -- -- -- UTILITIES : -- -- -- -- -- -- -- Let the session stay open; If it times out, fine. Force client to close it explicitly; SELECT type FROM -- For checkouts, must keep file, hence session, open; checkout => Process.Detach[ session.probingProcess _ FORK KeepFileSessionOpen[session]]; checkin => KillProbingProcess[session]; ENDCASE; CatchErrors: PROCEDURE [session: Session, proc: PROC, type: CommandType] = BEGIN ENABLE { Let the session stay open; If it times out, fine. Force client to close it explicitly; NSFile.Error => NSError[session, error]; Courier.Error => ERROR Error[session, communicationError]}; ValidateSession[session]; IF CheckoutLost[session] THEN { SetSessionError[session, FALSE]; ERROR Error[session, crashDuringCheckOut]}; IF NOT FileSessionIsOpen[session] THEN OpenFileSession[session]; proc[]; SELECT type FROM -- For checkouts, must keep file, hence session, open; checkout => Process.Detach[ session.probingProcess _ FORK KeepFileSessionOpen[session]]; checkin => KillProbingProcess[session]; ENDCASE; END; CourierError: PROCEDURE [session: Session--, errorCode: Courier.ErrorCode--] = BEGIN SELECT errorCode FROM noCourierAtRemoteSite, remoteSystemElementNotResponding, noSuchProcedureNumber => ERROR Error[session, serverNotResponding]; ENDCASE => ERROR Error[session, communicationError]; END; NSError: PROC [session: Session, error: NSFile.ErrorRecord] = BEGIN WITH error SELECT FROM access => SELECT problem FROM accessRightsInsufficient => ERROR Error[session, accessDenied]; accessRightsIndeterminate => ERROR Error[session, accessUndetermined]; fileInUse => ERROR Error[session, currentlyCheckedOut]; fileNotFound => ERROR Error[session, arNotFound]; ENDCASE => ERROR Error[session, communicationError]; authentication => SELECT problem FROM credentialsInvalid, credentialsTooWeak, keysUnavailable, simpleKeyDoesNotExist, strongKeyDoesNotExist => ERROR Error[session, invalidLogin]; ENDCASE => ERROR Error[session, authError]; space => IF problem = allocationExceeded THEN ERROR Error[session, directoryFull] ELSE IF problem = mediumFull THEN ERROR Error[session, fileServerFull] ENDCASE => ERROR Error[session, communicationError]; END; Note: The NSFile session should never timeout during checkouts; it is kept open by the probing process; OpenFileSession: PROCEDURE [session: Session] = { attr: ARRAY [0..1) OF NSFile.Attribute _ [ [fileID[session.referenceToARs.fileID]]]; session.nsFileSession _ NSFile.LogonDirect[ identity: session.userId, service: session.referenceToARs.service]; session.dirH _ NSFile.Open[ attributes: DESCRIPTOR[attr], session: session.nsFileSession]}; CloseFileSession: PROCEDURE [session: Session] = { KillProbingProcess[session]; Process.Detach[FORK EndSession[session.nsFileSession]]; session.nsFileSession _ NSFile.nullSession}; EndSession: PROCEDURE [session: NSFile.Session] = { NSFile.Logoff[session ! NSFile.Error, Courier.Error => CONTINUE]}; closes session.dirH KillProbingProcess: PROCEDURE [session: Session] = { IF session.probingProcess # NIL THEN Process.Abort[session.probingProcess]}; KeepFileSessionOpen: PROCEDURE [session: Session] = BEGIN DO ENABLE ABORTED => EXIT; waitSeconds: CARDINAL _ NSFile.Probe[ session.nsFileSession ! NSFile.Error => WITH error SELECT FROM session => GOTO error ENDCASE; Courier.Error => GOTO error] / 2; Process.Pause[Process.SecondsToTicks[waitSeconds]] ENDLOOP; session.probingProcess _ NIL; EXITS error => SetSessionError[session, TRUE]; END; String.AppendLongNumber[temp, number]; String.AppendChar[name, '0] String.AppendString[name, temp]; String.AppendString[name, ".AR"L]; RETURN[NSString.StringFromMesaString[name]] ValidateSession: PROCEDURE [session: Session] = { IF session = NIL OR session.sessionPassword # SessionPassword THEN ERROR Error[session, invalidSession]}; ValidateAR: PROCEDURE [arH: ARHandle, session: Session] = { IF arH = NIL OR arH.password # ARPassword THEN ERROR Error[session, invalidARHandle]}; bufferPages: CARDINAL = 4; bufferBytes: CARDINAL = bufferPages * Environment.bytesPerPage; CopyAR: PROC [session: Session, from: ARHandle, to: ARAccess.ARStorage--Stream.Handle--] RETURNS [bytes: LONG CARDINAL] = { buffer: LONG POINTER = AssertBuffer[session]; bytes _ 0; DO bytesTransferred: CARDINAL; why: Stream.CompletionCode; savedSST: Stream.SubSequenceType; block: Stream.Block _ [buffer, 0, bufferBytes]; [bytesTransferred, why, savedSST] _ from.get[ from, block, Stream.defaultInputOptions ! Stream.EndOfStream => { why _ endOfStream; bytesTransferred _ nextIndex; CONTINUE}]; block.stopIndexPlusOne _ bytesTransferred; bytes _ bytes + bytesTransferred; to.put[to, block, FALSE]; IF why = endOfStream THEN EXIT; ENDLOOP; MSegment.Kill[session.buffer]}; AssertBuffer: PROC [session: Session] RETURNS [LONG POINTER] = { IF session.buffer = NIL THEN session.buffer _ MSegment.Create[ file: NIL, release: [], pages: bufferPages]; RETURN[MSegment.Address[session.buffer]]}; IF fH^ # NSFile.nullHandle THEN { NSFile.Close[ fH^, session.nsFileSession ! NSFile.Error, Courier.Error => CONTINUE]; fH^ _ NSFile.nullHandle} FileSessionIsOpen: PROCEDURE [session: Session] RETURNS [BOOLEAN] = { IF session.nsFileSession # NSFile.nullSession THEN [] _ NSFile.Probe[ session.nsFileSession ! NSFile.Error => BEGIN WITH error SELECT FROM session => IF problem = sessionInvalid THEN session.nsFileSession _ NSFile.nullSession ENDCASE; CONTINUE END; Courier.Error => CONTINUE]; RETURN[session.nsFileSession # NSFile.nullSession]}; SetSessionError: ENTRY PROCEDURE [ session: Session, value: BOOLEAN] = { session.sessionError _ value; session.probingProcess _ NIL}; CheckoutLost: ENTRY PROCEDURE [session: Session] RETURNS [BOOLEAN] = {RETURN[session.sessionError]}; EmptySubString: PROC [s: NSString.SubString] RETURNS [BOOLEAN] = INLINE {RETURN[s.length = 0]}; FindSubDirectory[xxx]; ** i.e. Map name to subdirectory ** Κ •NewlineDelimiter –(cedarcode) style™šœ ΟeœD™OJšœ$™$Jšœ™Jšœ™Jšœ™Jšœ™Jšœ™Jšœ(™(—Icode˜K˜šΟk ˜ Kšœžœ˜Kšœ žœ˜ Kšœ žœ#˜1Jšœžœ.™8Kšœžœ˜Jšœžœ™!Jšœ žœ™(Kšžœžœ$žœ˜6Jšœ žœ!™/Jšœžœ ™šœ žœ™J™:—šœžœ™J™=Jšœ>žœ™AJ™AJ™9J™;—Jšœžœ%™1šœ žœ™J™A—Kšžœžœ9žœ$˜jJšœžœ1™>Kšœ:˜:Kšœžœ$žœ˜:šœžœ™J™@J™—Jšœžœ.™:—K˜šΟn œžœžœΟc&˜Bšžœžœž˜0K˜BK˜—Kšžœ ˜Kšžœžœ ˜—˜Jšœ™Jšœ™Jšœ™—˜Kšœ žœ˜(Jšœ žœžœ™"š œžœžœž œžœ™/Jšœžœ™,Jšœž œžœžœ™J™3™$Jšœ žœ™%—J™(Jšœžœ™"Jšœžœ™Jšœžœžœ™Jšœžœžœ™——˜Kšœ žœžœ ˜šœ žœžœžœ˜ Kšœ žœ˜ Jšœžœ™$Kšœžœ žœ œ ˜Kšœžœ œ˜;—˜Jšœ™Jšœ™Jšœ™—˜KšŸœžœžœ&žœ˜>—˜šŸœžœž œ™Jšœž œžœ™3Jšžœ™Jšž™šœ žœ™J™J™J™J™Jšœ žœ™ J™J™5—™J™*J™3—Jšžœ™——˜šŸœžœž œ™.Jšž™Jšœž œžœ™J™Jšœ 0™@šžœžœž™J™>—šžœ"žœžœ™.J™:Jšœžœ#™)—Jšœžœ ™Jšžœ™——™šŸœžœž œ™J™.Jšž™J™šžœžœž™J™>—J™AJšžœ™——™šŸœžœž œ™-Jšž™J™šžœ,ž™2šžœžœž™$Jšžœ$™)—Jšžœ™—Jšžœ™——˜šŸœžœž œžœ˜>Kšžœ˜Jšœ0™0Kšž˜šœžœ˜šœžœ ˜K˜>—K˜—K˜!Kšžœ˜ Kšžœ˜——˜šŸœž œ˜Kšœžœ˜%Kšžœžœ  œ˜0Kšœžœžœ ˜-Kšœžœžœ'˜3šœžœ˜Kšœžœ1˜:—™J™>J™J™ J™'J™(—Jšœ>™>Kš œ˜ ——˜šŸœžœž œ"˜:Kšžœ˜J™J™Kšžœžœžœ%˜AKšœ   œ ˜#Jšœ žœ™Kšžœžœ˜ Kšœ˜——˜šŸ œžœž œ#žœ˜bšŸœžœ˜!šžœ˜Kšžœžœ˜—Kšœ-žœžœ˜LK˜K˜—šœ žœ˜K˜ K˜K˜K˜—K˜(K˜—K˜šŸ œžœž œ<™WJšž™šŸœžœ&™0Jšž™Jšž™šžœ™Jšœžœ™!Jšžœ™!—™ J™(šžœ™ ™Jšœ!žœ™,J™———Jšžœ™Jšœ/žœ™8Jšžœ™—šœ žœ™J™=Jšœ  œ ™$J™—J™J™(Jšžœ™——˜šŸ œžœž œ™Jšœ8 œ™NšŸœžœ&™0Jšž™Jšž™šžœ™Jšœžœ™!Jšžœ™!—™ J™(šžœ™ ™Jšœ!žœ™,———Jšžœ™Jšœ/žœ™8Jšžœ™—šœ žœ™J™*™2Jšœžœžœ™+—™J™-Jšœžœ žœ™.J™8—J™=™J™>—J™)™J™"—J™*J™—J™J™+Jšœžœ™Jšœ™——˜šŸ œžœž œ™J™7Jšž™šŸœžœ"™.Jšž™Jšž™šžœ™Jšžœ™Jšœžœ™"—™ J™(Jšžœ5žœ™E—Jšžœ™Jšœ-žœ™6Jšžœ™—šœ žœ™šœžœžœ™,J™1—šœžœžœ™,J™—J™*™Jšœ ž œ ™J™ —šœ ™)J™&Jšœ ž œ ™J™ —J™J™J™J™)J™—J™Jšžœžœžœ™™>Jšœ™J™—J™'Jšžœ™——˜Jšœ™Jšœ ™ Jšœ™—˜šŸ œž œžœ˜JKšž˜šžœ˜JšœV™VKšžœ#˜&Kšžœ žœ#˜4Kšœ˜—K˜šžœžœ 6™H™ ™Jšœžœ™<——J™'Jšžœ™—Kšžœ˜K˜—šŸ œž œžœ™JJšž™šžœ™JšœV™VJ™(Jšœžœ%™;—J™šžœžœ™Jšœžœ™ Jšžœ&™+—Jšžœžœžœ™@J™šžœžœ 6™H™ ™Jšœžœ™<——J™'Jšžœ™—Jšžœ™——˜šŸ œž œ  )œ™NJšž™šžœ ž™™8J™Jšžœ%™*—Jšžœžœ$™4—Jšžœ™——˜šŸœžœ0™=Jšž™šžœžœž™™ šžœ ž™™Jšžœ™#—™Jšžœ$™)—Jšœ žœ%™7Jšœžœ™1Jšžœžœ$™4——™šžœ ž™™8J™/Jšžœ™#—Jšžœžœ™+——™šžœž™$Jšžœ™#—šž™šžœž™Jšžœ™$———Jšžœžœ$™4—Jšžœ™—K˜šŸœžœ+˜9Kšž˜šžœ ž˜˜šžœ ž˜Kšœžœ˜/Kšžœžœ˜)——šœ˜šžœ ž˜Kšœžœ˜4Kšœžœ˜6Kšœ.˜.Kšžœžœ˜+——šœ ˜ šžœ ž˜Kšœžœ˜/Kšžœžœ˜)——šœ˜Kšžœ ž˜Kšœ6˜6Kšžœžœ$˜4—Kšžœžœ$˜4—Kšžœ˜——˜Jšœi™išŸœž œ  œ™1šœžœžœ™*J™)—™+J™J™)—™Jšœ ž œ)™?———˜šŸœž œ  œ™2J™Jšœžœ$™7J™,——˜šŸ œž œ™3Jšœ7žœ™B—Jšœ™—˜šŸœž œ™4šžœžœž™$J™'———˜šŸœž œ™3Jšž™šž™Jšžœžœžœ™šœ žœ™™ J™™Jš žœžœžœ žœžœ™5—Jšœžœ ™!——J™2Jšžœ™—Jšœžœ™Jšžœ#žœ™.Jšžœ™——˜šŸœž œ ž œ˜EKšžœžœžœ˜Kšœ žœžœ ˜'Kšœ4žœ˜