DIRECTORY Ascii, BasicTime USING [FromNSTime, GMT], Convert, IO, MailBasics, MailBasicsFileTypes, MailBasicsItemTypes, MailBasicsMoreItemTypes, MailRetrieve, MailUtils USING [GeneratePostmark, GetTimeFromPostmark], MSBasics, MSMessage USING [GetHeaderRope, headingBodyPart], MSRetrieve, MSUtils, PFS, RefText, Rope, SerializedFiling, SystemNames USING [UserName], UserProfile, XNSCHName USING [NameFromRope, RopeFromName]; MSMailRetrieveImpl: CEDAR PROGRAM IMPORTS Ascii, BasicTime, Convert, IO, MailRetrieve, MailUtils, MSMessage, MSRetrieve, MSUtils, PFS, RefText, Rope, SerializedFiling, SystemNames, UserProfile, XNSCHName ~ BEGIN STREAM: TYPE ~ IO.STREAM; ROPE: TYPE ~ Rope.ROPE; Handle: TYPE ~ MailRetrieve.Handle; MBXState: TYPE ~ MailRetrieve.MBXState; ServerState: TYPE ~ MailRetrieve.ServerState; ServerType: TYPE ~ MailRetrieve.ServerType; FailureReason: TYPE ~ MailRetrieve.FailureReason; MSInfo: TYPE ~ REF MSInfoRec; MSInfoRec: TYPE ~ RECORD [ user: MSBasics.CHName, -- user/mailbox name envelope: MSBasics.Envelope, -- envelope of current message postmark: MailBasics.Timestamp, -- needed later if there is an attachment sender: ROPE, -- needed later if there is an attachment newMsg: BOOL, -- TRUE when envelope needs to be returned systemMessage: ROPE, -- derived from envelope if appropriate msH: MSRetrieve.Handle, -- XNS Mail Service handle for mailbox handle: Handle, -- for reproting state changes plainTextFromHeader: ROPE, -- if in header, non-nil until returned as item formattingFromHeader: ROPE, -- if in header, non-nil until returned as item bodyAnnotSize: CARD32 ฌ 0, -- size of extra text in body of message lastBodyPartType: MailBasicsItemTypes.ItemType ฌ MailBasicsItemTypes.header, -- for bodyAnnotSize fix reportChanges: PROC[Handle, MBXState] ]; msInfoList: LIST OF MSInfo ฌ NIL; tiogaTextOK: BOOL ฌ TRUE; AttributeType: TYPE = SerializedFiling.AttributeType; lastInterlispType: AttributeType = 4919; -- from MailFormatP1516V3 MSClose: PROC [ref: REF] RETURNS [] ~ { msInfo: MSInfo = NARROW[ref]; MSRetrieve.Close[msInfo.msH]; }; MSNewUser: PROC [handle: Handle, user: MailBasics.RName, password: ROPE, pollingInterval: CARDINAL, reportChanges: PROC[Handle, MBXState] ] RETURNS [REF] ~ { msInfo: MSInfo ฌ NEW[MSInfoRec]; msInfo.user ฌ XNSCHName.NameFromRope[user.name]; msInfo.msH ฌ MSRetrieve.Create[pollingInterval, IF reportChanges#NIL THEN ChangeReportFromMS ELSE NIL]; msInfo.reportChanges ฌ reportChanges; msInfo.handle ฌ handle; MSRetrieve.NewUser[msInfo.msH, msInfo.user, password]; msInfoList ฌ CONS[msInfo, msInfoList]; RETURN[msInfo]; }; MSMailboxState: PROC [ref: REF] RETURNS [mboxState: MBXState] ~ { ENABLE MSRetrieve.Failed => ERROR MailRetrieve.Failed[FromMSFailureReason[why], text]; msInfo: MSInfo = NARROW[ref]; mboxState ฌ FromMSMboxState[MSRetrieve.MailboxState[msInfo.msH]]; }; MSNextServer: PROC [ref: REF] RETURNS [noMore: BOOLEAN, state: ServerState, type: ServerType] ~ { ENABLE MSRetrieve.Failed => ERROR MailRetrieve.Failed[FromMSFailureReason[why], text]; msInfo: MSInfo = NARROW[ref]; msState: MSRetrieve.ServerState; noMore ฌ TRUE; state ฌ unknown; type ฌ $unknown; [noMore, msState] ฌ MSRetrieve.NextServer[msInfo.msH]; IF NOT noMore THEN { state ฌ FromMSServerState[msState]; type ฌ $xns; }; }; MSServerName: PROC [ref: REF] RETURNS [serverName: MailBasics.RName] ~ { msInfo: MSInfo = NARROW[ref]; serverName.ns ฌ $xns; serverName.name ฌ XNSCHName.RopeFromName[MSRetrieve.ServerName[msInfo.msH]]; }; MSUserName: PROC [ref: REF] RETURNS [userName: MailBasics.RName] ~ { msInfo: MSInfo = NARROW[ref]; userName.ns ฌ $xns; userName.name ฌ XNSCHName.RopeFromName[msInfo.user]; }; MSNextMessage: PROC [ref: REF] RETURNS [msgExists, archived, deleted, read: BOOLEAN] ~ { ENABLE MSRetrieve.Failed => ERROR MailRetrieve.Failed[FromMSFailureReason[why], text]; msInfo: MSInfo = NARROW[ref]; [msgExists, read] ฌ MSRetrieve.NextMessage[msInfo.msH]; archived ฌ FALSE; deleted ฌ FALSE; IF msgExists THEN { msInfo.envelope ฌ MSRetrieve.GetMessageEnvelope[msInfo.msH]; msInfo.systemMessage ฌ MSUtils.SystemMessageFromEnvelope[msInfo.envelope]; msInfo.newMsg ฌ TRUE; }; }; MSStartMessage: PROC [ref: REF] RETURNS [postmark: MailBasics.Timestamp, sender: MailBasics.RName, returnTo: MailBasics.RName] ~ { ENABLE MSRetrieve.Failed => ERROR MailRetrieve.Failed[FromMSFailureReason[why], text]; msInfo: MSInfo = NARROW[ref]; msInfo.postmark ฌ postmark ฌ RopeFromMSPostmark[msInfo.envelope]; sender ฌ [ns: $xns, name: MSUtils.RopeFromMSRName[msInfo.envelope.originator]]; msInfo.sender ฌ sender.name; returnTo ฌ sender; }; boilerPlate: ROPE ~ "\r===========> msg from XNSMailUser <===========\r"; MSNextItem: PROC [ref: REF] RETURNS [ih: MailBasics.ItemHeader, currentItem: STREAM] ~ { ENABLE MSRetrieve.Failed => ERROR MailRetrieve.Failed[FromMSFailureReason[why], text]; msInfo: MSInfo = NARROW[ref]; bp: MSBasics.BodyPartInfo; isTiogaText: BOOL ฌ FALSE; DoAttachment: PROC[baseName: ROPE, fileType: PFS.FileType] = { msg: ROPE; this: ROPE ฌ MSGetItemAsRope[ref]; IF UserProfile.Boolean["XNSMail.FlushMsgsWithAttachments", FALSE] THEN { who: ROPE = SystemNames.UserName[]; -- unix name needed wDir: ROPE ฌ UserProfile.Token["XNSMail.attachmentsDir", IO.PutFR1["/tilde/%g/.cedar/xnsMailAttachments/", [rope[who]]] ]; fileName: ROPE ฌ IO.PutFR["%g-%g.txt", [rope[baseName]], [rope[Intelligible[msInfo.postmark, msInfo.sender]]] ]; fullName: PFS.PATH ฌ PFS.AbsoluteName[short: PFS.PathFromRope[fileName], wDir: PFS.PathFromRope[wDir] ]; fileLength: INT ฌ 0; outStream: STREAM; outStream ฌ PFS.StreamOpen[fileName: fullName, accessOptions: create ! PFS.Error => CONTINUE]; IF outStream = NIL THEN { fullName ฌ PFS.AbsoluteName[short: PFS.PathFromRope[fileName], wDir: PFS.PathFromRope[IO.PutFR1["/tilde/%g/", [rope[who]] ]] ]; outStream ฌ PFS.StreamOpen[fileName: fullName, accessOptions: create ! PFS.Error => CONTINUE]; IF outStream = NIL THEN ERROR MailRetrieve.Failed[$couldntCreateFile, PFS.RopeFromPath[fullName]]; }; outStream.PutRope[this]; fileLength ฌ outStream.GetLength[]; outStream.Close[]; msg ฌ IO.PutFLR["%g==> %g stored as:\r\t%g (%g bytes) <==\r\r", LIST[[rope[boilerPlate]], [rope[baseName]], [rope[PFS.RopeFromPath[fullName]]], [integer[fileLength]]] ]; ih.type ฌ msInfo.lastBodyPartType ฌ MailBasicsMoreItemTypes.hasAttachment; } ELSE { msg ฌ IO.PutFR["%g\r %g attachment not retrieved because XNSMail.FlushMsgsWithAttachments was FALSE\r\r", [rope[boilerPlate]], [rope[baseName]] ]; ih.type ฌ msInfo.lastBodyPartType ฌ MailBasicsItemTypes.multinationalNote; }; currentItem ฌ IO.RIS[msg]; ih.length ฌ msg.Length[]; }; GetNSTextFile: PROC RETURNS[note, plainTextR, formattingR: ROPE] = { sf: SerializedFiling.SerializedFile; len: INT ~ msInfo.bodyAnnotSize; sf ฌ SerializedFiling.GetSerializedFile[MSRetrieve.GetBodyPart[msInfo.msH]]; note ฌ SerializedFiling.GetRopeContents[sf]; IF ( len # 0 ) THEN { msInfo.bodyAnnotSize ฌ 0; IF len < note.Length[] THEN note ฌ note.Substr[len]; }; plainTextR ฌ SerializedFiling.GetRopeAttribute[sf, lastInterlispType-1]; formattingR ฌ SerializedFiling.GetRopeAttribute[sf, lastInterlispType]; }; IF msInfo.newMsg THEN { -- return the envelope ih.type ฌ msInfo.lastBodyPartType ฌ MailBasicsItemTypes.envelope; [currentItem, ih.length] ฌ BuildMSEnvelopeItem[msInfo.envelope]; msInfo.newMsg ฌ FALSE; RETURN; }; IF msInfo.systemMessage # NIL THEN { -- return the system message ih.type ฌ msInfo.lastBodyPartType ฌ MailBasicsItemTypes.systemMessage; currentItem ฌ IO.RIS[msInfo.systemMessage]; ih.length ฌ Rope.Length[msInfo.systemMessage]; msInfo.systemMessage ฌ NIL; RETURN; }; IF msInfo.plainTextFromHeader # NIL THEN { ih.type ฌ msInfo.lastBodyPartType ฌ MailBasicsItemTypes.plainTextForFormatting; currentItem ฌ IO.RIS[msInfo.plainTextFromHeader]; ih.length ฌ Rope.Length[msInfo.plainTextFromHeader]; msInfo.plainTextFromHeader ฌ NIL; RETURN; }; IF msInfo.formattingFromHeader # NIL THEN { ih.type ฌ msInfo.lastBodyPartType ฌ MailBasicsItemTypes.tioga1; currentItem ฌ IO.RIS[msInfo.formattingFromHeader]; ih.length ฌ Rope.Length[msInfo.formattingFromHeader]; msInfo.formattingFromHeader ฌ NIL; RETURN; }; bp ฌ MSRetrieve.NextBodyPart[msInfo.msH]; ih.type ฌ msInfo.lastBodyPartType ฌ MapMSBodyPartType[bp.type]; SELECT ih.type FROM MailBasicsItemTypes.nsTextFile => IF UserProfile.Boolean["XNSMail.nsTextFileAsFile", FALSE] THEN DoAttachment["NSTextFile", [3] ] ELSE { tempBodies: ROPE; [tempBodies, , ] ฌ GetNSTextFile[]; currentItem ฌ IO.RIS[tempBodies]; ih.type ฌ msInfo.lastBodyPartType ฌ MailBasicsItemTypes.multinationalNote; ih.length ฌ tempBodies.Length[]; }; MailBasicsItemTypes.vpDocument => DoAttachment["VPDocument", MailBasicsFileTypes.vpDocFileType]; MailBasicsItemTypes.vpFolder => DoAttachment["VPFolder", [3] ]; MailBasicsItemTypes.otherNSFile => DoAttachment["OtherNSFile", [3] ]; MailBasicsItemTypes.interpress => DoAttachment["Interpress", [3] ]; MailBasicsItemTypes.postscript => DoAttachment["Postscript", [3] ]; ENDCASE => [currentItem, ih.length] ฌ MapMSItemContents[bp, msInfo]; }; MSGetItem: PROC [ref: REF] RETURNS [STREAM] ~ { ENABLE MSRetrieve.Failed => ERROR MailRetrieve.Failed[FromMSFailureReason[why], text]; msInfo: MSInfo = NARROW[ref]; RETURN[MSRetrieve.GetBodyPart[msInfo.msH]]; }; MSGetItemAsRope: PROC [ref: REF] RETURNS [rp: ROPE] ~ { ENABLE MSRetrieve.Failed => ERROR MailRetrieve.Failed[FromMSFailureReason[why], text]; msInfo: MSInfo = NARROW[ref]; rp ฌ MSRetrieve.GetBodyPartAsRope[msInfo.msH]; IF ( msInfo.lastBodyPartType = MailBasicsItemTypes.multinationalNote ) AND ( msInfo.bodyAnnotSize # 0 ) THEN { ln: INT ฌ msInfo.bodyAnnotSize; msInfo.bodyAnnotSize ฌ 0; IF ln < rp.Length[] THEN RETURN[rp.Substr[ln]] ELSE RETURN[rp]; } ELSE RETURN[rp]; }; MSGetItemViaCallback: PROC [ref: REF, proc: MailRetrieve.GetItemCallback] ~ { ENABLE MSRetrieve.Failed => ERROR MailRetrieve.Failed[FromMSFailureReason[why], text]; CheckForAbort: PROC RETURNS [BOOL] ~ { RETURN[FALSE]; }; msInfo: MSInfo = NARROW[ref]; MSRetrieve.GetBodyPartViaCallback[msInfo.msH, proc]; }; MSMarkMessage: PROC [ref: REF] RETURNS [] ~ { ENABLE MSRetrieve.Failed => ERROR MailRetrieve.Failed[FromMSFailureReason[why], text]; msInfo: MSInfo = NARROW[ref]; MSRetrieve.MarkMessage[msInfo.msH]; }; MSDeleteMessage: PROC [ref: REF] RETURNS [] ~ { ENABLE MSRetrieve.Failed => ERROR MailRetrieve.Failed[FromMSFailureReason[why], text]; msInfo: MSInfo = NARROW[ref]; MSRetrieve.DeleteMessage[msInfo.msH]; }; MSAccept: PROC [ref: REF] RETURNS [] ~ { ENABLE MSRetrieve.Failed => ERROR MailRetrieve.Failed[FromMSFailureReason[why], text]; msInfo: MSInfo = NARROW[ref]; MSRetrieve.Accept[msInfo.msH]; }; RopeFromMSPostmark: PROC [env: MSBasics.Envelope] RETURNS [id: ROPE] = { RETURN [MailUtils.GeneratePostmark[gmt: BasicTime.FromNSTime[env.postmark.time], machine: MSUtils.RopeFromMSRName[env.postmark.postedAt]] ]; }; Intelligible: PROC[timeStamp: MailBasics.Timestamp, sender: ROPE] RETURNS[ROPE] = { nameCount: INT ฌ 0; timeBuf.length ฌ 0; FOR i: INT IN [0..sender.Length[]) DO c: CHAR = sender.Fetch[i]; IF ~(Ascii.Letter[c] OR Ascii.Digit[c]) THEN LOOP; timeBuf ฌ RefText.AppendChar[timeBuf, c]; IF (nameCount ฌ nameCount + 1) >= 8 THEN EXIT; ENDLOOP; timeBuf ฌ RefText.AppendChar[timeBuf, '-]; -- after name timeBuf ฌ Convert.AppendTimeRFC822[timeBuf, MailUtils.GetTimeFromPostmark[timeStamp]]; FOR i: NAT IN [0..timeBuf.length) DO SELECT timeBuf[i] FROM ' , '\t => timeBuf[i] ฌ '-; ': => timeBuf[i] ฌ '.; ENDCASE; ENDLOOP; RETURN[Rope.FromRefText[timeBuf]]; }; timeBuf: REF TEXT ฌ NEW[TEXT[RefText.line]]; highXNS: MSBasics.BodyPartType = 499; MapMSBodyPartType: PROC [type: MSBasics.BodyPartType] RETURNS [mapped: MailBasics.ItemType] ~ { SELECT type FROM MSBasics.lastBodyPart => mapped ฌ MailBasicsItemTypes.lastItem; -- last item; < highXNS => mapped ฌ type; -- direct map ENDCASE => mapped ฌ highXNS; -- hopefully won't see these for awhile }; MapMSItemContents: PROC [bp: MSBasics.BodyPartInfo, msInfo: MSInfo] RETURNS [item: STREAM ฌ NIL, length: INT] ~ { SELECT bp.type FROM MSMessage.headingBodyPart => { -- convert X.400 header to text header, plainText, formatting: ROPE; item ฌ MSRetrieve.GetBodyPart[msInfo.msH]; [header, plainText, formatting, msInfo.bodyAnnotSize] ฌ MSMessage.GetHeaderRope[item]; length ฌ Rope.Length[header]; item ฌ IO.RIS[header]; IF plainText # NIL AND ( tiogaTextOK ) THEN { msInfo.plainTextFromHeader ฌ plainText; msInfo.formattingFromHeader ฌ formatting; }; }; ENDCASE => { -- return body part as is length ฌ bp.sizeInBytes; item ฌ NIL; -- get it from server if requested }; }; BuildMSEnvelopeItem: PROC [envelope: MSBasics.Envelope] RETURNS [item: STREAM, length: INT] ~ { rope: ROPE ฌ MSUtils.RopeFromEnvelope[envelope]; item ฌ IO.RIS[rope]; length ฌ Rope.Length[rope]; }; FromMSMboxState: PROC [msState: MSRetrieve.MboxState] RETURNS [state: MBXState] ~ { state ฌ VAL[ORD[msState]]; }; FromMSServerState: PROC [msState: MSRetrieve.ServerState] RETURNS [state: ServerState] ~ { state ฌ VAL[ORD[msState]]; }; FromMSFailureReason: PROC [msWhy: MSRetrieve.FailureReason] RETURNS [why: FailureReason] ~ { why ฌ SELECT msWhy FROM $RPC => $communicationFailure, $Protocol => $unknownFailure, $Service => $connectionRejected, $Authentication => $badCredentials, ENDCASE => $unknownFailure; }; ChangeReportFromMS: MSRetrieve.ChangeReportProc ~ { FOR mL: LIST OF MSInfo ฌ msInfoList, mL.rest UNTIL mL=NIL DO IF mL.first.msH = handle THEN mL.first.reportChanges[mL.first.handle, FromMSMboxState[state] ]; ENDLOOP; }; InitProcs: PROC = { mailRetrieveProcs: MailRetrieve.MailRetrieveProcsRef ฌ NEW[MailRetrieve.MailRetrieveProcs ฌ [ which: $xns, Close: MSClose, NewUser: MSNewUser, MailboxState: MSMailboxState, NextServer: MSNextServer, ServerName: MSServerName, UserName: MSUserName, NextMessage: MSNextMessage, StartMessage: MSStartMessage, NextItem: MSNextItem, GetItem: MSGetItem, GetItemAsRope: MSGetItemAsRope, GetItemViaCallback: MSGetItemViaCallback, MarkMessage: MSMarkMessage, DeleteMessage: MSDeleteMessage, Accept: MSAccept ]]; MailRetrieve.RegisterMailRetrieveProcs[mailRetrieveProcs]; }; InitProcs[]; END. ` MSMailRetrieveImpl.mesa Copyright ำ 1988, 1989, 1990, 1991 by Xerox Corporation. All rights reserved. Doug Terry, December 12, 1988 6:06:03 pm PST Willie-sue, November 6, 1992 11:23 am PST Wes Irish, December 22, 1988 6:11:51 pm PST The glue between MailRetrieveImpl & MSRetrieveImpl; taken from the old MailRetrieveImpl Handles A RetrieveHandle allows clients to retrieval mail from one or more mailboxes on one or more different types of mail servers. Associated with each handle is a list of mailboxes. For each mailbox, there is a record that holds the information needed to interact with the mail service maintaining the appropriate mailbox. XNS Mail Service: Global Variables Registered procedures Releases resources used by this handle. Further use of this handle is illegal. Provides new user name and password, and starts authentication and mailbox checking. This can be called several times to associate several mailboxes with the handle. Returns the current mailbox state. Will not return "unknown" or "userOK" (These change to "cantAuth" or "allDown" after suitable timeouts if necessary.) Returns information about the next server in the mailbox site list of the user (or the first server if reset=TRUE), and that server becomes the "current server". If there is no such server, noMore=TRUE, in which case the next call to "NextServer" will start a new sequence of mail retrieval. If the state is "unknown", attempting to access the mailbox is inadvisable, as the server is probably down. If the state is "empty", there may in fact be mail, as the state is only a hint obtained by polling. Provides the name of the current server. Provides the name of the current mailbox being accessed. Returns information about the next message in the mailbox, and that message becomes the "current message". If there is no such message, msgExists=FALSE. If deleted=TRUE then the message is really just a placeholder and has been removed from the mailbox; you should not attempt to access the message. Returning archived=TRUE indicates that the message has been spilled to some file server, and accessing it is likely to be much slower. If read=TRUE then the message is not new, i.e. it has been previously marked as being read. Returns information from the envelope of the message. Note: we should be able to get the proper "reply-to" name out of the message envelope if it is present; unfortunately, MSRetrieve doesn't provide the complete envelope so we'll reply to the originator for now. Skips the remainder of any previous item, then delivers the header of the next item. This implementation is responsible for mediating between the types of items that Grapevine returns and those that this interface returns; ditto for XNS mail body parts. we can't try to strip out the RFC822 extra headers inside an nsTextFile, because they are embedded inside a serialized file - we'd have to pick apart the serialized file and re-write it, which is too much of a pain thows away plainText & formatting from GetNSTextFile [currentItem, ih.length] _ MapMSItemContents[bp, msInfo]; Provides an IO stream for reading the current item. Provides the current item as a ROPE. Provides the current item via a callback. Marks current message as being read. Deletes current message. Flush the mailbox entirely (and irrecoverably). Postmarks Message body items Grapevine item types and XNS body part types are mapped into a single number space as follows: The low XNS body part types (in the range [0..highXNS)) are mapped directly. Currently (as of November 30, 1988), there are no allocated XNS body part types that do not lie in this range. Any that are encountered are currently mapped to highXNS. The high Grapevine item types (in the range (lowGV..GVBasics.LastItem)) are also mapped directly. Known Grapevine item types that do not lie in this range include the server-supplied "envelope" items; these are handled on a case-by-case basis. Other item types that do not lie in the directly-mapped range are mapped to lowGV. Note: envelope: MailBasics.ItemType = 500; Note: postscript: MailBasics.ItemType = 510; Item contents are generally passed to clients in the same form as they are retrieved from a mail service. In some cases, however, we transform the items before returning them. For example, Grapevine's Text items include both the header and the message body; we split these by reading the heading off the item stream and leaving the body. Also, Grapevine always returns the Recipients as the first and only envelope item; we map this to a complete envelope. For XNS mail, X.400 style headers are converted to RFC-822 text headers. Returning a NIL item stream means that the item's contents will be requested from the mail service on demand. In any case, the length returned should be accurate. Envelope information is put together into a single "envelope" item that looks like a RFC-822 header. For XNS mail, we have all of the relevant information in MSBasics.Envelope. For Grapevine, the StartMessage call returns all but the intended recipients, which is generally returned as the first item. Type conversions State reporting [state: MboxState, handle: Handle] สp•NewlineDelimiter –(cedarcode) style™code•Mark outsideHeaderšฯb™Kšœ ฯeœC™NKšœ)ฯk™,K™)Kšœ+™+K™KšœW™WK™—šŸ ˜ K˜Kšœ ŸœŸœ˜"K˜KšŸœ˜Kšœ ˜ K˜K˜K˜Kšœ ˜ Kšœ Ÿœ)˜8Kšœ ˜ Kšœ Ÿœ"˜1Kšœ ˜ K˜KšŸœ˜K˜Kšœ˜K˜Kšœ Ÿœ ˜K˜ Kšœ Ÿœ˜-—K˜šัblnœŸœŸ˜!KšŸœŸœ;ŸœF˜ฉKšœŸ˜K˜KšŸœŸœŸœŸœ˜KšŸœŸœŸœ˜KšœŸœ˜#Kšœ Ÿœ˜'Kšœ Ÿœ˜-Kšœ Ÿœ˜+šœŸœ˜1K˜——head™Kšœฟ™ฟ˜K˜—šŸœ™KšœŸœŸœ ˜šœ ŸœŸœ˜Kšœฯc˜-Kšœก˜Kšœก&˜?Kšœก˜/KšœŸœก/˜JKšœŸœก/˜KKšœŸœก(˜CKšœNก˜fKšœŸœ˜%K˜———™Kšœ ŸœŸœ Ÿœ˜!Kšœ ŸœŸœ˜KšœŸœ"˜5Kšœ)ก˜BK˜—™šฯnœŸœŸœŸœ˜'KšœO™OKšœŸœ˜Kšœ˜K˜K™—šข œŸœ4ŸœŸœŸœŸœŸœ˜Kšœฆ™ฆKšœŸœ ˜ K˜0Kš œ0ŸœŸœŸœŸœŸœ˜gK˜%K˜Kšœ6˜6Kšœ Ÿœ˜&KšŸœ ˜K˜K™—šขœŸœŸœŸœ˜AKšœ™™™KšŸœŸœ5˜VKšœŸœ˜K˜AK˜K™—š ข œŸœŸœŸœ Ÿœ+˜aKšœmŸœUŸœฎ™๘KšŸœŸœ5˜VKšœŸœ˜Kšœ ˜ Kšœ Ÿœ#˜0K˜6šŸœŸœŸœ˜K˜#K˜ K˜—K˜K™—šข œŸœŸœŸœ#˜HKšœ(™(KšœŸœ˜K˜K˜LK˜K™—šข œŸœŸœŸœ!˜DKšœ8™8KšœŸœ˜K˜K˜4K˜K™—š ข œŸœŸœŸœ&Ÿœ˜XKš œ“ŸœŸœ˜ŸœyŸœP™“šŸœŸœ5˜VKšœŸœ˜K˜—K˜7Kšœ Ÿœ˜Kšœ Ÿœ˜šŸœ Ÿœ˜K˜KšœŸœ˜ KšœŸœ˜"K™ึšŸœ9ŸœŸœ˜HKšœŸœก˜7KšœŸœ/Ÿœ?˜zKšœ ŸœŸœ]˜pKš œ ŸœŸœŸœŸœŸœ˜hKšœ Ÿœ˜Kšœ Ÿœ˜K˜Kšœ Ÿœ8Ÿœ Ÿœ˜_šŸœ ŸœŸœ˜Kš œ ŸœŸœŸœŸœ'˜Kšœ Ÿœ8Ÿœ Ÿœ˜_Kš Ÿœ ŸœŸœŸœ)Ÿœ˜bK˜—K˜Kšœ˜K˜#Kšœ˜KšœŸœ8Ÿœ.Ÿœ4˜ฉK˜JK˜šŸœ˜KšœŸœŠ˜’K˜JK˜——KšœŸœŸœ˜K˜K˜—šข œŸœŸœ Ÿœ˜DK˜$KšœŸœ˜ K˜LK˜,šŸœ Ÿœ˜K˜KšŸœŸœ˜4K˜—K˜HK˜GK˜—šŸœŸœก˜/K˜AK˜@KšœŸœ˜KšŸœ˜K˜—šŸœŸœŸœก˜BK˜FKšœŸœŸœ˜+K˜.KšœŸœ˜KšŸœ˜K˜—šŸœŸœŸœ˜*K˜OKšœŸœŸœ˜1K˜4KšœŸœ˜!KšŸœ˜K˜—šŸœŸœŸœ˜+K˜?KšœŸœŸœ˜2K˜5KšœŸœ˜"KšŸœ˜K˜—K˜)K˜?šŸœ Ÿ˜šœ"Ÿœ1ŸœŸœ!˜šŸœ˜Kšœ4™4Kšœ Ÿœ˜K˜#KšœŸœŸœ ˜!K˜JK˜ K˜——K˜`K˜?K˜EK˜CK˜DKšŸœ=˜D—Kšœ9™9K˜K™—š ข œŸœŸœŸœŸœ˜/Kšœ Ÿœ%™3KšŸœŸœ5˜VKšœŸœ˜KšŸœ%˜+K˜K™—š ขœŸœŸœŸœŸœ˜7Kšœ$™$KšŸœŸœ5˜VKšœŸœ˜K˜.šŸœEŸœŸœ˜nKšœŸœ˜K˜Kš ŸœŸœŸœŸœŸœ˜?K˜KšŸœŸœ˜—K˜K™—šขœŸœŸœ)˜MKšœ)™)KšŸœŸœ5˜Všข œŸœŸœŸœ˜&KšŸœŸœ˜K˜—KšœŸœ˜Kšœ4˜4K˜K™—šข œŸœŸœŸœ˜-K™$KšŸœŸœ5˜VKšœŸœ˜Kšœ#˜#K˜K˜—šขœŸœŸœŸœ˜/K™KšŸœŸœ5˜VKšœŸœ˜Kšœ%˜%K˜K˜—šขœŸœŸœŸœ˜(Kšœ/™/KšŸœŸœ5˜VKšœŸœ˜Kšœ˜K˜——™ šขœŸœŸœŸœ˜HKšŸœ†˜ŒK˜K˜—š ข œŸœ)ŸœŸœŸœ˜SKšœ Ÿœ˜K˜šŸœŸœŸœŸ˜%KšœŸœ˜KšŸœŸœŸœŸœ˜2K˜)KšŸœ"ŸœŸœ˜.KšŸœ˜—Kšœ+ก ˜8K˜VšŸœŸœŸœŸ˜$šŸœ Ÿ˜K˜K˜KšŸœ˜—KšŸœ˜—KšŸœ˜"K˜K˜—Kš œ ŸœŸœŸœŸœ˜,—™KšœŸœLŸœŸœด™กK˜K˜%Kšœ*™*Kšœ,™,K˜šขœŸœŸœ"˜_šŸœŸ˜KšœAก ˜NKšœก ˜*KšŸœก'˜E—K˜K˜—K™KšœัŸœ,Ÿœ™•K™š ขœŸœ-ŸœŸœŸœ Ÿœ˜qKšœ Ÿœ”™ฃšŸœ Ÿ˜šœ ก˜?KšœŸœ˜$K˜*K˜VK˜KšœŸœŸœ ˜šŸœ ŸœŸœŸœ˜-K˜'K˜)K˜—K˜—šŸœก˜'K˜KšœŸœก"˜/Kšœ˜——K˜K˜—K™KšœUŸœŸœย™ฏK™š ขœŸœŸœŸœ Ÿœ˜_KšœŸœ&˜0KšœŸœŸœ˜K˜K˜——™šขœŸœ!Ÿœ˜TKšœŸœŸœ ˜Kšœ˜K˜—šขœŸœ#Ÿœ˜[KšœŸœŸœ ˜Kšœ˜K˜—šขœŸœ#Ÿœ˜]šœŸœŸ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ#˜#KšŸœ˜—Kšœ˜——™šขœ!˜3Kšฯs"™"š ŸœŸœŸœŸœŸœŸ˜