DIRECTORY BasicTime USING [GMT, nullGMT], IO, RefText USING [New], Rope, RuntimeError USING [BoundsFault], ViewerTools USING [TiogaContents], WalnutDB -- USING lots -- , WalnutDefs USING [Error, MsgSet], WalnutKernelDefs USING [LogEntry, MsgLogEntry], WalnutLog -- USING lots -- , WalnutOps, WalnutOpsExtras USING [], WalnutOpsMonitorImpl, WalnutOpsInternal USING [rootFileName, CarefullyApply, CheckInProgress, LongRunningApply], WalnutParseMsg USING [ParseHeadersFromRope], WalnutRegistryPrivate USING [NotifyForMove, NotifyForMsgEvent, NotifyForMsgSetEvent]; WalnutOpsImpl: CEDAR MONITOR LOCKS walnutOpsMonitorImpl IMPORTS IO, RefText, Rope, RuntimeError, walnutOpsMonitorImpl: WalnutOpsMonitorImpl, WalnutDefs, WalnutDB, WalnutOpsInternal, WalnutLog, WalnutParseMsg, WalnutRegistryPrivate EXPORTS WalnutOps, WalnutOpsExtras SHARES WalnutOpsMonitorImpl = BEGIN OPEN WalnutOpsInternal; TiogaContents: TYPE = ViewerTools.TiogaContents; ROPE: TYPE = Rope.ROPE; MsgSet: TYPE = WalnutDefs.MsgSet; DomainVersion: TYPE = WalnutOps.DomainVersion; MsgSetVersion: TYPE = WalnutOps.MsgSetVersion; DeletedMsgSetName: PUBLIC ROPE _ "Deleted"; ActiveMsgSetName: PUBLIC ROPE _ "Active"; EnumeratorForMsgs: TYPE = REF EnumeratorForMsgsObject; EnumeratorForMsgsObject: PUBLIC TYPE = RECORD[ SELECT type: * FROM FromLog => [ createDate: BasicTime.GMT _ BasicTime.nullGMT, scanPos: INT _ 0, endPos: INT _ 0, headers: REF TEXT _ NIL ], FromMsgSet => [ lazyEnum: WalnutDB.LazyEnumerator ], ENDCASE ]; ReadOnly: PUBLIC ENTRY PROC RETURNS[readonly: BOOL] = { ENABLE UNWIND => NULL; WalnutOpsInternal.CheckInProgress[]; readonly _ WalnutDB.IsReadOnly[]; -- doesn't really read DB }; GetRootInfo: PUBLIC ENTRY PROC RETURNS[ createDate: BasicTime.GMT, rootFile, mailFor: ROPE] = { ENABLE UNWIND => NULL; Gri: PROC = { [ createDate, , mailFor] _ WalnutDB.GetRootInfo[] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Gri, FALSE]; rootFile _ WalnutOpsInternal.rootFileName; }; FileName: PUBLIC ENTRY PROC RETURNS[fileName: ROPE] = { ENABLE UNWIND => NULL; WalnutOpsInternal.CheckInProgress[]; fileName _ WalnutDB.GetDBName[]; -- doesn't read DB }; SizeOfDatabase: PUBLIC ENTRY PROC RETURNS[messages, msgSets: INT] = { ENABLE UNWIND => NULL; Sd: PROC = { [messages, msgSets] _ WalnutDB.SizeOfDatabase[] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Sd, FALSE]; }; LogLength: PUBLIC ENTRY PROC RETURNS[length: INT] = { ENABLE UNWIND => NULL; LLen: PROC = { length _ WalnutLog.LogLength[] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[LLen, FALSE]; }; MsgSetsInfo: PUBLIC ENTRY PROC RETURNS[version, num: INT] = { ENABLE UNWIND => NULL; Msv: PROC = { [version, num] _ WalnutDB.MsgSetsInfo[] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Msv, FALSE]; }; CreateMsg: PUBLIC ENTRY PROC [msgName: ROPE, body: TiogaContents] = { ENABLE UNWIND => NULL; Cm: PROC = { at: INT _ WalnutLog.WriteMessage[msgName, body]; le: WalnutKernelDefs.LogEntry; mle: WalnutKernelDefs.MsgLogEntry; WalnutLog.SetIndex[at]; le _ WalnutLog.NextEntry[].le; mle _ NARROW[le]; mle.show _ TRUE; [] _ WalnutDB.AddNewMsg[mle]; }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Cm, TRUE]; }; CreateMsgSet: PUBLIC ENTRY PROC[name: ROPE, msDomainVersion: DomainVersion] = { ENABLE UNWIND => NULL; exists: BOOL; Cme: INTERNAL PROC = { exists _ WalnutDB.CreateMsgSet[name, msDomainVersion].existed; [] _ WalnutLog.CreateMsgSet[name]; }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Cme, TRUE]; IF ~exists THEN WalnutRegistryPrivate.NotifyForMsgSetEvent[created, name]; }; MsgSetExists: PUBLIC ENTRY PROC[name: ROPE, msDomainVersion: DomainVersion] RETURNS[exists: BOOL, version: INT] = { ENABLE UNWIND => NULL; Mse: INTERNAL PROC = { [exists, version] _ WalnutDB.MsgSetExists[name, msDomainVersion] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Mse, FALSE]; }; SizeOfMsgSet: PUBLIC ENTRY PROC[name: ROPE] RETURNS[messages, version: INT] = { ENABLE UNWIND => NULL; Sms: INTERNAL PROC = { [messages, version] _ WalnutDB.NumInMsgSet[name] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Sms, FALSE]; }; EmptyMsgSet: PUBLIC ENTRY PROC [msgSet: MsgSet] RETURNS [someInDeleted: BOOL] = { ENABLE UNWIND => NULL; Ems: INTERNAL PROC[inProgress: BOOL] = { someInDeleted _ FALSE; IF WalnutDB.EqMsgSets[msgSet.name, DeletedMsgSetName] THEN RETURN; IF ~inProgress THEN { at: INT; IF ~WalnutDB.VerifyMsgSet[msgSet] THEN RETURN; at _ WalnutLog.EmptyMsgSet[msgSet.name].at; WalnutDB.SetOpInProgressPos[at]; }; someInDeleted _ WalnutDB.EmptyMsgSet[msgSet]; }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.LongRunningApply[Ems]; }; DestroyMsgSet: PUBLIC ENTRY PROC [msgSet: MsgSet, msDomainVersion: DomainVersion] RETURNS [someInDeleted: BOOL] = { ENABLE UNWIND => NULL; isActive: BOOL; Dms: INTERNAL PROC[inProgress: BOOL] = { someInDeleted _ FALSE; IF ~inProgress THEN { at: INT; IF ~WalnutDB.VerifyMsgSet[msgSet] THEN RETURN; WalnutDB.VerifyDomainVersion[msDomainVersion]; at _ IF isActive THEN WalnutLog.EmptyMsgSet[msgSet.name].at ELSE WalnutLog.DestroyMsgSet[msgSet.name].at; WalnutDB.SetOpInProgressPos[at]; }; IF isActive THEN someInDeleted _ WalnutDB.EmptyMsgSet[msgSet] ELSE someInDeleted _ WalnutDB.DestroyMsgSet[msgSet, msDomainVersion]; }; WalnutOpsInternal.CheckInProgress[]; IF msgSet.name.Equal[DeletedMsgSetName, FALSE] THEN RETURN[FALSE]; -- may not destroy Deleted isActive _ msgSet.name.Equal[ActiveMsgSetName, FALSE]; WalnutOpsInternal.LongRunningApply[Dms]; IF ~isActive THEN WalnutRegistryPrivate.NotifyForMsgSetEvent[destroyed, msgSet.name]; }; EnumerateMsgs: PUBLIC ENTRY PROC RETURNS[enum: EnumeratorForMsgs] = { ENABLE UNWIND => NULL; thisEnum: REF FromLog EnumeratorForMsgsObject; Em: INTERNAL PROC = { thisEnum.createDate _ WalnutDB.GetRootFileVersion[]; thisEnum.endPos _ WalnutLog.LogLength[]; }; WalnutOpsInternal.CheckInProgress[]; thisEnum _ NEW[FromLog EnumeratorForMsgsObject]; WalnutOpsInternal.CarefullyApply[Em, FALSE]; RETURN[thisEnum]; }; NextMsg: PUBLIC ENTRY PROC[enum: EnumeratorForMsgs] RETURNS [msgID: ROPE, msList: LIST OF ROPE, headers: REF TEXT] = { ENABLE UNWIND => NULL; ok: BOOL _ TRUE; thisEnum: REF FromLog EnumeratorForMsgsObject _ NARROW[enum]; Nm: INTERNAL PROC = { skipped: INT; TRUSTED { WITH thisEnum: enum SELECT FROM FromLog => { IF thisEnum.createDate # WalnutDB.GetRootFileVersion[] THEN ERROR WalnutDefs.Error[$db, $InvalidEnumerator, "Wrong rootfile referenced"]; skipped _ WalnutLog.SetPosition[thisEnum.scanPos]; DO wle: WalnutLog.LogEntry; at: INT; [wle, at] _ WalnutLog.QuickScan[]; IF at >= thisEnum.endPos OR wle = NIL THEN { ok _ FALSE; RETURN }; TRUSTED { WITH mle: wle SELECT FROM CreateMsg => { natLen: NAT _ mle.headersLen; -- this better not cause an error isAt: INT; msgID _ Rope.FromRefText[mle.msg]; isAt _ WalnutDB.GetMsgEntryPosition[msgID]; IF isAt = -1 OR isAt > mle.entryStart THEN LOOP; -- oops or duplicate msList _ WalnutDB.GetCategories[msgID]; IF thisEnum.headers = NIL OR thisEnum.headers.maxLength < natLen THEN thisEnum.headers _ RefText.New[natLen]; WalnutLog.GetRefTextFromLog[ mle.entryStart+mle.textOffset, natLen, thisEnum.headers]; headers _ thisEnum.headers; thisEnum.scanPos _ WalnutLog.NextAt[]; EXIT; }; ENDCASE => LOOP; }; ENDLOOP; }; ENDCASE => ERROR WalnutDefs.Error[$db, $InvalidEnumerator, "Wrong type of enumerator"]; }; }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Nm, FALSE]; IF ~ok THEN RETURN[NIL, NIL, NIL]; }; MsgsEnumeration: PUBLIC ENTRY PROC[alphaOrder: BOOL] RETURNS[mL: LIST OF ROPE] = { ENABLE UNWIND => NULL; Me: INTERNAL PROC = { mL _ WalnutDB.MsgsEnumeration[alphaOrder] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Me, FALSE]; }; MsgSetNames: PUBLIC ENTRY PROC[alphaOrder: BOOL] RETURNS[mL: LIST OF ROPE, msDomainVersion: DomainVersion] = { ENABLE UNWIND => NULL; Ems: INTERNAL PROC = { [mL, msDomainVersion] _ WalnutDB.MsgSetsNames[alphaOrder] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Ems, FALSE]; }; MsgsInSetEnumeration: PUBLIC ENTRY PROC[name: ROPE, fromStart: BOOL] RETURNS [mL: LIST OF ROPE, msVersion: MsgSetVersion] = { ENABLE UNWIND => NULL; Emis: INTERNAL PROC = { [mL, msVersion] _ WalnutDB.MsgsInSetEnumeration[name, fromStart] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Emis, FALSE]; }; EnumerateMsgSets: PUBLIC ENTRY PROC [ alphaOrder: BOOL _ TRUE, proc: PROC[msgSet: MsgSet] ] RETURNS [msVersion: MsgSetVersion] = { ENABLE UNWIND => NULL; Emss: INTERNAL PROC = { msVersion _ WalnutDB.EnumerateMsgSets[alphaOrder, proc] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Emss, FALSE]; }; EnumerateMsgsInSet: PUBLIC ENTRY PROC [ name: ROPE, fromStart: BOOL, proc: PROC[msg, TOCentry: ROPE, hasBeenRead: BOOL, startOfSubject: INT]] RETURNS [msVersion: MsgSetVersion] = { ENABLE UNWIND => NULL; Ems: INTERNAL PROC = { msVersion _ WalnutDB.EnumerateMsgsInSet[name, fromStart, proc] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Ems, FALSE]; }; ParseHeaders: PUBLIC ENTRY PROC [headers: ROPE, proc: WalnutOps.ParseProc] RETURNS[msgHeaders: WalnutOps.MsgHeaders] = { ENABLE UNWIND => NULL; WalnutOpsInternal.CheckInProgress[]; msgHeaders _ WalnutParseMsg.ParseHeadersFromRope[headers, proc]; }; MsgExists: PUBLIC ENTRY PROC [msg: ROPE] RETURNS[exists: BOOL] = { ENABLE UNWIND => NULL; Me: INTERNAL PROC = { exists _ WalnutDB.MsgExists[msg] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Me, FALSE]; }; GetCategories: PUBLIC ENTRY PROC [msg: ROPE] RETURNS[msL: LIST OF ROPE] = { ENABLE UNWIND => NULL; GetC: INTERNAL PROC = { msL_ WalnutDB.GetCategories[msg] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[GetC, FALSE]; }; GetDisplayProps: PUBLIC ENTRY PROC[msg: ROPE] RETURNS[hasBeenRead: BOOL, TOCentry: ROPE, startOfSubject: INT] = { ENABLE UNWIND => NULL; GetDP: INTERNAL PROC = { [hasBeenRead, TOCentry, startOfSubject] _ WalnutDB.GetDisplayProps[msg] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[GetDP, FALSE]; }; GetMsgDate: PUBLIC ENTRY PROC [msg: ROPE] RETURNS[date: BasicTime.GMT] = { ENABLE UNWIND => NULL; GetMD: INTERNAL PROC = { date _ WalnutDB.GetMsgDate[msg] }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[GetMD, FALSE]; }; GetMsg: PUBLIC ENTRY PROC [msg: ROPE] RETURNS[contents: TiogaContents, herald, shortName: ROPE] = { ENABLE UNWIND => NULL; GetMT: INTERNAL PROC = { textStart, textLen, formatLen, shortNameLen: INT; [textStart, textLen, formatLen, herald, shortNameLen] _ WalnutDB.GetMsgText[msg]; IF textStart = 0 THEN RETURN; contents _ WalnutLog.GetTiogaContents[textStart, textLen, formatLen]; shortName _ herald.Substr[0, shortNameLen]; }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[GetMT, FALSE]; }; GetMsgText: PUBLIC ENTRY PROC [msg: ROPE, text: REF TEXT] RETURNS[contents: REF TEXT] = { ENABLE UNWIND => NULL; CheckForNat: PROC[len: INT] RETURNS[nat: NAT] = { nat _ len }; Gmt: INTERNAL PROC = { textStart, textLen: INT; natLen: NAT; [textStart, textLen, ] _ WalnutDB.GetMsgText[msg]; IF textStart = 0 THEN { contents _ text; IF contents # NIL THEN contents.length _ 0; RETURN}; BEGIN ENABLE RuntimeError.BoundsFault => GOTO oops; natLen _ CheckForNat[textLen]; IF text = NIL OR (natLen > text.maxLength) THEN contents _ RefText.New[natLen] ELSE contents _ text; WalnutLog.GetRefTextFromLog[textStart, textLen, contents]; EXITS oops => ERROR WalnutDefs.Error[$log, $MsgTooLong, "Msg will not fit in a REF TEXT"]; END; }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Gmt, FALSE]; }; GetMsgHeaders: PUBLIC ENTRY PROC [msg: ROPE, text: REF TEXT] RETURNS[headers: REF TEXT] = { ENABLE UNWIND => NULL; natLen: NAT; Gmh: INTERNAL PROC = { wle: WalnutLog.LogEntry; isAt: INT = WalnutDB.GetMsgEntryPosition[msg]; headers _ text; IF isAt = -1 THEN { IF headers # NIL THEN headers.length _ 0; RETURN}; [] _ WalnutLog.SetPosition[isAt]; [wle, ] _ WalnutLog.QuickScan[]; BEGIN ENABLE RuntimeError.BoundsFault => GOTO oops; TRUSTED { WITH mle: wle SELECT FROM CreateMsg => { natLen: NAT _ mle.headersLen; IF headers = NIL OR headers.maxLength < natLen THEN headers _ RefText.New[natLen]; WalnutLog.GetRefTextFromLog[ mle.entryStart+mle.textOffset, natLen, headers]; }; ENDCASE => NULL; }; EXITS oops => ERROR WalnutDefs.Error[$log, $MsgHeadersTooLong, IO.PutFR["Msg headers (%g bytes) will not fit in a REF TEXT", IO.int[natLen]]]; END; }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Gmh, FALSE]; }; GetMsgShortName: PUBLIC ENTRY PROC [msg: ROPE] RETURNS[shortName: ROPE] = { ENABLE UNWIND => NULL; Gmsn: INTERNAL PROC = { shortNameLen: INT; herald: ROPE; [, , , herald, shortNameLen] _ WalnutDB.GetMsgText[msg]; shortName _ herald.Substr[0, shortNameLen]; }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Gmsn, FALSE]; }; SetHasBeenRead: PUBLIC ENTRY PROC [msg: ROPE] = { ENABLE UNWIND => NULL; Shbr: INTERNAL PROC = { [] _ WalnutLog.HasBeenRead[msg]; WalnutDB.SetHasBeenRead[msg]; }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Shbr, TRUE]; WalnutRegistryPrivate.NotifyForMsgEvent[firstRead, msg]; }; AddMsg: PUBLIC ENTRY PROC [msg: ROPE, from, to: MsgSet] RETURNS [exists: BOOL] = { ENABLE UNWIND => NULL; Am: INTERNAL PROC = { exists _ WalnutDB.AddMsg[msg, from, to]; [] _ WalnutLog.AddMsg[msg, to.name]; }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Am, TRUE]; IF ~exists THEN WalnutRegistryPrivate.NotifyForMove[msg: msg, to: to.name, from: NIL]; }; MoveMsg: PUBLIC ENTRY PROC [msg: ROPE, from, to: MsgSet] RETURNS [exists: BOOL] = { ENABLE UNWIND => NULL; Mm: INTERNAL PROC = { exists _ WalnutDB.MoveMsg[msg, from, to]; [] _ WalnutLog.MoveMsg[msg, from.name, to.name]; }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Mm, TRUE]; IF ~exists THEN WalnutRegistryPrivate.NotifyForMove[msg: msg, to: to.name, from: from.name]; }; RemoveMsg: PUBLIC ENTRY PROC [msg: ROPE, from: MsgSet, deletedVersion: MsgSetVersion] RETURNS [deleted: BOOL] = { ENABLE UNWIND => NULL; Rm: INTERNAL PROC = { deleted _ WalnutDB.RemoveMsg[msg, from, deletedVersion]; [] _ WalnutLog.RemoveMsg[msg, from.name]; }; WalnutOpsInternal.CheckInProgress[]; WalnutOpsInternal.CarefullyApply[Rm, TRUE]; IF deleted THEN WalnutRegistryPrivate.NotifyForMsgEvent[deleted, msg] ELSE WalnutRegistryPrivate.NotifyForMove[msg: msg, to: NIL, from: from.name]; }; END. ΔWalnutOpsImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Willie-Sue, October 21, 1985 12:25:40 pm PDT Donahue, August 5, 1985 2:53:02 pm PDT Implementation of (some of) WalnutOps Last Edited by: Willie-sue, January 10, 1985 3:45:31 pm PST Last Edited by: Donahue, December 11, 1984 8:51:42 pm PST Types Public variables Private types Procedures These procedures are all of the primitive atomic actions out of which Walnut is built. More complex operations will be found in WalnutClientOps (someday). Information about the Walnut database Is the database readonly? What is the name of the file storing the database? Adding new messages to the database Log a message from some agent other than Grapevine and add it to the database. Body is expected to conform to the syntax for messages. The first message on the log with a given name wins. Any subsequent messages with the same name are dropped on the floor. Primitive message set operations Create a message set with name msgSet. the named message set already exists (return with exists TRUE). Remove all messages from msgSet. Messages that are no longer in any message set will be added to "Deleted". msgSet is "Deleted" (do nothing). messages added to "Deleted" (return with someInDeleted TRUE). Remove the specified message set from the database. msgSet must exist (ignore otherwise). msgSet is "Active" (same as EmptyMsgSet). msgSet is "Deleted" (do nothing). Create an enumeration for a message set. Create an enumeration for the messages in a message set. Parsing a message proc is called for each fieldName encountered in the headers; if proc is NIL then all headers are returned. It is ok to take the REF TEXT returned by NextMsg and use it, wrapped in a RefText.TrustTextAsRope. Primitive message operations More complex message set / message operations Add the message (msg) to the message set (to). msg must exist (ignore). to must exist (ignore). to must not be "Deleted" (ignore). msg is already in to (return with exists TRUE) msg had been in "Deleted" (was taken out) (return with undeleted TRUE) Move the message (msg) from one message set (from) to another (to). msg must exist (ignore). from, to must exist (ignore). msg must be in from (ignore). msg is already in to (return with exists TRUE). msg was in "Deleted" (return with undeleted TRUE) msg is now in "Deleted" (return with deleted TRUE) Remove the message (msg) from the message set (from). If this action results in the message not belonging to any message set, it will be placed in the Deleted message set. msg must exist (ignore). from must exist (ignore). from must not be "Deleted" (ignore). msg must be in from (ignore). msg was added to "Deleted" (return with nowInDeleted TRUE). Κτ– "cedar" style˜šΟb™Jšœ Οmœ1™˜>Jšœ"˜"Jšœ˜—Jšœ$˜$Jšœ&Ÿœ˜,JšŸœ Ÿœ;˜JJ˜—J˜š‘ œŸœŸœŸœŸœ"Ÿœ Ÿœ Ÿœ˜sJšŸœŸœŸœ˜š‘œŸ œ˜JšœE˜E—Jšœ$˜$Jšœ&Ÿœ˜-J˜—J˜š ‘ œŸœŸœŸœŸœ˜OJšŸœŸœŸœ˜š‘œŸ œ˜Jšœ5˜5—Jšœ$˜$Jšœ&Ÿœ˜-J˜—J˜š‘ œŸœŸ œŸœ˜QJšœk™kJ™Jšœ!™!Jšœ=™=JšŸœŸœŸœ˜š‘œŸœŸœ Ÿœ˜(JšœŸœ˜JšŸœ4ŸœŸœ˜BšŸœ Ÿœ˜JšœŸœ˜JšŸœ ŸœŸœ˜.Jšœ+˜+J˜ J˜—Jšœ-˜-J˜—Jšœ$˜$Jšœ(˜(J˜—J˜š‘ œŸœ1ŸœŸœ˜sJšœ3™3J™J™%J™)Jšœ!™!JšŸœŸœŸœ˜Jšœ Ÿœ˜š‘œŸœŸœ Ÿœ˜(JšœŸœ˜šŸœ Ÿœ˜JšœŸœ˜JšŸœ ŸœŸœ˜.Jšœ.˜.šœŸœ Ÿœ&˜;JšŸœ)˜-—J˜ J˜—šŸœ Ÿœ-˜=JšŸœA˜E—J˜—J˜Jšœ$˜$Jš Ÿœ&ŸœŸœŸœŸœ ˜]Jšœ/Ÿœ˜6Jšœ(˜(JšŸœ ŸœD˜UJ˜—J™š ‘ œŸœŸœŸœŸœ˜EJšŸœŸœŸœ˜Jšœ Ÿœ!˜.š‘œŸœŸœ˜Jšœ4˜4Jšœ(˜(Jšœ˜—Jšœ$˜$Jšœ Ÿœ"˜0Jšœ%Ÿœ˜,JšŸœ ˜J˜—J˜š ‘œŸœŸœŸœŸ˜;Jš œ Ÿœ ŸœŸœŸœ ŸœŸœ˜;JšŸœŸœŸœ˜JšœŸœŸœ˜Jšœ Ÿœ#Ÿœ˜=š‘œŸœŸœ˜Jšœ Ÿœ˜ šŸœŸœŸœŸœ˜*˜ šŸœ5Ÿ˜;JšŸœH˜M—J˜2šŸ˜J˜JšœŸœ˜J˜"Jš ŸœŸœŸœŸœŸœŸœ˜BšŸœŸœ ŸœŸ˜#šœ˜JšœŸœ !˜@JšœŸœ˜ Jšœ"˜"Jšœ+˜+Jš Ÿœ ŸœŸœŸœ ˜FJšœ'˜'šŸœŸœŸœ%Ÿ˜EJšœ'˜'—šœ˜Jšœ9˜9—Jšœ˜Jšœ&˜&JšŸœ˜J˜—JšŸœŸœ˜J˜—JšŸœ˜—J˜—šŸœ˜ JšŸœG˜L—J˜—Jšœ˜—Jšœ$˜$Jšœ%Ÿœ˜,Jš ŸœŸœŸœŸœŸœŸœ˜"J˜—J˜š‘œŸœŸœŸœ ŸœŸœŸœŸœŸœ˜RJšŸœŸœŸœ˜š‘œŸœŸœ˜Jšœ.˜.—Jšœ$˜$Jšœ%Ÿœ˜,J˜—J™š‘ œŸœŸœŸœ ŸœŸœŸœŸœŸœ%˜nJšœ(™(JšŸœŸœŸœ˜š‘œŸœŸœ˜Jšœ>˜>—Jšœ$˜$Jšœ&Ÿœ˜-J˜—J˜š‘œŸœŸœŸœŸœ ŸœŸœŸœŸœŸœ˜}Jšœ8™8JšŸœŸœŸœ˜š‘œŸœŸœ˜JšœE˜E—Jšœ$˜$Jšœ'Ÿœ˜.J˜—J˜š‘œŸœŸœŸœŸœŸœŸœŸœ˜‚JšŸœŸœŸœ˜š‘œŸœŸœ˜Jšœ<˜<—Jšœ$˜$Jšœ'Ÿœ˜.J˜—J˜š‘œŸœŸœŸœ Ÿœ ŸœŸœŸœŸœŸœŸœ˜΄JšŸœŸœŸœ˜š‘œŸœŸœ˜JšœC˜C—Jšœ$˜$Jšœ&Ÿœ˜-J˜—J˜—šœ™š ‘ œŸœŸœŸœ Ÿœ˜JJšœŸœ&˜.KšœΠ™ΠJšŸœŸœŸœ˜Jšœ$˜$Jšœ@˜@J˜J˜——šœ™J™š‘ œŸœŸœŸœŸœŸœ Ÿœ˜BJšŸœŸœŸœ˜š‘œŸ œ˜Jšœ%˜%—Jšœ$˜$Jšœ%Ÿœ˜,J˜—J˜š‘ œŸœŸœŸœŸœŸœŸœŸœŸœ˜KJšŸœŸœŸœ˜š‘œŸ œ˜Jšœ%˜%—Jšœ$˜$Jšœ'Ÿœ˜.Jšœ˜—J˜š‘œŸœŸœŸœŸœŸœŸœ ŸœŸœ˜qJšŸœŸœŸœ˜š‘œŸ œ˜JšœL˜L—Jšœ$˜$Jšœ(Ÿœ˜/J˜—J˜š‘ œŸœŸœŸœŸœŸœŸœ˜JJšŸœŸœŸœ˜Jš‘œŸ œ'˜;Jšœ$˜$Jšœ(Ÿœ˜/J˜—J˜š‘œŸœŸœŸœŸœŸœ-Ÿœ˜cJšŸœŸœŸœ˜š‘œŸ œ˜Jšœ-Ÿœ˜1JšœQ˜QJšŸœŸœŸœ˜JšœE˜EJšœ+˜+Jšœ˜—Jšœ$˜$Jšœ(Ÿœ˜/J˜—J˜š‘ œŸœŸœŸœŸœŸœŸœ˜9JšœŸœ ŸœŸœ˜ JšŸœŸœŸœ˜Jš ‘ œŸœŸœŸœŸœ˜>š‘œŸ œ˜JšœŸœ˜JšœŸœ˜ Jšœ2˜2šŸœŸœ˜Jšœ˜JšŸœ ŸœŸœ˜+JšŸœ˜—šŸœŸœŸœ˜3Jšœ˜šŸœŸœŸœŸ˜/JšœŸœ˜4—Jšœ:˜:—šŸ˜˜JšŸœG˜L——JšŸœ˜Jšœ˜—Jšœ$˜$Jšœ&Ÿœ˜-J˜—J˜š‘ œŸœŸœŸœŸœŸœŸœ˜