DIRECTORY AlpineWalnutCmds USING [CopyForExpunge], Buttons USING [ButtonProc], Commander USING [CommandProc, Handle, Register], CommandTool USING [Run], Containers, DefaultRemoteNames USING [Get], DB USING [Aborted, Failure, Transaction, AbortTransaction, DeclareSegment, Initialize, TransactionOf], Labels USING [Set], FS USING [Error, SetKeep], GVRetrieve USING [MBXState], Icons USING [IconFlavor, NewIconFromFile], IO, MBQueue USING [Create, QueueClientAction], Menus, MessageWindow USING [Append], PrincOpsUtils USING [IsBound], Process USING [Detach], Rope, Rules USING [Create], UserCredentials USING [Get], UserProfile USING[ProfileChangedProc, Boolean, CallWhenProfileChanges, Token], ViewerBLT USING[ChangeNumberOfLines], ViewerClasses USING [Viewer], ViewerEvents USING [EventProc, EventRegistration, RegisterEventProc, UnRegisterEventProc], ViewerOps, ViewerSpecs USING[openLeftWidth, openRightTopY, openRightWidth], ViewerIO USING [CreateViewerStreams], WalnutControlPrivate USING [CloseTransactions, ClosingWalnut, FlushWQueue, QuitWalnut, StartOrRestartWalnut, WalnutNotifier], WalnutControlMonitorImpl, WalnutDB USING [RegisterUpdatesPendingProc, UnRegisterUpdatesPendingProc], WalnutDBLog USING [GetStartExpungePos], WalnutDisplayerOps USING [msgName, msgSetName], WalnutLog USING [ExpungeMsgs, LogLength, MarkWalnutTransaction], WalnutLogExtras USING [onlyOneTempLog, walnutTempLogName, QuietlyMarkTransaction], WalnutExtras USING [ChangeDBProc, DoWaitCall, DumpProc, EnumWalnutViewers, EstablishFileNames, ExpungeProc, ReadMailProc, RetrieveNewMailProc, ScavengeProc, SetWalnutIcons, TakeDownWalnutViewers], WalnutRetrieve USING [CloseConnection], WalnutSendOps USING [userRName, RegisterReporter, UnregisterReporter, WalnutSendProc], WalnutViewer USING [CreateMenuEntry, FirstLabel, MakeRuler, MakeTypescript], WalnutVoice USING [CheckForWalnuthatch], WalnutWindow USING [Queue, firstMsgSetButton, lastMsgSetButton, selectedMsgSetButtons, AppendButtonProc, ArchiveButtonProc, CreateMsgSetButtonProc, DeleteMsgSetsProc, DestroyAllMsgSetButtons, DoNewMail, PrintMsgSetsProc, SizeOfMsgSetsProc]; WalnutWindowImpl: CEDAR MONITOR LOCKS walnutControlLock IMPORTS AlpineWalnutCmds, DB, FS, Commander, CommandTool, DefaultRemoteNames, Containers, Icons, Labels, MBQueue, Menus, MessageWindow, Rules, IO, PrincOpsUtils, Process, Rope, UserCredentials, UserProfile, ViewerBLT, ViewerEvents, ViewerOps, ViewerIO, ViewerSpecs, walnutControlLock: WalnutControlMonitorImpl, WalnutControlPrivate, WalnutDB, WalnutDBLog, WalnutDisplayerOps, WalnutExtras, WalnutLog, WalnutLogExtras, WalnutRetrieve, WalnutSendOps, WalnutViewer, WalnutVoice, WalnutWindow EXPORTS WalnutControlPrivate, WalnutExtras, WalnutWindow SHARES WalnutControlMonitorImpl, WalnutWindow = BEGIN OPEN WalnutControlPrivate, WalnutExtras, WalnutWindow; ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; InitialNotifyLabel: PUBLIC ROPE_ " "; walnutVersion: ROPE_ "Walnut"; walnut: PUBLIC Viewer_ NIL; wtsOut: IO.STREAM_ NIL; walnutIcon: PUBLIC Icons.IconFlavor_ tool; newMailIcon: PUBLIC Icons.IconFlavor_ tool; msgSetIcon: PUBLIC Icons.IconFlavor_ tool; msgIcon: PUBLIC Icons.IconFlavor_ tool; iconFilePathName: PUBLIC ROPE_ NIL; walnutEventReg: ViewerEvents.EventRegistration_ NIL; mustQuitWalnut: PUBLIC ROPE_ NIL; previousUser: PUBLIC ROPE_ NIL; doingCheckpoint: PUBLIC BOOL_ FALSE; rollbackFinished: PUBLIC CONDITION; initialActiveIconic: PUBLIC BOOL_ FALSE; initialActiveRight: PUBLIC BOOL_ TRUE; initialActiveOpen: PUBLIC BOOL_ TRUE; msgSetBorders: PUBLIC BOOL_ FALSE; enableTailRewrite: PUBLIC BOOL_ FALSE; excessBytesInLogFile: PUBLIC INT_ 300000; walnutRulerBefore, walnutRulerAfter, walnutTS: PUBLIC Viewer; msgSetText: PUBLIC Viewer; -- the text argument for Create MsgSet fileNameText: PUBLIC Viewer; -- fileName for Archiving mailNotifyLabel: PUBLIC Viewer; -- is there new mail or not autoNewMail: BOOL_ FALSE; tryForNewMail: BOOL_ FALSE; doAutoCommit: BOOL_ FALSE; walnutSegmentFile: PUBLIC ROPE; walnutLogName: PUBLIC ROPE; readOnlyAccess: PUBLIC BOOL; logIsAlpineFile: PUBLIC BOOL; personalMailDB: PUBLIC BOOL; segmentName: PUBLIC ATOM_ $Walnut; walnutQueue: PUBLIC Queue; walnutNullTrans: PUBLIC DB.Transaction; responseSynch: CONDITION; userHasResponded, userConfirmed: BOOL_ FALSE; alpineServer: ROPE = "[Luther.alpine]"; -- for now lastStateReported: PUBLIC GVRetrieve.MBXState_ unknown; BuildWalnut: PUBLIC ENTRY Commander.CommandProc = BEGIN ENABLE UNWIND => NULL; h: IO.STREAM; dirName, segName, logName, captionName: ROPE; alpNeeded, logIsAlp: BOOL; IF doingCheckpoint THEN WAIT rollbackFinished; personalMailDB_ TRUE; IF cmd # NIL THEN { h_ IO.RIS[cmd.commandLine]; dirName_ h.GetTokenRope[IO.IDProc ! IO.EndOfStream => {dirName_ NIL; CONTINUE}].token; }; [segName, logName, captionName, logIsAlp]_ CmdProcCall[dirName, cmd]; IF segName=NIL THEN RETURN; IF walnut # NIL THEN IF segName.Equal[walnutSegmentFile, FALSE] THEN { Report["\nWalnut is already running"]; RETURN} ELSE { cdb: ChangeDBParams_ NEW[ChangeDBObject_ [segName: segName, logName: logName, logIsAlp: logIsAlp, alpNeeded: alpNeeded]]; walnut.name_ captionName; ViewerOps.PaintViewer[walnut, caption]; TRUSTED { Process.Detach[FORK ChangeDB[cdb]]}; WAIT cdb.cond; IF walnut # NIL THEN ViewerOps.AddProp[walnut, $IconLabel, dirName]; RETURN }; IF Rope.Length[UserCredentials.Get[].name] = 0 THEN { IF cmd # NIL THEN cmd.out.PutRope["Please Login"]; RETURN}; walnutSegmentFile_ segName; walnutLogName_ logName; logIsAlpineFile_ logIsAlp; WalnutDisplayerOps.msgName _ Rope.Concat[walnutSegmentFile, "!Msg!"]; WalnutDisplayerOps.msgSetName _ Rope.Concat[walnutSegmentFile, "!MsgSet!"]; StartUp[FALSE, captionName]; IF walnut # NIL THEN { ViewerOps.AddProp[walnut, $IconLabel, dirName]; IF personalMailDB AND autoNewMail THEN { tryForNewMail_ FALSE; TRUSTED {Process.Detach[FORK AutoNewMailProc]}; }; }; END; CmdProcCall: INTERNAL PROC[dirName: ROPE, cmd: Commander.Handle] RETURNS[segName, logName, captionName: ROPE, logIsAlp: BOOL] = BEGIN sName, lName: ROPE; alpServer: ROPE = "[Luther.alpine]<"; seg: ROPE = ">Walnut.segment"; log: ROPE = ">Walnut.DBLog"; user: ROPE_ UserCredentials.Get[].name; personalMailDB_ TRUE; IF dirName.Length = 0 THEN { sName_ UserProfile.Token[key: "Walnut.WalnutSegmentFile", default: ""]; lName_ UserProfile.Token[key: "Walnut.WalnutLogFile", default: ""]; IF sName.Length[] = 0 THEN sName_ Rope.Cat[alpServer, user, seg]; IF lName.Length[] = 0 THEN lName_ Rope.Cat[alpServer, user, log]; captionName_ walnutVersion; } ELSE { sName_ Rope.Cat[alpServer, dirName, seg]; lName_ Rope.Cat[alpServer, dirName, log]; personalMailDB_ FALSE; captionName_ Rope.Cat[walnutVersion, " <", dirName, ">"]; }; [segName, logName, logIsAlp]_ EstablishFileNames[sName, lName]; walnutNullTrans_ NIL; IF ~segName.Find[".alpine]", 0, FALSE] > 0 THEN { msg: ROPE_ Rope.Concat[segName, ": is not a valid Walnut segment file; it MUST be on alpine"]; IF cmd # NIL THEN {cmd.out.PutRope[msg]; cmd.out.PutChar['\n]} ELSE ReportRope[msg]; segName_ NIL; }; END; StartUp: INTERNAL PROC[scavengeFirst: BOOL, captionName: ROPE] = BEGIN doAutoCommit_ UserProfile.Boolean[key: "Walnut.DoAutoCommit", default: TRUE]; WalnutLogExtras.onlyOneTempLog_ UserProfile.Boolean[key: "Walnut.OnlyOneTempLog", default: TRUE]; SetTempLogName[]; IF ~BuildWalnutControlWindow[captionName] THEN RETURN; IF doAutoCommit THEN BEGIN old: Menus.MenuEntry; IF (old_ Menus.FindEntry[mailDBMenu, "Commit"])#NIL THEN Menus.ReplaceMenuEntry[mailDBMenu, old, NIL]; IF (old_ Menus.FindEntry[nonMailDBMenu, "Commit"])#NIL THEN Menus.ReplaceMenuEntry[nonMailDBMenu, old, NIL]; END ELSE BEGIN IF Menus.FindEntry[mailDBMenu, "Commit"] = NIL THEN Menus.AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Commit", MyCommitProc]]; IF Menus.FindEntry[nonMailDBMenu, "Commit"] = NIL THEN Menus.AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Commit", MyCommitProc]]; END; IF ~StartOrRestartWalnut[TRUE, scavengeFirst] THEN RETURN; FlushWQueue[]; -- for good measure Report[" ...Ready"]; TRUSTED { Process.Detach[FORK WalnutNotifier[]] }; END; CloseDownWalnut: PUBLIC INTERNAL PROC[doCommit: BOOL] = BEGIN v: Viewer_ walnut; walnut.inhibitDestroy_ TRUE; FlushWQueue[]; InternalChangeMenu[workingMenu]; WalnutDB.UnRegisterUpdatesPendingProc[SetWalnutUpdatesPending]; selectedMsgSetButtons_ firstMsgSetButton_ lastMsgSetButton_ NIL; TakeDownWalnutViewers[]; ReportRope["Closing database and saving log ..."]; BEGIN CloseTransactions[doCommit ! DB.Failure, IO.Error => GOTO failure; -- IO.Error replaces FileIOAlpine.Failure UNWIND => CONTINUE ]; EXITS failure => IF DB.TransactionOf[segmentName] # NIL THEN DB.AbortTransaction[DB.TransactionOf[segmentName ! IO.Error => CONTINUE]]; END; IF walnutEventReg # NIL THEN ViewerEvents.UnRegisterEventProc[walnutEventReg, destroy]; walnutEventReg_ NIL; walnut_ NIL; -- don't let others try to use Report WalnutRetrieve.CloseConnection[]; -- NOP if no open connection lastStateReported_ unknown; mailNotifyLabel_ NIL; WalnutSendOps.UnregisterReporter[wtsOut]; wtsOut.Close[]; wtsOut_ NIL; mustQuitWalnut_ NIL; MBQueue.QueueClientAction[walnutQueue, ClosingWalnut, NIL]; v.inhibitDestroy_ FALSE; doingCheckpoint_ FALSE; ViewerOps.DestroyViewer[v]; END; WalnutReadMailFile: PUBLIC ENTRY Commander.CommandProc = BEGIN ENABLE UNWIND => NULL; h: IO.STREAM; fName, messageSet: ROPE; IF walnut = NIL THEN {NoWalnutReport[cmd, "read old mail files"]; RETURN}; IF doingCheckpoint THEN WAIT rollbackFinished; h_ IO.RIS[cmd.commandLine]; fName_ h.GetTokenRope[IO.IDProc ! IO.EndOfStream => GOTO noFile].token; messageSet_ h.GetTokenRope[IO.IDProc ! IO.EndOfStream => CONTINUE].token; ReadMailFile[fName, messageSet]; EXITS noFile => Report["No file specified"]; END; ReadMailFile: PUBLIC PROC[fName, msgSet: ROPE] = BEGIN mfp: LIST OF ROPE_ LIST[fName, IF msgSet=NIL THEN "Active" ELSE msgSet]; DoWaitCall[ReadMailProc, mfp]; END; WalnutExpunge: PUBLIC ENTRY Commander.CommandProc = BEGIN ENABLE UNWIND => NULL; IF walnut = NIL THEN {NoWalnutReport[cmd, "do Expunge"]; RETURN}; IF doingCheckpoint THEN WAIT rollbackFinished; DoWaitCall[ExpungeProc]; FinishCall[]; END; WalnutDump: PUBLIC ENTRY Commander.CommandProc = BEGIN ENABLE UNWIND => NULL; IF walnut = NIL THEN {NoWalnutReport[cmd, "do Dump"]; RETURN}; IF doingCheckpoint THEN WAIT rollbackFinished; DoWaitCall[DumpProc]; FinishCall[]; END; WalnutScavenge: PUBLIC ENTRY Commander.CommandProc = BEGIN ENABLE UNWIND => NULL; IF walnut = NIL THEN { segName, logName, captionName: ROPE; logIsAlp: BOOL; personalMailDB_ TRUE; [segName, logName, captionName, logIsAlp]_ CmdProcCall[NIL, cmd]; IF segName=NIL THEN RETURN; walnutSegmentFile_ segName; walnutLogName_ logName; logIsAlpineFile_ logIsAlp; WalnutDisplayerOps.msgName _ Rope.Concat[walnutSegmentFile, "!Msg!"]; WalnutDisplayerOps.msgSetName _ Rope.Concat[walnutSegmentFile, "!MsgSet!"]; StartUp[TRUE, walnutVersion]; IF walnut # NIL THEN ViewerOps.AddProp[walnut, $IconLabel, NIL]; RETURN }; IF doingCheckpoint THEN WAIT rollbackFinished; InternalChangeMenu[workingMenu]; DoWaitCall[ScavengeProc]; FinishCall[]; END; FinishCall: INTERNAL PROC = BEGIN Report["\n... Restarting"]; CloseTransactions[ TRUE ! DB.Failure, IO.Error => CONTINUE]; IF ~StartOrRestartWalnut[TRUE] THEN RETURN; Report[" ... done"]; END; GetNewMail: PUBLIC PROC = {[]_ WalnutNewMail[NIL]}; WalnutNewMail: PUBLIC ENTRY Commander.CommandProc = BEGIN ENABLE UNWIND => NULL; IF walnut = NIL THEN {NoWalnutReport[cmd, "retrieve new mail"]; RETURN}; IF doingCheckpoint THEN WAIT rollbackFinished; DoWaitCall[RetrieveNewMailProc, NIL] END; NoWalnutReport: INTERNAL PROC[cmd: Commander.Handle, msg: ROPE] = BEGIN r: ROPE_ Rope.Concat["Walnut must be running to ", msg]; IF cmd # NIL THEN cmd.out.PutRope[r] ELSE MessageWindow.Append[r] END; BuildWalnutControlWindow: INTERNAL PROC[captionName: ROPE] RETURNS[ok: BOOL] = BEGIN bt: Viewer; walnutWidth: INTEGER; transOK: BOOL_ TRUE; IF iconFilePathName=NIL THEN iconFilePathName_ "Walnut.icons"; -- try local one first IF walnutIcon = tool THEN { BEGIN ENABLE FS.Error => GOTO notFound; walnutIcon_ Icons.NewIconFromFile[iconFilePathName, 0]; EXITS notFound => BEGIN ENABLE FS.Error => { iconFilePathName_ NIL; CONTINUE}; remote: ROPE_ DefaultRemoteNames.Get[].current; iconFilePathName_ Rope.Concat[remote, "Walnut>Walnut.icons"]; walnutIcon _ Icons.NewIconFromFile[iconFilePathName, 0]; END; END; IF iconFilePathName#NIL THEN SetWalnutIcons[iconFilePathName]; }; walnut_ ViewerOps.CreateViewer[ flavor: $Container, info: [name: captionName, iconic: FALSE, column: right, scrollable: FALSE, icon: walnutIcon, openHeight: ViewerSpecs.openRightTopY/4]]; walnut.inhibitDestroy_ TRUE; walnutWidth_ IF walnut.column = right THEN ViewerSpecs.openRightWidth ELSE ViewerSpecs.openLeftWidth; ViewerOps.SetMenu[walnut, blankMenu]; mailNotifyLabel_ WalnutViewer.FirstLabel[name: InitialNotifyLabel, parent: walnut]; bt_ walnutRulerBefore_ WalnutViewer.MakeRuler[sib: mailNotifyLabel, h: 2]; walnutRulerAfter_ Rules.Create[ info: [parent: walnut, wy: bt.wy+bt.wh+14+3, ww: walnutWidth, wh: 1]]; Containers.ChildXBound[walnut, walnutRulerAfter]; walnutTS_ WalnutViewer.MakeTypescript[sib: walnutRulerAfter]; FS.SetKeep[tsLogName, 2 ! FS.Error => CONTINUE]; -- if tsLogName doesn't exist OpenTS[doRegister: FALSE]; TRUSTED BEGIN DO IF ~PrincOpsUtils.IsBound[WalnutSendOps.RegisterReporter] THEN {IF ~ContinueThisWalnut["WalnutSend"] THEN RETURN[FALSE] ELSE LOOP}; IF ~PrincOpsUtils.IsBound[AlpineWalnutCmds.CopyForExpunge] THEN {IF ~ContinueThisWalnut["AlpineUserImpls"] THEN RETURN[FALSE] ELSE LOOP}; IF ~PrincOpsUtils.IsBound[DB.DeclareSegment] THEN {IF ~ContinueThisWalnut["Cypress"] THEN RETURN[FALSE] ELSE LOOP}; EXIT; ENDLOOP; END; ViewerOps.SetMenu[walnut, workingMenu]; walnutEventReg_ ViewerEvents.RegisterEventProc[proc: QuitProc, event: destroy, filter: walnut]; WalnutDB.RegisterUpdatesPendingProc[SetWalnutUpdatesPending]; WalnutSendOps.RegisterReporter[wtsOut]; DB.Initialize[nCachePages: 256]; []_ WalnutVoice.CheckForWalnuthatch[]; RETURN[TRUE]; END; tsLogName: ROPE = "///Temp/Walnut/Walnut.TypescriptLog"; OpenTS: PUBLIC PROC[msg: ROPE_ NIL, doRegister: BOOL_ TRUE] = BEGIN IF wtsOut = NIL THEN { wtsOut_ ViewerIO.CreateViewerStreams[NIL, walnutTS, tsLogName].out; IF msg # NIL THEN wtsOut.PutRope[msg]; IF doRegister THEN WalnutSendOps.RegisterReporter[wtsOut]; }; END; CloseTS: PUBLIC PROC = BEGIN IF wtsOut # NIL THEN wtsOut.Close[]; WalnutSendOps.UnregisterReporter[wtsOut]; wtsOut_ NIL; END; ContinueThisWalnut: INTERNAL PROC[who: ROPE] RETURNS[reTry: BOOL]= BEGIN v: Viewer; IF InternalLoadBcd[who] THEN RETURN[TRUE]; Report["Click Continue to push on anyway, Quit to quit out of Walnut"]; IF InternalConfirm[startupConfirmMenu] THEN RETURN[TRUE]; mailNotifyLabel_ NIL; v_ walnut; walnut_ NIL; CloseTS[]; ViewerOps.DestroyViewer[v]; RETURN[FALSE] END; LoadBcdForWalnut: PUBLIC ENTRY PROC[who: ROPE] RETURNS[ok: BOOL] = { ENABLE UNWIND => NULL; RETURN[InternalLoadBcd[who]] }; InternalLoadBcd: INTERNAL PROC[who: ROPE] RETURNS[ok: BOOL] = BEGIN errMsg: ROPE; error: BOOL; [errMsg, error]_ CommandTool.Run[who]; Report[errMsg]; IF ~error THEN RETURN[errMsg=NIL]; IF errMsg.Find["unbound imports", 0, FALSE] >= 0 THEN RETURN[TRUE]; RETURN[FALSE] END; QueueExecCall: PUBLIC ENTRY PROC[proc: PROC[REF ANY], ra: REF ANY] = BEGIN ENABLE UNWIND => NULL; IF walnut # NIL THEN IF doingCheckpoint THEN WAIT rollbackFinished; MBQueue.QueueClientAction[walnutQueue, proc, ra]; END; ChangeWalnutMenu: PUBLIC ENTRY PROC[menu: Menus.Menu] = BEGIN ENABLE UNWIND => NULL; InternalChangeMenu[menu] END; InternalChangeMenu: PUBLIC INTERNAL PROC[menu: Menus.Menu] = BEGIN ENABLE UNWIND => NULL; oldCount, newCount: Menus.MenuLine; IF walnut = NIL THEN RETURN; oldCount_ Menus.GetNumberOfLines[walnut.menu]; newCount_ Menus.GetNumberOfLines[menu]; walnut.menu _ menu; IF oldCount # newCount THEN ViewerBLT.ChangeNumberOfLines[walnut, newCount]; ViewerOps.PaintViewer[walnut, menu]; END; UserConfirmed: PUBLIC ENTRY PROC RETURNS[BOOL] = BEGIN ENABLE UNWIND => NULL; RETURN[InternalConfirm[confirmMenu]]; END; InternalConfirm: PUBLIC INTERNAL PROC[m: Menus.Menu_ NIL] RETURNS[BOOL] = BEGIN InternalChangeMenu[IF m = NIL THEN confirmMenu ELSE m]; IF walnut.iconic THEN ViewerOps.BlinkIcon[walnut, 0] ELSE ViewerOps.BlinkIcon[walnutTS]; UNTIL userHasResponded DO WAIT responseSynch; ENDLOOP; userHasResponded_ FALSE; InternalChangeMenu[workingMenu]; RETURN[userConfirmed]; END; walnutMenu: PUBLIC Menus.Menu; workingMenu: PUBLIC Menus.Menu_ Menus.CreateMenu[]; confirmMenu: Menus.Menu_ Menus.CreateMenu[]; blankMenu: Menus.Menu_ Menus.CreateMenu[]; startupConfirmMenu: Menus.Menu_ Menus.CreateMenu[]; forceQuitMenu: PUBLIC Menus.Menu_ Menus.CreateMenu[]; maybeQuitMenu: PUBLIC Menus.Menu_ Menus.CreateMenu[]; scavMenu: PUBLIC Menus.Menu_ Menus.CreateMenu[]; mailDBMenu: PUBLIC Menus.Menu_ Menus.CreateMenu[]; readOnlyDBMenu: PUBLIC Menus.Menu_ Menus.CreateMenu[]; nonMailDBMenu: PUBLIC Menus.Menu_ Menus.CreateMenu[]; BuildWalnutMenu: PROC = { OPEN Menus; AppendMenuEntry[mailDBMenu, CreateEntry["NewForm", NewMsgProc]]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "NewMail", NewMailProc]]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Commit", MyCommitProc]]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "CloseAll", CloseAllProc]]; AppendMenuEntry[mailDBMenu, CreateEntry["MessageSetOps", MsgSetOpsProc]]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[q: walnutQueue, name: "Expunge", proc: MenuExpunge, guarded: TRUE], 1]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Delete", DeleteMsgSetsProc], 1]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "SizeOf", SizeOfMsgSetsProc], 1]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Print", PrintMsgSetsProc], 1]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Create", CreateMsgSetButtonProc], 1]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Archive", ArchiveButtonProc], 1]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Append", AppendButtonProc], 1]; Menus.ChangeNumberOfLines[mailDBMenu, 1]; AppendMenuEntry[readOnlyDBMenu, CreateEntry["NewForm", NewMsgProc]]; AppendMenuEntry[readOnlyDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "CloseAll", CloseAllProc]]; AppendMenuEntry[readOnlyDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "SizeOf", SizeOfMsgSetsProc]]; AppendMenuEntry[readOnlyDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Print", PrintMsgSetsProc]]; AppendMenuEntry[readOnlyDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Archive", ArchiveButtonProc], 1]; AppendMenuEntry[readOnlyDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Append", AppendButtonProc], 1]; AppendMenuEntry[nonMailDBMenu, CreateEntry["NewForm", NewMsgProc]]; AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Commit", MyCommitProc]]; AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "CloseAll", CloseAllProc]]; AppendMenuEntry[nonMailDBMenu, CreateEntry["MessageSetOps", MsgSetOpsProc]]; AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[q: walnutQueue, name: "Expunge", proc: MenuExpunge, guarded: TRUE], 1]; AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Delete", DeleteMsgSetsProc], 1]; AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "SizeOf", SizeOfMsgSetsProc], 1]; AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Print", PrintMsgSetsProc], 1]; AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Create", CreateMsgSetButtonProc], 1]; AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Archive", ArchiveButtonProc], 1]; AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Append", AppendButtonProc], 1]; Menus.ChangeNumberOfLines[nonMailDBMenu, 1]; AppendMenuEntry[workingMenu, CreateEntry["NewForm", NewMsgProc]]; AppendMenuEntry[confirmMenu, CreateEntry["NewForm", NewMsgProc]]; AppendMenuEntry[confirmMenu, CreateEntry["Confirm", WWConfirmProc]]; AppendMenuEntry[confirmMenu, CreateEntry["Deny", WWDenyProc]]; AppendMenuEntry[startupConfirmMenu, CreateEntry["Continue", WWConfirmProc]]; AppendMenuEntry[startupConfirmMenu, CreateEntry["Quit", WWDenyProc]]; AppendMenuEntry[forceQuitMenu, CreateEntry["Quit", WWConfirmProc]]; AppendMenuEntry[maybeQuitMenu, CreateEntry["Quit", WWConfirmProc]]; AppendMenuEntry[maybeQuitMenu, CreateEntry["Retry", WWDenyProc]]; AppendMenuEntry[scavMenu, CreateEntry["Scavenge", WWConfirmProc]]; AppendMenuEntry[scavMenu, CreateEntry["Quit", WWDenyProc]]; }; ChangeDBParams: TYPE = REF ChangeDBObject; ChangeDBObject: TYPE = MONITORED RECORD[segName, logName: ROPE, logIsAlp, alpNeeded: BOOL, cond: CONDITION]; ChangeDB: PROC[cdb: ChangeDBParams] = { DoWaitCall[ChangeDBProc, cdb] }; ChangeDatabase: PUBLIC ENTRY PROC[ra: REF ANY] = BEGIN ENABLE UNWIND => NULL; cdb: ChangeDBParams_ NARROW[ra]; BEGIN ENABLE UNWIND => { NOTIFY cdb.cond }; walnut.inhibitDestroy_ TRUE; InternalChangeMenu[workingMenu]; Report["\nClosing database on ", walnutSegmentFile]; TakeDownWalnutViewers[]; DestroyAllMsgSetButtons[]; FlushWQueue[]; CloseTransactions[TRUE ! DB.Failure, IO.Error, UNWIND => CONTINUE]; WalnutRetrieve.CloseConnection[]; lastStateReported_ unknown; walnutSegmentFile_ cdb.segName; walnutLogName_ cdb.logName; logIsAlpineFile_ cdb.logIsAlp; WalnutDisplayerOps.msgName _ Rope.Concat[walnutSegmentFile, "!Msg!"]; WalnutDisplayerOps.msgSetName _ Rope.Concat[walnutSegmentFile, "!MsgSet!"]; []_ StartOrRestartWalnut[TRUE]; Report["Database is now ", walnutSegmentFile]; NOTIFY cdb.cond; END; END; NewMsgProc: Menus.MenuProc = { WalnutSendOps.WalnutSendProc[fromExec: FALSE]}; MsgSetOpsProc: Menus.MenuProc = BEGIN v: Viewer = NARROW[parent]; count: NAT = Menus.GetNumberOfLines[v.menu]; newCount: NAT = IF count = 2 THEN 1 ELSE 2; Menus.ChangeNumberOfLines[v.menu, newCount]; ViewerBLT.ChangeNumberOfLines[v, newCount]; END; MenuExpunge: Menus.MenuProc = { EntryExpunge: ENTRY PROC = BEGIN ENABLE UNWIND => NULL; DoExpunge[doUpdates: TRUE, tailRewrite: mouseButton=red]; FinishCall[]; END; IF shift THEN { start: INT_ WalnutDBLog.GetStartExpungePos[]; len: INT_ WalnutLog.LogLength[FALSE]; dif: INT; Report[IO.PutFR[" The log file is %g bytes (%g pages) long", IO.int[len], IO.int[(len+511)/512]]]; Report[IO.PutFR[" An expunge would start at pos %g and read %g bytes (%g pages) of the log", IO.int[start], IO.int[dif_ (len - start)], IO.int[(dif+511)/512]]]; } ELSE EntryExpunge[]; }; DoExpunge: PUBLIC INTERNAL PROC[doUpdates, tailRewrite: BOOL] = BEGIN ok: BOOL_ TRUE; tempLogName: ROPE_ "Walnut.TempLog"; InternalChangeMenu[workingMenu]; TakeDownWalnutViewers[]; DestroyAllMsgSetButtons[]; WalnutLog.MarkWalnutTransaction[]; FlushWQueue[]; IF WalnutLogExtras.walnutTempLogName = NIL THEN SetTempLogName[]; Report[IO.PutFR["Dumping message database to %g at %g", IO.rope[WalnutLogExtras.walnutTempLogName], IO.time[]]]; BEGIN ENABLE ABORTED => {ok_ FALSE; CONTINUE}; ok_ WalnutLog.ExpungeMsgs [tempLog: NIL, doUpdates: doUpdates, tailRewrite: (tailRewrite AND enableTailRewrite)]; END; IF ~ok THEN { DB.AbortTransaction[ DB.TransactionOf[segmentName ! DB.Aborted, DB.Failure => CONTINUE]]; Report["Expunge failed or aborted; changes to database have been aborted"]; } ELSE Report[" Expunge complete"]; InternalChangeMenu[walnutMenu]; END; MyCommitProc: Menus.MenuProc = { ENABLE UNWIND => ChangeWalnutMenu[walnutMenu]; ChangeWalnutMenu[workingMenu]; WalnutLog.MarkWalnutTransaction[]; ChangeWalnutMenu[walnutMenu] }; NewMailProc: Menus.MenuProc = { ENABLE UNWIND => ChangeWalnutMenu[walnutMenu]; ChangeWalnutMenu[workingMenu]; RetrieveNewMail[]; ChangeWalnutMenu[walnutMenu] }; AutoNewMailProc: PROC = BEGIN ENABLE UNWIND => tryForNewMail_ TRUE; DoWaitCall[RetrieveNewMailProc]; tryForNewMail_ TRUE; END; RetrieveNewMail: PUBLIC ENTRY PROC = BEGIN ENABLE UNWIND => NULL; IF doingCheckpoint THEN WAIT rollbackFinished; InternalNewMail[]; END; InternalNewMail: PUBLIC PROC = BEGIN ENABLE UNWIND => tryForNewMail_ TRUE; thisUser: ROPE_ UserCredentials.Get[].name; IF ~Rope.Equal[thisUser, previousUser, FALSE] THEN { r: ROPE_ "User has changed"; Report[IO.PutFR ["******%g may not retrieve %g's new mail", IO.rope[thisUser], IO.rope[previousUser]]]; Report["You will be forced to quit out of Walnut; you should then Login to the exec"]; FlushWQueue[]; MBQueue.QueueClientAction[walnutQueue, QuitWalnut, r]; } ELSE { tryForNewMail_ FALSE; DoNewMail[]; tryForNewMail_ TRUE }; END; CloseAllProc: Menus.MenuProc = BEGIN msgSetList, msgList, queryList: LIST OF Viewer; [msgSetList, msgList, queryList]_ EnumWalnutViewers[TRUE]; FOR vL: LIST OF Viewer_ msgList, vL.rest UNTIL vL=NIL DO ViewerOps.DestroyViewer[vL.first]; ENDLOOP; FOR vL: LIST OF Viewer_ queryList, vL.rest UNTIL vL=NIL DO ViewerOps.CloseViewer[vL.first]; ENDLOOP; FOR vL: LIST OF Viewer_ msgSetList, vL.rest UNTIL vL=NIL DO ViewerOps.CloseViewer[vL.first]; ENDLOOP; MyCommitProc[parent]; ViewerOps.CloseViewer[walnut]; END; QuitProc: ENTRY ViewerEvents.EventProc = BEGIN IF walnutEventReg = NIL THEN RETURN[FALSE]; MBQueue.QueueClientAction[walnutQueue, QuitWalnut, NIL]; RETURN[TRUE]; END; WWDenyProc: ENTRY Menus.MenuProc = { ENABLE UNWIND => NULL; userConfirmed_ FALSE; userHasResponded_ TRUE; BROADCAST responseSynch }; WWConfirmProc: ENTRY Menus.MenuProc = { ENABLE UNWIND => NULL; userConfirmed_ TRUE; userHasResponded_ TRUE; BROADCAST responseSynch }; SetWalnutUpdatesPending: PUBLIC PROC[newVersion: BOOL] = BEGIN old: BOOL; IF walnut = NIL OR walnut.destroyed OR doAutoCommit THEN RETURN; old_ walnut.newVersion; IF newVersion#old THEN {walnut.newVersion_ newVersion; ViewerOps.PaintViewer[walnut, caption]}; END; CheckForAutoCommit: PUBLIC INTERNAL PROC = BEGIN IF doAutoCommit THEN WalnutLogExtras.QuietlyMarkTransaction[]; END; UncomittedUpdates: PUBLIC ENTRY PROC RETURNS[updatesPending: BOOL] = { ENABLE UNWIND => NULL; RETURN[IF walnut#NIL THEN walnut.newVersion ELSE FALSE]; }; Report: PUBLIC PROC[msg1, msg2, msg3, msg4: ROPE_ NIL] = { IF wtsOut = NIL THEN { IF msg1#NIL THEN MessageWindow.Append[msg1]; IF msg2#NIL THEN MessageWindow.Append[msg2]; IF msg3#NIL THEN MessageWindow.Append[msg3]; IF msg4#NIL THEN MessageWindow.Append[msg4]; RETURN }; IF msg1#NIL THEN wtsOut.PutRope[msg1]; IF msg2#NIL THEN wtsOut.PutRope[msg2]; IF msg3#NIL THEN wtsOut.PutRope[msg3]; IF msg4#NIL THEN wtsOut.PutRope[msg4]; wtsOut.PutChar[IO.CR]; }; ReportRope: PUBLIC PROC[msg1: ROPE] = { IF wtsOut # NIL THEN wtsOut.PutRope[msg1] ELSE MessageWindow.Append[msg1]; }; WatchMailBox: PUBLIC PROC[newState: GVRetrieve.MBXState] = BEGIN showTime: BOOL_ TRUE; status: ROPE; icon: Icons.IconFlavor_ walnutIcon; IF walnut = NIL THEN RETURN; IF walnut.destroyed THEN RETURN; IF newState = unknown THEN RETURN; IF (lastStateReported = notEmpty) AND (newState = someEmpty OR newState = allEmpty) THEN status_ "New mail was read" ELSE { SELECT newState FROM badName => {status_ "Your user name is invalid, please log in"; showTime_ FALSE}; badPwd => {status_ "Your password is invalid"; showTime_ FALSE}; cantAuth => {status_ "Can't check your credentials at this time"; showTime_ FALSE}; userOK => {status_ "Your credentials are OK"; showTime_ FALSE}; allDown => status_ "All of the mail servers are down"; someEmpty => status_ "All of the mail servers checked are empty"; allEmpty => status_ "There is no new mail"; notEmpty => {status_ "You have new mail"; icon_ newMailIcon}; ENDCASE => status_ "Bad State!"; }; lastStateReported _ newState; IF walnut.icon # icon THEN { walnut.icon_ icon; IF walnut.iconic THEN ViewerOps.PaintViewer[walnut, all]}; Labels.Set[mailNotifyLabel, IF showTime THEN Rope.Concat[status, IO.PutFR[" at %g", IO.time[]]] ELSE status]; IF newState = notEmpty AND autoNewMail AND tryForNewMail THEN { tryForNewMail_ FALSE; TRUSTED {Process.Detach[FORK AutoNewMailProc]}; }; END; SetAutoNewMailVars: ENTRY UserProfile.ProfileChangedProc = CHECKED BEGIN ENABLE UNWIND => NULL; autoNewMail_ UserProfile.Boolean[key: "Walnut.AutoNewMail", default: FALSE]; tryForNewMail_ autoNewMail; SetTempLogName[]; END; SetTempLogName: PROC = { WalnutLogExtras.walnutTempLogName_ Rope.Cat["///Walnut/", WalnutSendOps.userRName, "/Walnut.TempLog"]; }; walnutQueue_ MBQueue.Create[pushModel: FALSE]; -- queue for menu/button pushes BuildWalnutMenu[]; Commander.Register["Walnut", BuildWalnut, "For retrieving and sending mail"]; Commander.Register["WalnutScavenge", WalnutScavenge, "Rebuilds Mail database from log file"]; Commander.Register["WalnutOldMailReader", WalnutReadMailFile, "Reads Laurel, Hardy or Archive files into Mail database"]; Commander.Register["WalnutExpunge", WalnutExpunge, "Expunges deleted messages"]; Commander.Register["WalnutDump", WalnutDump, "Writes an expunged log file on Walnut.TempLog; does not change database"]; Commander.Register["WalnutNewMail", WalnutNewMail, "Retrieves new mail"]; UserProfile.CallWhenProfileChanges[SetAutoNewMailVars]; END. jFile: WalnutWindowImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Contents: Top level Viewer for Walnut; initializes database & displays control window created February, 1981 by Willie-Sue & Rick Last edit by: Willie-Sue on: August 28, 1984 11:44:43 am PDT Donahue, July 26, 1983 9:13 am Last Edited by: Woosh, August 23, 1984 2:19:53 pm PDT Walnut Viewers types and global data walnutVersion: ROPE_ "WalnutWithVoice 4.4.101"; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * if doAutoCommit is true, then don't show Commit on the menus clean up after Walnut make separate proc so callable by program * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ------------------------- menu for personal mail database now for the second line menu for read only database menu for nonMail writeable database now for the second line Create a new blank form in a viewer for user to send msg with. ********************************************************************** can't be an entry proc ********************************************************************** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This is called when the condition of the mailbox changes -------------------------- Ê!k˜šœ™Jšœ Ïmœ1™<—J˜JšœU™UJ˜Jšœ+™+šœ ™ Jšœ.™.Jšœ™J™5J˜—šÏk ˜ Jšœžœ˜(Jšœžœ˜Jšœ žœ!˜0Jšœ žœ˜J˜ Jšœžœ˜šžœžœB˜JJ˜—Jšœžœ˜Jšžœžœ˜Jšœ žœ ˜Jšœžœ˜*Jšžœ˜Jšœžœ˜*J˜Jšœžœ ˜Jšœžœ ˜Jšœžœ ˜J˜Jšœžœ ˜Jšœžœ˜Jšœ žœ=˜NJšœ žœ˜%Jšœžœ ˜Jšœ žœH˜ZJ˜ Jšœ žœ/˜@Jšœ žœ˜%šœžœ<˜VJ˜&—J˜Jšœ žœ<˜JJšœ žœ˜'Jšœžœ˜/Jšœ žœ1˜@Jšœžœ=˜Ršœ žœ8˜JJ˜CJ˜5—Jšœžœ˜'JšœžœC˜VJšœ žœ:˜LJšœ žœ˜(šœ žœD˜VJ˜šž˜Jšœžœ˜Jšœ žœ˜%Jšœžœ˜Jšœžœ˜Jšœžœ˜'J˜Jšœžœ˜J˜šžœž˜˜IJ˜CJšžœžœ'˜AJšžœžœ'˜AJ˜—J˜Jšž˜˜+J˜)Jšœžœ˜J˜;J˜——J˜?Jšœžœ˜šžœžœž˜/šœžœ˜ J˜Sšžœžœžœ-˜>Jšžœ˜—Jšœ žœ˜ —J˜——Jšžœ˜J˜—š  œžœžœžœžœ˜@šž˜JšœGžœ˜Mšœ˜Jšœ;žœ˜A—Jšœ˜J˜Jšžœ(žœžœ˜6—šœ<™<šžœž˜šž˜J˜šžœ.žœž˜8Jšœ(žœ˜-—šžœ1žœž˜;Jšœ+žœ˜0——Jšž˜—šœž˜šž˜šžœ)žœž˜3˜!J˜C——šžœ,žœž˜6˜$J˜C———Jšžœ˜—Jšžœžœžœžœ˜:J˜JšœŸ˜#J˜Jšžœžœ˜2J˜—Jšžœ˜J˜—š  œžœžœžœ žœ˜7Jšœ™šž˜J˜Jšœžœ˜J˜J˜J˜ J˜?Jšœ<žœ˜@J˜J˜J˜2˜Jšž˜˜Jšžœ žœ žœ Ÿ)˜PJšžœžœ˜—šž˜šœ žœžœžœž˜6Jšžœžœžœ žœ˜J———Jšžœ˜J˜šžœžœž˜J˜:—Jšœžœ˜J˜JšœžœŸ%˜3Jšœ#Ÿ˜?J˜Jšœžœ˜J˜)J˜Jšœžœ˜ šœžœ˜Jšœ6žœ˜;Jšœžœ˜Jšœžœ˜J˜——Jšžœ˜J˜J˜—š œžœžœ˜8šžœžœžœžœ˜Jšœžœžœ˜ Jšœžœ˜Jšžœ žœžœ.žœ˜JJšžœžœžœ˜.Jšœžœžœ˜Jšœžœ žœžœ˜GJšœžœ žœžœ˜IJ˜ J˜šž˜J˜&——Jšžœ˜J˜—Jšœ)™)š  œžœžœžœ˜0šž˜Jšœžœžœžœžœžœžœžœ žœ ˜HJ˜—Jšžœ˜J˜—š  œžœžœ˜3šžœžœžœžœ˜Jšžœ žœžœ%žœ˜AJšžœžœžœ˜.J˜J˜ —Jšžœ˜J˜—š  œžœžœ˜0šžœžœžœžœ˜šžœ žœžœ"žœ˜>Jšžœžœžœ˜.—J˜J˜ —Jšžœ˜J˜—š œžœžœ˜4šžœžœžœžœ˜Jšžœ žœž˜šœ!žœ˜&Jšœ žœ˜Jšœžœ˜Jšœ7žœ˜AJšžœ žœžœžœ˜J˜J˜J˜J˜EJ˜KJšœžœ˜Jšžœ žœžœ'žœ˜@Jšž˜J˜J˜Jšžœžœžœ˜.J˜ —J˜J˜ —Jšžœ˜J˜—š  œžœžœ˜šž˜J˜š œžœžœ žœ žœ˜———J˜˜˜J˜šœ"žœžœ˜JJ˜<——Jšœžœ˜šœ žœžœž˜JJ˜J˜—J˜%J˜SJ˜J˜JJ˜˜J˜F—J˜1J˜J˜=Jšžœžœ žœŸ˜OJšœžœ˜˜šž˜Jšž˜šž˜šžœ8ž˜>Jš œžœ#žœžœžœžœžœ˜Dšžœ9ž˜?Jš œžœ(žœžœžœžœžœ˜I——šžœžœž˜1Jš œžœ žœžœžœžœžœ˜A——Jšžœ˜Jšžœ˜—Jšžœ˜J˜——J˜'˜J˜O—J˜=˜'J˜—Jšžœ˜ J˜&Jšžœžœ˜ —Jšžœ˜J˜—Jšœ žœ)˜8J˜š œžœžœžœžœžœžœ˜>šž˜šžœ žœž˜šœ'žœ˜EJšžœžœžœ˜&Jšžœ žœ(˜:—J˜——Jšžœ˜J˜—š œžœžœ˜šž˜Jšžœ žœžœ˜$J˜)Jšœžœ˜ —Jšžœ˜J˜—š  œžœžœžœžœžœ˜Bšž˜J˜ J˜Jšžœžœžœžœ˜*J˜GJšžœ%žœžœžœ˜9Jšœžœ˜J˜ Jšœžœ˜ J˜ J˜Jšžœžœ˜ —Jšžœ˜J˜—š œžœžœžœžœžœžœ˜Bšœžœžœžœ˜Jšžœ˜—J˜J˜—š  œžœžœžœžœžœ˜=šž˜Jšœžœ˜ Jšœžœ˜ J˜J˜&J˜J˜Jšžœžœžœžœ˜"Jš žœ#žœžœžœžœ˜CJšžœžœ˜ —Jšžœ˜J˜—š  œžœžœžœžœžœžœžœžœ˜Dšžœžœžœžœ˜Jš žœ žœžœžœžœžœ˜CJ˜1—Jšžœ˜J˜—JšœO™Oš œžœžœžœ˜7šžœžœžœžœ˜Jšœ˜—Jšžœ˜J˜—š œžœžœžœ˜<šžœžœžœžœ˜˜#Jšžœ žœžœžœ˜J˜.J˜'J˜šžœž˜J˜0—J˜$——Jšžœ˜J˜J˜—š   œžœžœžœžœžœ˜0šžœžœžœžœ˜Jšžœ˜%—Jšžœ˜J˜—š œžœžœžœžœžœžœ˜Išž˜Jš œžœžœžœ žœ˜7Jšžœžœ žœ˜XJšžœžœžœžœ˜6Jšœžœ˜J˜ Jšžœ˜—Jšžœ˜—J˜Jšœ™Jšœ žœ ˜Jšœ žœ ˜3J˜,J˜*J˜3Jšœžœ ˜5Jšœžœ ˜5Jšœ žœ ˜0J˜Jšœ žœ ˜2Jšœžœ ˜6Jšœžœ ˜5J˜š œžœ˜Jšœžœ˜ J˜—šœ™J˜@˜J˜C—˜J˜C˜J˜E—J˜I——šœ™˜˜PJšœ žœ˜—˜J˜K—˜J˜K—˜J˜I—˜J˜P—˜J˜L—˜J˜J——˜J˜)—J˜šœ™J˜D˜J˜E—˜J˜H—˜J˜F—˜J˜L—˜J˜J—J˜—šœ#™#J˜C˜J˜C˜J˜E—J˜L——J™šœ™˜˜PJšœ žœ˜——˜J˜K—˜J˜K—˜J˜I—˜J˜P—˜J˜L—˜J˜J——˜J˜,—˜J˜AJ˜J˜AJ˜DJ˜>—˜J˜LJ˜E—˜J˜CJ˜J˜CJ˜AJ˜J˜BJ˜;—J˜J˜—Jšœžœžœ˜*šœžœ˜Jš ž œžœžœžœž œ˜UJ˜—Jš œžœ:˜HJ˜š  œžœžœžœžœžœ˜0šžœžœžœžœ˜Jšœžœ˜ Jšžœžœžœžœ ˜+Jšœžœ˜J˜ J˜4J˜J˜J˜Jš œžœžœ žœžœžœ˜CJ˜!J˜J˜J˜J˜J˜EJ˜KJšœžœ˜J˜.Jšžœ ˜—Jšžœ˜Jšžœ˜J˜—š  œ<žœ˜NJšœ?™?J˜—š  œ˜šž˜Jšœ žœ ˜Jšœžœ"˜,Jš œ žœžœ žœžœ˜+J˜,J˜+—Jšžœ˜J˜—š  œ˜šœ  œžœžœ˜šžœžœžœžœ˜Jšœžœ ˜9J˜ —Jšžœ˜šžœž˜ šœ žœ#˜/Jšœžœžœ˜%Jšœžœ˜ šœžœ5˜>Jšžœ žœ˜%—šœžœU˜^Jšžœ žœžœ˜C——Jšœ˜—Jšžœ˜—J˜J˜—š   œžœžœžœžœ˜@šž˜Jšœžœžœ˜Jšœ žœ˜$J˜J˜ J˜J˜J˜"J˜Jšžœ%žœžœ˜Ašœžœ.˜7Jšžœ*žœ ˜8—J˜š žœžœžœ žœžœ˜.˜Jšœ žœ2žœ˜WJšžœ˜J˜——šžœž˜ šœžœ˜Jšžœžœ žœ žœ˜DJ˜K—˜Jšžœ˜!——J˜—Jšžœ˜J˜—š  œ˜šœžœžœ!˜0J˜J˜"J˜—J˜J˜—š  œ˜šœžœžœ!˜0J˜J˜J˜—J˜J˜—š œžœ˜šžœžœžœžœ˜+J˜ Jšœžœ˜—Jšžœ˜J˜—š œžœžœžœ˜$šžœžœžœžœ˜Jšžœžœžœ˜.J˜—Jšžœ˜J˜—š œžœžœ˜šžœžœžœžœ˜+Jšœ žœ˜+šžœ%žœž˜2šœžœ˜šœžœ˜Jšœ,žœžœ˜W—J˜VJ˜J˜6—J˜šžœ˜šœžœ˜J˜ Jšœž˜—J˜———Jšžœ˜J˜—š  œ˜šž˜Jšœ žœžœ˜/Jšœ4žœ˜:š žœžœžœžœžœž˜8Jšœ#žœ˜+—š žœžœžœžœžœž˜:Jšœ!žœ˜)—š žœžœžœžœžœž˜;Jšœ!žœ˜)—J˜J˜—Jšžœ˜J˜—š œžœ˜(šž˜Jš žœžœžœžœžœ˜+Jšœ3žœ˜8Jšžœžœ˜ —Jšžœ˜J˜—š  œžœ˜"šœžœžœžœ˜Jšœžœ˜Jšœžœ˜Jšž œ˜—˜J˜——š  œžœ˜%šœžœžœžœ˜Jšœžœ˜Jšœžœ˜Jšž œ˜—J˜—J˜J˜JšœF™FJšœ™š œžœžœ žœ˜8šž˜Jšœžœ˜ Jš žœ žœžœžœžœžœ˜@J˜šžœž˜J˜H——Jšžœ˜—J˜š œžœžœžœ˜*šž˜Jšžœžœ*˜>—Jšžœ˜—J˜š  œžœžœžœžœžœ˜Dšœžœžœžœ˜Jš žœžœžœžœžœžœ˜8—˜J˜——JšœF™Fš  œžœžœžœžœ˜8šœžœ žœž˜šœžœžœžœ˜.Jšžœžœžœ˜,Jšžœžœžœ˜,—Jšžœžœžœ˜,Jšž˜J˜Jšžœžœžœ˜&Jšžœžœžœ˜&Jšžœžœžœ˜&Jšžœžœžœ˜&Jšœžœžœ˜—J˜J˜—š  œžœžœžœ˜%š œžœ žœžœžœ˜LJ˜J˜——JšœO™OJš  œžœžœ!˜:šœ8™8Jšž˜Jšœ žœžœ˜Jšœžœ˜ J˜#Jšžœ žœžœžœ˜Jšžœžœžœ˜ Jšžœžœžœ˜"šžœ žœžœž˜XJ˜šž˜šœžœ ž˜JšœLžœ˜SJšœ<žœ˜CJšœMžœ˜TJšœ;žœ˜BJ˜8J˜AJ˜,J˜>Jšžœ˜"—˜J˜šžœž˜Jšœžœžœ%˜O—J˜—š žœ žœžœžœ žœ ˜Qšžœžœ žœž˜=šœžœ˜Jšžœžœ˜/J˜—————Jšžœ˜J˜—š œžœ"ž˜Bšžœžœžœžœ˜JšœEžœ˜LJ˜Jšœ˜—Jšžœ˜—J˜š œžœ˜šœ$˜$JšœC˜C—J˜—Jšœ™J˜Jšœ'žœŸ˜OJ˜J˜J˜MJ˜]˜)J˜O—J˜PJ˜J˜xJ˜J˜IJ˜J˜7J˜Jšžœ˜J˜J˜—…—rð™Å