DIRECTORY BasicTime USING [GMT, Now, nullGMT, Period], Convert USING [RopeFromInt], DFInternal USING [AbortDF, CheckAbort, Client, ClientDescriptor, DefaultInteractionProc, DoAbort, GetFileInfo, LocalFileInfo, RemoteFileInfo, ReportFSError, ShortName, SimpleInteraction, YesOrNo], DFOperations USING [AbortInteraction, DFInfoInteraction, FileAction, FileInteraction, InfoInteraction, InteractionProc, SModelAction], DFUtilities USING [Date, DateFormat, DateToRope, DirectoryItem, FileItem, Filter, GetVersionNumber, ImportsItem, IncludeItem, ParseFromStream, ProcessItemProc, RemoveVersionNumber, SyntaxError, WriteItemToStream], FS USING [Copy, Create, Delete, Error, ExpandName, FileInfo, GetInfo, GetName, OpenFile, OpenFileFromStream, StreamFromOpenFile, StreamOpen], IO USING [Close, GetIndex, PutFLR, PutFR, PutFR1, STREAM], Rope USING [Cat, Concat, Equal, Index, Length, ROPE, Run, Substr]; SModelImpl: CEDAR MONITOR IMPORTS BasicTime, Convert, DFInternal, DFUtilities, FS, IO, Rope EXPORTS DFOperations = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; checkImports: BOOL ¬ FALSE; tempDF: ROPE = Rope.Cat["SModelTemporaryDF-", Convert.RopeFromInt[from: LOOPHOLE[BasicTime.Now[]]], "-"]; nSModels: NAT ¬ 0; SModel: PUBLIC PROC [dfFile: ROPE, action: DFOperations.SModelAction, interact: DFOperations.InteractionProc, clientData: REF, log: STREAM, workingDir: ROPE] RETURNS [errors, warnings, filesActedUpon: INT ¬ 0] = { client: DFInternal.Client = NEW[DFInternal.ClientDescriptor ¬ [ (interact ¬ IF interact = NIL THEN DFInternal.DefaultInteractionProc ELSE interact), clientData, log, log, workingDir ]]; NewTemporaryDF: ENTRY PROC [pages: INT] RETURNS [out: STREAM] = { ENABLE UNWIND => NULL; filename: ROPE ~ tempDF.Concat[Convert.RopeFromInt[nSModels]]; outFile: FS.OpenFile ~ FS.Create[ name: filename, pages: pages, setKeep: TRUE, keep: CARDINAL.LAST ! FS.Error => { localInfo: REF DFInternal.LocalFileInfo ¬ NEW[DFInternal.LocalFileInfo ¬ [name: filename]]; DFInternal.ReportFSError[error, localInfo, client, $abort]; } ]; nSModels ¬ nSModels.SUCC; RETURN[FS.StreamFromOpenFile[outFile, $write]] }; CloseTemporaryDF: PROC [out: STREAM] RETURNS [tempName: ROPE] = { outFile: FS.OpenFile = FS.OpenFileFromStream[out]; tempName ¬ outFile.GetName[].fullFName; -- includes version number out.Close[]; }; FinishWithTemporaryDF: ENTRY PROC [tempName: ROPE, localName: ROPE, commit: BOOL ¬ TRUE] = { ENABLE UNWIND => NULL; FS.Delete[tempName]; }; UserConfirms: PROC [localInfo: REF DFInternal.LocalFileInfo, remoteInfo: REF DFInternal.RemoteFileInfo] RETURNS [BOOL] = { RETURN[DFInternal.YesOrNo[ client: client, message: IO.PutFR[ "%g {%g} to %g ?", [rope[localInfo.name]], [rope[DFUtilities.DateToRope[localInfo.date]]], [rope[DFUtilities.RemoveVersionNumber[remoteInfo.name]]] ], default: TRUE ]] }; SModelInner: PROC [dfFile: ROPE, date: DFUtilities.Date] RETURNS [REF DFInternal.RemoteFileInfo ¬ NIL] = { directoryPath: ROPE ¬ NIL; writeDirectoryPath: ROPE ¬ NIL; directoryLen: INT ¬ 0; somethingChanged: BOOL ¬ FALSE; dfRemoteInfo: REF DFInternal.RemoteFileInfo = NEW[DFInternal.RemoteFileInfo ¬ [name: dfFile, date: date]]; dfLocalInfo: REF DFInternal.LocalFileInfo = NEW[DFInternal.LocalFileInfo ¬ [name: DFInternal.ShortName[dfFile]]]; DoOneItem: DFUtilities.ProcessItemProc = { StoreThisFile: PROC [ localInfo: REF DFInternal.LocalFileInfo, remoteInfo: REF DFInternal.RemoteFileInfo, formatFromDF: DFUtilities.DateFormat] RETURNS [store: BOOL ¬ FALSE] = { lGMT: BasicTime.GMT = localInfo.date.gmt; -- can't be nullGMT rGMT: BasicTime.GMT = remoteInfo.date.gmt; -- may be nullGMT attachmentsArePossible: BOOL = FALSE; IF attachmentsArePossible THEN { -- Disable this until we have attachments in PCedar - MFP IF localInfo.attachedTo.Length[] = 0 THEN RETURN[TRUE]; IF ~Rope.Equal[ DFUtilities.RemoveVersionNumber[remoteInfo.name], DFUtilities.RemoveVersionNumber[localInfo.attachedTo], FALSE] THEN { IF remoteInfo.date = localInfo.date AND Rope.Equal[ DFInternal.ShortName[remoteInfo.name], DFInternal.ShortName[localInfo.attachedTo], FALSE] THEN { [] ¬ FS.Copy[ to: DFUtilities.RemoveVersionNumber[localInfo.name], from: remoteInfo.name, wantedCreatedTime: remoteInfo.date.gmt, remoteCheck: action.remoteCheck, attach: TRUE ! FS.Error => GO TO storeAnyway ]; localInfo.date.format ¬ $omitted; DFInternal.GetFileInfo[info: localInfo, remoteCheck: FALSE, client: client ! FS.Error => DFInternal.ReportFSError[error, localInfo, client, $abort] ]; RETURN[FALSE]; EXITS storeAnyway => NULL; }; RETURN[TRUE] }; }; SELECT formatFromDF FROM $explicit, $omitted => RETURN[lGMT ~= rGMT]; $notEqual => RETURN[action.remoteCheck AND lGMT ~= rGMT]; $greaterThan => SELECT TRUE FROM ~action.remoteCheck => RETURN[FALSE]; remoteInfo.date.format ~= $explicit => RETURN[TRUE]; -- no extant remote file ENDCASE => SELECT BasicTime.Period[from: lGMT, to: rGMT] FROM < 0 => RETURN[TRUE]; = 0 => RETURN[FALSE]; > 0 => { warnings ¬ warnings.SUCC; DFInternal.SimpleInteraction[ client, NEW[DFOperations.InfoInteraction ¬ [ class: $warning, message: IO.PutFLR["%g {%g} is referenced with '>' in the DF file but is older than the remote version %g {%g}.", LIST[ [rope[localInfo.name]], [rope[DFUtilities.DateToRope[localInfo.date]]], [rope[remoteInfo.name]], [rope[DFUtilities.DateToRope[remoteInfo.date]]] ]] ]] ]; RETURN[FALSE] }; ENDCASE; ENDCASE; }; ReportMissing: PROC [localInfo: REF DFInternal.LocalFileInfo] = { warnings ¬ warnings.SUCC; DFInternal.SimpleInteraction[ client, NEW[DFOperations.InfoInteraction ¬ [ class: $warning, message: IO.PutFR1["'%g' doesn't exist.", [rope[localInfo.name]]] ]] ]; }; SelfReference: PROC [shortName: ROPE] RETURNS [BOOL] = { RETURN[shortName.Equal[dfLocalInfo.name, FALSE]] }; DFInternal.CheckAbort[client]; WITH item SELECT FROM directory: REF DFUtilities.DirectoryItem => IF directory.readOnly THEN writeDirectoryPath ¬ NIL ELSE { directoryPath ¬ directory.path1 ¬ FS.ExpandName[directory.path1].fullFName; directoryLen ¬ Rope.Length[directoryPath]; writeDirectoryPath ¬ TranslateHost[directoryPath]; }; file: REF DFUtilities.FileItem => IF writeDirectoryPath # NIL THEN { shortName: ROPE = DFUtilities.RemoveVersionNumber[file.name]; localInfo: REF DFInternal.LocalFileInfo ¬ NEW[DFInternal.LocalFileInfo ¬ [shortName]]; remoteInfo: REF DFInternal.RemoteFileInfo ¬ NEW[DFInternal.RemoteFileInfo ¬ [ name: directoryPath.Concat[file.name], date: file.date ]]; knownRemoteVersion: ROPE ¬ NIL; DFInternal.GetFileInfo[info: localInfo, remoteCheck: FALSE, client: client ! FS.Error => IF error.group = $user THEN {ReportMissing[localInfo]; GO TO skip} ELSE DFInternal.ReportFSError[error, localInfo, client, $abort] ]; IF action.remoteCheck THEN { CheckWriteInfo[Rope.Concat[writeDirectoryPath, shortName], localInfo, remoteInfo ! FS.Error => DFInternal.ReportFSError[error, remoteInfo, client, $abort]; ]; }; knownRemoteVersion ¬ DFUtilities.GetVersionNumber[remoteInfo.name]; remoteInfo.name ¬ DFUtilities.RemoveVersionNumber[remoteInfo.name]; SELECT TRUE FROM SelfReference[shortName] => { remoteDFInfo: REF DFInternal.RemoteFileInfo = NEW[DFInternal.RemoteFileInfo ¬ [name: remoteInfo.name]]; CheckWriteInfo[TranslateHost[remoteDFInfo.name], localInfo, remoteDFInfo ! FS.Error => DFInternal.ReportFSError[error, remoteDFInfo, client, $abort]; ]; IF remoteDFInfo.date.gmt ~= BasicTime.nullGMT AND file.date.format = $explicit AND BasicTime.Period[from: file.date.gmt, to: remoteDFInfo.date.gmt] > 0 AND ~DFInternal.YesOrNo[ client: client, message: IO.PutFLR[ "%g may be obsolete, since the remote version from which it is derived {%g} is older than %g {%g} (the present newest remote one); continue anyway?", LIST[ [rope[shortName]], [rope[DFUtilities.DateToRope[file.date]]], [rope[remoteDFInfo.name]], [rope[DFUtilities.DateToRope[remoteDFInfo.date]]] ]], default: FALSE, blunder: TRUE ] THEN DFInternal.DoAbort[client.log, "Obsolete self-reference; remote version is newer than date in DF file."]; IF StoreThisFile[localInfo, remoteInfo, file.date.format] THEN somethingChanged ¬ TRUE; -- we'll actually store it later, if user approves. dfRemoteInfo.name ¬ remoteInfo.name; -- redundant unless top-level DF file.name ¬ shortName; -- ensure no version number SELECT file.date.format FROM $explicit, $omitted => file.date ¬ [$explicit, outFile.GetInfo[].created]; ENDCASE; }; StoreThisFile[localInfo, remoteInfo, file.date.format] AND UserConfirms[localInfo, remoteInfo] => { somethingChanged ¬ TRUE; IF action.storeChanged THEN { DFInternal.SimpleInteraction[ client, NEW[DFOperations.FileInteraction ¬ [ localFile: localInfo.name, remoteFile: remoteInfo.name, dateFormat: SELECT file.date.format FROM $explicit => $explicit, $greaterThan => $greaterThan, ENDCASE => $notEqual, date: localInfo.date.gmt, action: store ]] ]; file.name ¬ FS.Copy[ to: remoteInfo.name, from: localInfo.name, attach: FALSE ! FS.Error => DFInternal.ReportFSError[error, remoteInfo, client, $abort]]; localInfo.name ¬ Rope.Substr[localInfo.name, 0, Rope.Index[localInfo.name, 0, "!"]]; -- remove any version info IF makeAttachment THEN [] ¬ FS.Copy[ to: localInfo.name, from: file.name, attach: TRUE ! FS.Error => DFInternal.ReportFSError[error, remoteInfo, client, $abort]]; IF Rope.Run[file.name, 0, directoryPath, 0, FALSE] = directoryLen THEN { file.name ¬ Rope.Substr[file.name, directoryLen]; } ELSE { DFInternal.DoAbort[client.log, IO.PutFR1["Bogus file name (%g).", [rope[file.name]] ]]; }; }; filesActedUpon ¬ filesActedUpon.SUCC; SELECT file.date.format FROM $explicit, $omitted => file.date ¬ localInfo.date; ENDCASE => file.name ¬ shortName; }; ENDCASE => { remoteVersion: ROPE = knownRemoteVersion; IF NOT remoteVersion.Equal[DFUtilities.GetVersionNumber[file.name]] THEN { file.name ¬ shortName.Concat[remoteVersion]; somethingChanged ¬ TRUE; }; SELECT file.date.format FROM $omitted => { file.date ¬ localInfo.date; somethingChanged ¬ TRUE; }; $explicit => IF file.date ~= localInfo.date THEN { file.date ¬ localInfo.date; somethingChanged ¬ TRUE; }; ENDCASE; }; EXITS skip => NULL; }; include: REF DFUtilities.IncludeItem => { path: ROPE ¬ include.path1 ¬ FS.ExpandName[include.path1].fullFName; remoteInfo: REF DFInternal.RemoteFileInfo = SModelInner[path, include.date]; IF ~Rope.Equal[remoteInfo.name, path, FALSE] THEN { include.path1 ¬ remoteInfo.name; somethingChanged ¬ TRUE}; SELECT include.date.format FROM $explicit, $omitted => { include.date ¬ remoteInfo.date; somethingChanged ¬ TRUE}; ENDCASE => include.path1 ¬ DFUtilities.RemoveVersionNumber[include.path1]; }; imports: REF DFUtilities.ImportsItem => IF checkImports THEN { localInfo: REF DFInternal.LocalFileInfo = NEW[DFInternal.LocalFileInfo ¬ [name: DFInternal.ShortName[imports.path1]]]; remoteInfo: REF DFInternal.RemoteFileInfo = NEW[DFInternal.RemoteFileInfo ¬ [name: imports.path1, date: imports.date]]; DFInternal.GetFileInfo[info: localInfo, remoteCheck: FALSE, client: client ! FS.Error => IF error.group = $user THEN {ReportMissing[localInfo]; GO TO skip} ELSE DFInternal.ReportFSError[error, localInfo, client, $abort] ]; SELECT TRUE FROM localInfo.date.gmt = BasicTime.nullGMT => { warnings ¬ warnings.SUCC; DFInternal.SimpleInteraction[ client, NEW[DFOperations.InfoInteraction ¬ [ class: $warning, message: IO.PutFR1["Local import %g not found.", [rope[localInfo.name]] ] ]] ]; }; imports.date.format = $explicit AND imports.date.gmt # localInfo.date.gmt => { warnings ¬ warnings.SUCC; DFInternal.SimpleInteraction[ client, NEW[DFOperations.InfoInteraction ¬ [ class: $warning, message: IO.PutFR["Local import %g does not have requested date.", [rope[localInfo.name]], [rope[DFUtilities.DateToRope[localInfo.date]]] ] ]] ]; }; ENDCASE; IF action.remoteCheck THEN { CheckWriteInfo[remoteInfo.name, localInfo, remoteInfo ! FS.Error => DFInternal.ReportFSError[error, remoteInfo, client, $abort]; ]; IF localInfo.date.gmt # remoteInfo.date.gmt THEN { warnings ¬ warnings.SUCC; DFInternal.SimpleInteraction[ client, NEW[DFOperations.InfoInteraction ¬ [ class: $warning, message: IO.PutFLR["%g {%g} doesn't correspond to %g {%g}.", LIST[ [rope[localInfo.name]], [rope[DFUtilities.DateToRope[localInfo.date]]], [rope[remoteInfo.name]], [rope[DFUtilities.DateToRope[remoteInfo.date]]]] ] ]] ]; }; IF imports.date.format = explicit THEN somethingChanged ¬ NOT Rope.Equal[imports.path1, remoteInfo.name, FALSE]; imports.path1 ¬ remoteInfo.name; }; SELECT imports.date.format FROM $explicit => NULL; $omitted => {imports.date ¬ localInfo.date; somethingChanged ¬ TRUE}; ENDCASE => imports.path1 ¬ DFUtilities.RemoveVersionNumber[imports.path1]; EXITS skip => NULL; }; ENDCASE; DFUtilities.WriteItemToStream[out, item]; }; in: STREAM = FS.StreamOpen[ fileName: dfLocalInfo.name, accessOptions: $read, wDir: client.workingDir ! FS.Error => DFInternal.ReportFSError[error, dfLocalInfo, client, $abort] ]; inFile: FS.OpenFile = FS.OpenFileFromStream[in]; out: STREAM = NewTemporaryDF[inFile.GetInfo[].pages]; outFile: FS.OpenFile = FS.OpenFileFromStream[out]; makeAttachment: BOOL ~ WITH clientData SELECT FROM refBool: REF BOOL => refBool­ ENDCASE => TRUE; dfLocalInfo.date ¬ [$explicit, inFile.GetInfo[].created]; DFInternal.SimpleInteraction[ client, NEW[DFOperations.DFInfoInteraction ¬ [action: start, dfFile: dfLocalInfo.name]] ]; DFUtilities.ParseFromStream[in, DoOneItem, DFUtilities.Filter[comments: TRUE] ! DFUtilities.SyntaxError -- [reason: ROPE]-- => DFInternal.DoAbort[ log, IO.PutFR["Syntax error in '%g'[%d]: %g", [rope[dfLocalInfo.name]], [cardinal[in.GetIndex[]]], [rope[reason]] ], interact, clientData ]; DFInternal.AbortDF => { in.Close[]; FinishWithTemporaryDF[CloseTemporaryDF[out], NIL, FALSE]; }; ]; in.Close[]; dfLocalInfo.date.gmt ¬ outFile.GetInfo[].created; IF somethingChanged AND UserConfirms[dfLocalInfo, dfRemoteInfo] THEN { tempName: ROPE = CloseTemporaryDF[out]; remoteDFName: ROPE; dfRemoteDateFormat: DFUtilities.DateFormat = dfRemoteInfo.date.format; dfRemoteInfo.date ¬ dfLocalInfo.date; IF action.storeChanged THEN { DFInternal.SimpleInteraction[ client, NEW[DFOperations.FileInteraction ¬ [ localFile: dfLocalInfo.name, remoteFile: dfRemoteInfo.name, dateFormat: SELECT dfRemoteDateFormat FROM $explicit => $explicit, $greaterThan => $greaterThan, ENDCASE => $notEqual, date: dfLocalInfo.date.gmt, action: $store ]] ]; remoteDFName ¬ FS.Copy[to: dfRemoteInfo.name, from: tempName, attach: FALSE ! FS.Error => DFInternal.ReportFSError[error, dfRemoteInfo, client, $abort]]; [] ¬ FS.Copy[to: dfLocalInfo.name, from: remoteDFName, attach: makeAttachment ! FS.Error => DFInternal.ReportFSError[error, dfRemoteInfo, client, $abort]]; FinishWithTemporaryDF[tempName, dfLocalInfo.name]; }; filesActedUpon ¬ filesActedUpon.SUCC; } ELSE FinishWithTemporaryDF[CloseTemporaryDF[out], NIL, FALSE]; DFInternal.SimpleInteraction[ client, NEW[DFOperations.DFInfoInteraction ¬ [ action: end, dfFile: dfLocalInfo.name, message: IF somethingChanged THEN NIL ELSE "DF file is unchanged" ]] ]; RETURN[dfRemoteInfo] }; [] ¬ SModelInner[dfFile, [] ! ABORTED => { DFInternal.SimpleInteraction[client, NEW[DFOperations.AbortInteraction ¬ [TRUE]]]; }; DFInternal.AbortDF => { errors ¬ errors.SUCC; DFInternal.SimpleInteraction[client, NEW[DFOperations.DFInfoInteraction ¬ [action: $abort, dfFile: dfFile]]]; CONTINUE }; ]; }; CheckWriteInfo: PROC [path: ROPE, localInfo: REF DFInternal.LocalFileInfo, remoteInfo: REF DFInternal.RemoteFileInfo] = { wantedCreatedTime: BasicTime.GMT ~ localInfo.date.gmt; fullFName: ROPE ¬ NIL; created: BasicTime.GMT ¬ BasicTime.nullGMT; [fullFName: fullFName, created: created] ¬ FS.FileInfo[DFUtilities.RemoveVersionNumber[path] ! FS.Error => SELECT error.code FROM $unknownCreatedTime, $unknownFile => { GOTO NotFound}; ENDCASE; ]; remoteInfo.name ¬ fullFName; remoteInfo.date ¬ [$explicit, created]; RETURN; EXITS NotFound => remoteInfo.date ¬ [$omitted, BasicTime.nullGMT]}; TranslateHost: PROC [path: ROPE] RETURNS [ROPE] = { < SELECT error.code FROM $unknownCreatedTime, $unknownFile => { File not found, so just continue with updated info remoteInfo.date.gmt _ BasicTime.nullGMT; remoteInfo.date.format _ $omitted; CONTINUE; }; ENDCASE; ]; }; Eduardo Pelegri-Llopart March 2, 1989 10:49:25 am PST Changes to: NewTemporaryDF (local of SModel) and, FinishWithTemporaryDF (local of SModel) to deal with (obviously unfrequent) FS errors. Michael Plass, December 1, 1989 11:18:03 am PST Dummied out TranslateHost; under PFS, there is currently only one host. Michael Plass, January 2, 1990 1:32:48 pm PST Changed NewTemporaryDF to generate really unique names. Made version-number fixups happen even when attachements are not implemented. Κ•NewlineDelimiter –(cedarcode) style™codešœ™Kšœ ΟeœO™ZKšœ*™*K™/K™'K™,K™5K™,K™"K™%K™*K˜šΟk ˜ Kšœ žœžœ˜,Kšœžœ˜Kšœ žœ–žœ˜ΔKšœ žœt˜†Kšœ žœΔ˜ΥKšžœžœ…˜Kšžœžœ*žœ˜:Kšœžœ%žœœ˜B——headšœ žœž˜Kšžœ.žœžœ˜AKšžœž˜—˜Kšžœžœžœ˜Kšžœžœžœžœ˜—K™™K™šœžœžœ˜K™—K˜—šœ™K™Kšœžœ<žœ˜iKšœ žœ˜K˜—Kšœ™K˜šΟnœžœžœ žœYžœžœžœžœ$žœ ˜Υšœžœ ˜?Kš œ žœ žœžœ#žœ ˜TKšœ ˜ K˜ Kšœ ˜ Kšœ˜—š Ÿœžœžœ žœžœžœ˜AKšžœžœžœ˜Kšœ žœ0˜>šœ žœ ˜šžœ˜ Kšœ˜Kšœ žœžœž˜"šœžœ ˜Kšœ žœžœ.˜[Kšœ;˜;K˜——K˜—Kšœžœ˜Kšžœžœ%˜.Kšœ˜—š Ÿœžœžœžœ žœ˜AKšœ žœ žœ˜2Kšœ)Οc˜CK˜ Kšœ˜—šŸœžœžœ žœ žœ žœžœ˜\Kšžœžœžœ˜Kšžœ˜Kšœ˜—š Ÿ œžœ žœ'žœžœžœ˜zšžœ˜Kšœ˜šœ ˜ šžœ˜ Kšœ˜Kšœ˜Kšœ/˜/Kšœ8˜8Kšœ˜——Kšœ ž˜ Kšœ˜—K˜—š Ÿ œžœ žœžœžœžœ˜jKšœžœžœ˜Kšœžœžœ˜Kšœžœ˜Kšœžœžœ˜Kšœžœžœ9˜jKšœ žœžœB˜qšŸ œ!˜*šŸ œžœžœ'žœBžœ žœžœ˜±Kšœžœ•™°Kšœžœ ˜>Kšœžœ ˜=Kšœžœžœ˜%šžœžœ 9˜ZKšœ[™[Kšžœ#žœžœžœ˜7Kšœ`žœR™΄šžœ ˜Kšœ1˜1Kšœ6˜6šžœžœ˜ Kšœδ™δšžœ"žœ ˜3Kšœ&˜&Kšœ+˜+šžœžœ˜ šœžœ˜ Kšœ4˜4Kšœ˜Kšœ'˜'Kšœ ˜ Kšœž˜ Kšœžœ žœžœ ˜Kšœ˜—šœ!˜!KšœH™H—šœ5žœ˜JKšœ™KšœžœD˜HK˜—Kšžœžœ˜šž˜Kšœžœ˜—K˜——Kšžœžœ˜ K˜——Kšœ˜—Kšœ€žœΖ™Θšžœž˜Kšœžœ˜,Kšœ žœžœ˜9šœ˜šžœžœž˜Kšœžœžœ˜%Kšœ'žœžœ ˜Nšžœ˜ šžœ(ž˜2Kšœžœžœ˜Kšœžœžœ˜šœ˜Kšœžœ˜šœ˜Kšœ˜šžœ!˜$K˜šœ žœgžœ˜wKšœ˜Kšœ/˜/Kšœ˜Kšœ/˜/K˜—K˜—Kšœ˜—Kšžœžœ˜ K˜—Kšžœ˜————Kšžœ˜—K˜—šŸ œžœ žœ˜AKšœžœ˜šœ˜Kšœ˜šžœ!˜$K˜Kšœ žœ6˜AK˜—Kšœ˜—K˜—š Ÿ œžœ žœžœžœ˜8Kšžœ#žœ˜1K˜—Kšœ˜šžœžœžœ˜šœ žœ˜+Kšœ)™)šžœžœž˜3šžœ˜Kšœ"žœ'˜KKšœ*˜*Kšœ2˜2K˜———š œžœžœžœžœ˜DKšœ žœ.˜=Kšœ žœžœ)˜Všœ žœ˜+šžœ˜!Kšœ&˜&Kšœ˜Kšœ˜——Kšœžœžœ˜šœ5žœ žœ˜Jšœžœ ˜ Kšžœžœžœžœ˜BKšžœ;˜?—Kšœ˜—šžœžœ˜KšœΪ™ΪšœP˜PKšœžœF˜JKšœ˜—K˜—KšœC˜CKšœC˜CKšœ«™«šžœžœž˜šœ˜Kšœ%žœvžœJžœ™ρšœžœ˜-Kšžœ6˜9—šœH˜HKšœžœH˜LKšœ˜—šžœ,ž˜1Kšœž˜ KšœEž˜Hšœ˜Kšœ˜šœ ˜ šžœ˜ Kšœ–žœ˜›Kšœ˜Kšœ*˜*Kšœ˜Kšœ1˜1Kšœ˜——Kšœ žœ˜Kšœ ž˜ Kšœžœj˜p——šžœ8ž˜>Kšœžœ 3˜M—Kšœ&  ˜FKšœ ˜3šžœž˜KšœJ˜JKšžœ˜—K˜—šœ7žœ)˜cKšœžœ˜šžœžœ˜šœ˜K˜šžœ!˜$Kšœ˜Kšœ˜šœ ˜ šžœž˜Kšœ˜Kšœ˜Kšžœ˜——Kšœ˜K˜ Kšœ˜—K˜—šœ žœ˜Kšœ3ž˜8KšœžœG˜K—KšœU ˜ošžœžœžœ˜$Kšœ-ž˜1KšœžœG˜K—šžœ*žœ˜Ašžœ˜Kšœ™Kšœ1˜1K˜—šžœ˜Kšœžœ6˜WKšœ˜——K˜—Kšœ žœ˜%šžœž˜Kšœ2˜2Kšžœ˜!—K˜—šžœ˜ KšœΡžœ™ΨKšœžœ˜)šžœžœ>žœ˜JKšœ,˜,Kšœžœ˜K˜—šžœž˜šœ ˜ Kšœ˜Kšœžœ˜Kšœ˜—šœ ˜ šžœžœ˜%Kšœ˜Kšœžœ˜Kšœ˜——Kšžœ˜—Kšœ˜——šž˜Kšœžœ˜ —K˜—šœ žœ˜)Kšœžœžœ%˜DKšœ žœ=˜Lšžœ$žœžœ˜3Kšœ ˜ Kšœžœ˜—šžœž˜šœ˜Kšœ˜Kšœžœ˜—KšžœC˜J—Kšœ˜—šœ žœžœžœ˜>šœ žœ˜)KšžœI˜L—šœ žœ˜+KšžœH˜K—šœ5žœ˜Jšœžœ ˜ Kšžœžœžœžœ˜BKšžœ;˜?—Kšœ˜—šžœžœž˜šœ+˜+Kšœžœ˜šœ˜Kšœ˜šžœ!˜$K˜šœ žœ%˜0Kšœ˜K˜—K˜—Kšœ˜—K˜—šœ žœ+˜NKšœžœ˜šœ˜Kšœ˜šžœ!˜$K˜šœ žœ7˜BKšœF˜FK˜—K˜—Kšœ˜—K˜—Kšžœ˜—šžœžœ˜šœ5˜5KšœžœF˜JKšœ˜—šžœ*žœ˜2Kšœžœ˜šœ˜Kšœ˜šžœ!˜$K˜šœ žœ2žœ˜BKšœG˜GKšœI˜IK˜—K˜—Kšœ˜—K˜—Kšžœ žœžœ,žœ˜pK˜ K˜—šžœž˜Kšœ žœ˜Kšœ?žœ˜EKšžœC˜J—šž˜Kšœžœ˜ —K˜—Kšžœ˜—Kšœ)˜)K˜—šœžœžœ ˜KšœI˜IKšœžœF˜JK˜—Kšœžœ žœ˜0Kšœžœ*˜5Kšœ žœ žœ˜2Kšœžœžœ žœžœ žœžœ žœžœ˜bK˜Kšœ9˜9šœ˜Kšœ˜KšžœL˜OKšœ˜—šœHžœ˜Ošœ œ˜.šœ˜Kšœ˜šžœ&˜(KšœC˜CK˜—Kšœ ˜ K˜ Kšœ˜——šœ˜Kšœ ˜ Kšœ-žœžœ˜9Kšœ˜—Kšœ˜—K˜ Kšœ1˜1šžœžœ(˜?šžœ˜Kšœ žœ˜'Kšœžœ˜KšœF˜FKšœ%˜%šžœžœ˜šœ˜K˜šžœ!˜$Kšœ˜Kšœ˜šœ ˜ šžœž˜Kšœ˜Kšœ˜Kšžœ˜——Kšœ˜K˜Kšœ˜—K˜—šœžœ5ž˜KKšœžœI˜M—šœžœF˜MKšœžœI˜M—Kšœ2˜2K˜—Kšœ žœ˜%K˜—Kšžœ.žœžœ˜>—šœ˜Kšœ˜šžœ#˜&Kšœ ˜ Kšœ˜Kš œ žœžœžœžœ˜AKšœ˜—Kšœ˜—Kšžœ˜K˜—šœ˜šžœ˜ Kšœ%žœ"žœ˜RKšœžœžœžœ™bKšœ˜—šœ˜Kšœžœ˜Kšœ%žœE˜mKšž˜K˜—K˜—K˜K˜—š Ÿœžœžœ žœ'žœ˜yKšœžœ˜6Kšœ žœžœ˜Kšœžœ˜+šœ+žœ/˜\šœžœ ˜ šžœ ž˜šœ&˜&Kšœ2™2Kšžœ ˜—Kšžœ˜——Kšœ˜—KšœQ™QKšœ˜Kšœ'˜'Kšžœ˜Kšžœ>˜CK˜—š Ÿœžœžœ žœ'žœ™yKšŸœ&™7šœ=žœ ™IKšœ ™ Kšœ%™%šœžœ ™ šžœ ž™šœ&™&Kšœ2™2Kšœ(™(Kšœ"™"Kšžœ™ K™—Kšžœ™——Kšœ™—K™K™—š Ÿ œžœžœžœžœ˜3šΠkyΟy‘’˜$Kš’‘’˜&Kš’‘’ ˜*Kš’‘’˜'Kš’ ‘’+˜:š‘’‘’‘’‘’˜0Kš‘’‘’‘’+˜Tš‘’8‘’˜VKš‘’˜!—Kš‘’ ˜&Kš’˜—Kš’‘˜—Kšžœ˜K˜K˜—K˜Kšžœ˜™5Kšœ Οrœ£œA™ˆ—™/Kšœ Ÿ œ.™G—™-Kšœ†™†—K™K˜K˜—…—@Ldκ