DIRECTORY BasicTime USING [GMT, nullGMT, Period], 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, Rename, StreamFromOpenFile, StreamOpen], FSPseudoServers USING [TranslateForWrite], IO USING [Close, GetIndex, PutFR, PutFR1, STREAM], Rope USING [Concat, Equal, Length, Match, Replace, ROPE, Run, SkipTo, Substr]; SModelImpl: CEDAR MONITOR IMPORTS BasicTime, DFInternal, DFUtilities, FS, FSPseudoServers, IO, Rope EXPORTS DFOperations = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; nSModels: NAT _ 0; SModel: PUBLIC PROC [dfFile: ROPE, action: DFOperations.SModelAction _ [], interact: DFOperations.InteractionProc _ NIL, clientData: REF ANY _ NIL, log: STREAM _ NIL] RETURNS [errors, warnings, filesActedUpon: INT _ 0] = { client: DFInternal.Client = NEW[DFInternal.ClientDescriptor _ [ (interact _ IF interact = NIL THEN DFInternal.DefaultInteractionProc ELSE interact), clientData, log ]]; tempDF: ROPE = "SModelTemporaryDF$"; NewTemporaryDF: ENTRY PROC [pages: INT] RETURNS [out: STREAM] = { outFile: FS.OpenFile; nSModels _ nSModels.SUCC; outFile _ FS.Create[ name: tempDF, pages: pages, setKeep: TRUE, keep: IF nSModels = 1 THEN 1 ELSE CARDINAL.LAST ! FS.Error => { localInfo: REF DFInternal.LocalFileInfo _ NEW[DFInternal.LocalFileInfo _ [name: tempDF]]; DFInternal.ReportFSError[error, localInfo, client, $abort]; } ]; 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] = { IF commit THEN FS.Rename[from: tempName, to: localName] ELSE FS.Delete[tempName]; nSModels _ nSModels.PRED; }; 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] = { 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] = { lGMT: BasicTime.GMT = localInfo.date.gmt; -- can't be nullGMT rGMT: BasicTime.GMT = remoteInfo.date.gmt; -- may be nullGMT 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 ! 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.PutFR["%g {%g} is referenced with '>' in the DF file but is older than the remote version %g {%g}.", [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 => { directoryPath _ directory.path1 _ FS.ExpandName[directory.path1].fullFName; directoryLen _ Rope.Length[directoryPath]; writeDirectoryPath _ TranslateHost[directoryPath]; }; file: REF DFUtilities.FileItem => { 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 ]]; DFInternal.GetFileInfo[info: localInfo, remoteCheck: FALSE ! 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, file.name], localInfo, remoteInfo ! FS.Error => DFInternal.ReportFSError[error, remoteInfo, client, $abort]; ]; }; 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.PutFR[ "%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?", [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 older 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: 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 => IF localInfo.attachedTo.Length ~= 0 THEN { remoteVersion: ROPE = DFUtilities.GetVersionNumber[localInfo.attachedTo]; IF ~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 => { 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 ! 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.PutFR["%g {%g} doesn't correspond to %g {%g}.", [rope[localInfo.name]], [rope[DFUtilities.DateToRope[localInfo.date]]], [rope[remoteInfo.name]], [rope[DFUtilities.DateToRope[remoteInfo.date]]] ] ]] ]; }; 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[dfLocalInfo.name, $read ! 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]; 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]; 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 ]] ]; [] _ FS.Copy[to: dfRemoteInfo.name, from: tempName, attach: TRUE ! 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] = { remoteInfo.date.gmt _ FS.FileInfo[ name: path, wantedCreatedTime: localInfo.date.gmt ! FS.Error => SELECT error.code FROM $unknownCreatedTime, $unknownFile => { remoteInfo.date.gmt _ BasicTime.nullGMT; remoteInfo.date.format _ $omitted; CONTINUE; }; ENDCASE; ].created; }; TranslateHost: PROC [path: ROPE] RETURNS [ROPE] = { IF Rope.Match["[*]*", path] THEN { rPos: INT _ Rope.SkipTo[path, 1, "]"]; host: ROPE _ Rope.Substr[path, 1, rPos-1]; writeHost: ROPE _ FSPseudoServers.TranslateForWrite[host]; IF NOT Rope.Equal[host, writeHost, FALSE] THEN RETURN [Rope.Replace[path, 1, rPos-1, writeHost]]; }; RETURN [path]; }; END. .SModelImpl.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. Bob Hagmann on May 18, 1984 9:04:25 am PDT Russ Atkinson (RRA) October 28, 1985 9:39:27 pm PST Global (monitored) variables Exported to DFOperations This procedure returns TRUE if, in principle, the file should be stored. It does not alter either 'localInfo' or 'remoteInfo' and does not let the user influence its decision. If the local file is not attached, we store it anyway, so that the attachment will be made. If the local file is attached to a remote file whose name differs from the one specified in the DF, we store it even if the dates match, so that the proper attachment will be made. If the short names of the two files are the same and they have the same date, we assume that the remote file is good enough. We need to make an attachment "the other way", however, and prevent the main loop from doing anything. force GetFileInfo to get the highest number version (that we just wrote) update attachedTo The following tests need to be done delicately, since we may not know the actual truth about the remote file, but only what the DF file claims is true. In particular, it is quite possible that remoteDate.gmt = nullGMT when a remote file actually exists. (This case arises if formatFromDF ~= $explicit and ~action.remoteCheck.) Get the directory in angle-bracket format The local file is known to exist. Any remote file with whose date matches will be satisfactory. Note that remoteInfo.name will typically have a version (hint). We do the checking with the name suitably translated for the write server, since that gets around extra checking on the read servers, which are allowed to lag the write server anyway. At this point, remoteInfo.date.format will be $explicit if we are supposed to believe that there is a remote file with create date remoteInfo.date.gmt, and remoteInfo.date.format will be $omitted if we are supposed to believe no such file exists. Furthermore, remoteInfo.name has no version number. This file item is a reference to the DF file we are updating. We check to see if the !H version on the remote server is newer than the input version of the DF file. If so, the user is warned, since he is probably using an obsolete DF file. Factor out the directory path If the file's date and/or (remote) version number is missing or incorrect, we may wish to update them/it. Because of the logic on the earlier call of GetFileInfo, the local file is known to exist. However, it may or may not be attached to a remote file, since the user may have explicitly prohibited a Copy in the preceding arm of the SELECT. If it isn't attached, we don't want to disturb the DF file entry. We would like to RESUME at this point, but until ABORTED is redeclared as a SIGNAL, it won't work. File not found, so just continue with updated info ΚM˜codešœ™Kšœ Οmœ7™BKšœ*™*K™3K˜šΟk ˜ Kšœ žœžœ˜'Kšœ žœ–žœ˜ΔKšœ žœt˜†Kšœ žœΔ˜ΥKšžœžœ˜•Kšœžœ˜*Kšžœžœ"žœ˜2Kšœžœ)žœ˜N——headšœ žœž˜Kšžœ%žœžœ˜IKšžœž˜—˜Kšžœžœžœ˜Kšžœžœžœžœ˜—K™šœ™K™Kšœ žœ˜K˜—Kšœ™K˜šΟnœžœžœ žœSžœžœžœžœžœžœžœ$žœ ˜ήšœžœ ˜?Kš œ žœ žœžœ#žœ ˜TKšœ ˜ Kšœ˜Kšœ˜—Kšœžœ˜$š Ÿœžœžœ žœžœžœ˜AKšœ žœ ˜Kšœžœ˜˜ šžœ˜ Kšœ˜Kš œ žœžœžœžœžœž˜>šœžœ ˜Kšœ žœžœ,˜YKšœ;˜;K˜——K˜—Kšžœžœ%˜.Kšœ˜—š Ÿœžœžœžœ žœ˜AKšœ žœ žœ˜2KšœžœΟc˜CK˜ Kšœ˜—šŸœžœžœ˜#Kš œ žœ žœ žœžœ˜9Kšžœžœžœ&˜7Kšžœ˜Kšœžœ˜Kšœ˜—š Ÿ œžœ žœ'žœžœžœ˜zšžœ˜Kšœ˜šœ ˜ šžœ˜ Kšœ˜Kšœ˜Kšœ/˜/Kšœ9˜9Kšœ˜——Kšœ ž˜ Kšœ˜—K˜—š Ÿ œžœ žœžœžœ˜dKšœžœžœ˜Kšœžœžœ˜Kšœžœ˜Kšœžœžœ˜Kšœžœžœ9˜jKšœ žœžœB˜qšœ*˜*š Ÿ œžœžœ'žœAžœ žœ˜©Kšœ°™°Kšœžœ ˜>Kšœžœ ˜=Kšœ[™[Kšžœ#žœžœžœ˜7Kšœ΄™΄šžœ ˜Kšœ1˜1Kšœ6˜6šžœžœ˜ Kšœδ™δšžœ"žœ ˜3Kšœ&˜&Kšœ+˜+šžœžœ˜ šœžœ˜ Kšœ4˜4Kšœ˜Kšœ'˜'Kšœ ˜ Kšœž˜ Kšœžœ žœžœ ˜Kšœ˜—šœ!˜!KšœH™H—šœ5ž˜:Kšœ™KšœžœD˜HK˜—Kšžœžœ˜šž˜Kšœžœ˜—K˜——Kšžœžœ˜ K˜——Kšœ€žœΖ™Θšžœž˜Kšœžœ˜,Kšœ žœžœ˜9šœ˜šžœžœž˜Kšœžœžœ˜%Kšœ'žœžœ ˜Nšžœ˜ šžœ(ž˜2Kšœžœžœ˜Kšœžœžœ˜šœ˜Kšœžœ˜šœ˜Kšœ˜šžœ!˜$K˜šœ žœe˜pKšœ˜Kšœ/˜/Kšœ˜Kšœ/˜/K˜—K˜—Kšœ˜—Kšžœžœ˜ K˜—Kšžœ˜————Kšžœ˜—K˜—šŸ œžœ žœ˜AKšœžœ˜šœ˜Kšœ˜šžœ!˜$K˜Kšœ žœžœ˜AK˜—Kšœ˜—K˜—š Ÿ œžœ žœžœžœ˜8Kšžœ#žœ˜1K˜—Kšœ˜šžœžœžœ˜šœ žœ˜-Kšœ)™)Kšœ"žœ'˜KKšœ*˜*Kšœ2˜2K˜—šœžœ˜#Kšœ žœ.˜=Kšœ žœžœ)˜Všœ žœ˜+šžœ˜!Kšœ&˜&Kšœ˜Kšœ˜——šœ5ž˜:šœžœ ˜ Kšžœžœžœžœ˜BKšžœ;˜?—Kšœ˜—šžœžœ˜KšœΪ™ΪšœP˜PKšœžœF˜JKšœ˜—K˜—KšœC˜CKšœ«™«šžœžœž˜šœ˜Kšœρ™ρšœžœ˜-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ž˜7KšœžœG˜K—šžœ*žœ˜Ašžœ˜Kšœ™Kšœ1˜1K˜—šžœ˜Kšœžœ6˜WKšœ˜——K˜—Kšœ žœ˜%šžœž˜Kšœ2˜2Kšžœ˜!—K˜—šžœ˜ KšœΡžœ6žœ ™›šžœ"žœ˜*Kšœžœ6˜Išžœ?žœ˜GKšœ,˜,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ž˜:šœžœ ˜ 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˜šœ žœ0˜;KšœG˜GKšœH˜HK˜—K˜—Kšœ˜—K˜—K˜ K˜—šžœž˜Kšœ žœ˜Kšœ?žœ˜EKšžœC˜J—šž˜Kšœžœ˜ —K˜—Kšžœ˜—Kšœ)˜)K˜—šœžœžœ#˜2KšœžœF˜JK˜—Kšœžœ žœ˜0Kšœžœ*˜5Kšœ žœ žœ˜2Kšœ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šœF˜FKšœ%˜%šžœžœ˜šœ˜K˜šžœ!˜$Kšœ˜Kšœ˜šœ ˜ šžœž˜Kšœ˜Kšœ˜Kšžœ˜——Kšœ˜K˜Kšœ˜—K˜—šœžœ5ž˜@Kšœžœ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˜—š Ÿœžœžœ žœ'žœ˜yšœžœ ˜"Kšœ ˜ Kšœ%˜%šœžœ ˜ šžœ ž˜šœ&˜&Kšœ2™2Kšœ(˜(Kšœ"˜"Kšžœ˜ K˜—Kšžœ˜——Kšœ ˜ —K˜K˜—š Ÿ œžœžœžœžœ˜3šžœžœ˜"Kšœžœ˜&Kšœžœ ˜*Kšœ žœ+˜:šžœžœžœž˜.Kšžœ,˜2—K˜—Kšžœ˜K˜—K˜Kšžœ˜—…—:V•