DIRECTORY Ascii USING [CR, SP, TAB], Buttons USING [ButtonProc, Create], Commander USING [CommandProc, Handle, Register], CommandTool USING [DoCommand], Containers USING [ChildXBound], Convert USING [Error, IntFromRope, RopeFromInt], FileNames USING [CurrentWorkingDirectory], FS USING [ComponentPositions, Delete, EnumerateForNames, Error, ExpandName, NameProc], Icons USING [DrawIcon, IconFlavor, NewIconFromFile], Imager USING [DoSaveAll, MaskRectangleI, SetColor], ImagerBackdoor USING [invert], IO USING [CharClass, EndOf, EndOfStream, GetLineRope, GetTokenRope, IDProc, PutChar, PutRope, RIS, STREAM], Labels USING [Create, Set], Menus USING [CreateEntry, CreateMenu, GetNumberOfLines, InsertMenuEntry, Menu, MenuEntry, MenuProc], PieViewers USING [Create, Set], PressPrinter USING [Abort, CurrentProgress, CurrentState, CurrentStateMessage, Handle, IsAPressFile, ProgressProc, SendPressFile, State], PressScreen USING [NewPressName, PressScreen, Side], PrincOps USING [], PrincOpsUtils USING [], Process USING [CheckForAbort, Detach, Pause, priorityBackground, SecondsToTicks, SetPriority, Ticks], PseudoCursors USING [Create], Rope USING [Cat, Concat, Equal, Fetch, Find, IsEmpty, Length, ROPE, Substr], RuntimeError USING [UNCAUGHT], SafeStorage USING [ReclaimCollectibleObjects], TSFormat USING [FormatOneOutputFile], TSGlue USING [], TSOutput USING [Handle], TSViewer USING [Tool, ToolRec], UserCredentials USING [Get], UserProfile USING [Boolean, Token], ViewerClasses USING [AdjustProc, PaintProc, Viewer, ViewerClass, ViewerClassRec], ViewerOps USING [AddProp, CreateViewer, DestroyViewer, EnumerateViewers, EnumProc, EstablishViewerPosition, FetchProp, FetchViewerClass, PaintViewer, RegisterViewerClass, SetMenu, SetOpenHeight], ViewerPrivate USING [selectedIcon], ViewerSpecs USING [captionHeight, iconHeight, iconWidth, menuHeight, scrollBarW, windowBorderSize], ViewerTools USING [GetContents, GetSelectedViewer, InhibitUserEdits, MakeNewTextViewer, SetContents, SetSelection]; TSetterStarter: CEDAR MONITOR IMPORTS Buttons, Commander, CommandTool, Containers, Convert, FileNames, FS, Imager, ImagerBackdoor, Icons, IO, Labels, Menus, PieViewers, PressPrinter, PressScreen, Process, PseudoCursors, Rope, RuntimeError, SafeStorage, TSFormat, UserCredentials, UserProfile, ViewerOps, ViewerPrivate, ViewerSpecs, ViewerTools EXPORTS TSViewer = BEGIN OPEN TSViewer; ROPE: TYPE = Rope.ROPE; indent: INTEGER = 4; baseline: INTEGER = 16; rightIcon: Icons.IconFlavor _ Icons.NewIconFromFile["TSetter.icons", 0]; leftIcon: Icons.IconFlavor _ Icons.NewIconFromFile["TSetter.icons", 2]; NewButton: Menus.MenuProc = { IF mouseButton=yellow THEN ShowMessage[NARROW[clientData], doc[New]] ELSE { selectedViewer: ViewerClasses.Viewer _ ViewerTools.GetSelectedViewer[]; server: ROPE _ NIL; server _ IF selectedViewer = NIL OR selectedViewer.class.get = NIL THEN NIL ELSE NARROW[selectedViewer.class.get[selectedViewer, $SelChars ! RuntimeError.UNCAUGHT => CONTINUE]]; IF server.Length < 2 THEN server _ NIL; [] _ NewTool[server]; }; }; doc: REF ARRAY MenuCode OF ROPE _ InitDoc[]; MenuCode: TYPE = {New, RightScreen, Screen, LeftScreen, All, Print, Get, StopSending, Stop, Pause}; InitDoc: PROCEDURE RETURNS [d: REF ARRAY MenuCode OF ROPE] = { d _ NEW[ARRAY MenuCode OF ROPE]; d[New] _ "New: Create a new typesetter tool for selected server."; d[RightScreen] _ ">: Print the right side of the screen."; d[Screen] _ "Screen: Print the whole screen."; d[LeftScreen] _ "<: Print the left side of the screen."; d[All] _ "All: Print all the documents in one press file."; d[Print] _ "Print: Print the documents named above."; d[Get] _ "Get: Add selected documents to the document queue."; d[StopSending] _ "StopSending: Abort transmission to the printer."; d[Stop] _ "Stop: Stop typesetting as soon as possible."; d[Pause] _ "Pause: Stop typesetting at end of current document."; }; NewTool: PUBLIC ENTRY PROCEDURE [server: ROPE, feedBack: IO.STREAM _ NIL] RETURNS [Tool] = { ENABLE UNWIND => NULL; data: Tool _ NEW[ToolRec _ [stop: FALSE, feedBack: feedBack]]; curY: INTEGER _ indent/2; NextY: PROCEDURE RETURNS [y:NAT] = {y _ curY _ curY+baseline}; container: ViewerClasses.Viewer _ ViewerOps.CreateViewer[ flavor: $TSetter, info: [name: IF server.Length = 0 THEN "TSetter" ELSE server, column: right, scrollable: FALSE ], paint: FALSE ]; menu: Menus.Menu _ Menus.CreateMenu[]; InsertMenuEntry: PROCEDURE [name: ROPE, proc: Menus.MenuProc, fork: BOOL _ FALSE, row: INTEGER _ 0, copy: BOOL _ FALSE, documentation: ROPE _ NIL, guarded: BOOL _ FALSE] = { menuEntry: Menus.MenuEntry ~ Menus.CreateEntry[name: name, proc: proc, clientData: data, documentation: documentation, fork: fork, guarded: guarded]; Menus.InsertMenuEntry[menu, menuEntry]; }; InsertMenuEntry[name: "New", proc: NewButton, fork: FALSE, documentation: doc[New]]; InsertMenuEntry[name: ">", proc: RightScreenButton, fork: TRUE, documentation: doc[RightScreen]]; InsertMenuEntry[name: "Screen", proc: ScreenButton, fork: TRUE, documentation: doc[Screen]]; InsertMenuEntry[name: "<", proc: LeftScreenButton, fork: TRUE, documentation: doc[LeftScreen]]; InsertMenuEntry[name: "All", proc: AllButton, fork: FALSE, documentation: doc[All]]; InsertMenuEntry[name: "Print", proc: PrintButton, fork: FALSE, documentation: doc[Print]]; InsertMenuEntry[name: "Get", proc: GetSelectionButton, fork: FALSE, documentation: doc[Get]]; InsertMenuEntry[name: "StopSending", proc: StopSendingButton, fork: FALSE, documentation: doc[StopSending]]; InsertMenuEntry[name: "Stop", proc: StopButton, fork: FALSE, documentation: doc[Stop] ]; InsertMenuEntry[name: "Pause", proc: PauseButton, fork: FALSE, documentation: doc[Pause]]; ViewerOps.SetMenu[container, menu]; data.nameButton _ Buttons.Create[ info:[name: "Documents: ", wx: indent, wy: curY, parent: container, border: FALSE], clientData: data, proc: NameButton, fork: FALSE, paint: FALSE, documentation: "Select the document name window. The right button empties it first." ]; PlaceChild[data.nameButton, 0, 0, TRUE]; data.nameBox _ ViewerTools.MakeNewTextViewer[ info:[wx: data.nameButton.wx + data.nameButton.ww, wy: curY+1, ww: 4*72, wh: data.nameButton.wh, parent: container, scrollable: TRUE, border: FALSE], paint: FALSE ]; PlaceChild[data.nameBox, 0, 0, FALSE]; Containers.ChildXBound[container, data.nameBox]; -- Let the text box grow to the right data.pie _ PieViewers.Create[parent: container, x: indent, y: NextY[]]; PlaceChild[data.pie, 1, 0, TRUE]; data.miniDisplay _ PseudoCursors.Create[parent: container, x: indent+20, y: curY]; PlaceChild[data.miniDisplay, 1, 0, TRUE]; data.messageBox _ ViewerTools.MakeNewTextViewer[ info: [wx: indent + 40, wy: curY, ww: 350, wh: 16, parent: container, scrollable: TRUE, border: TRUE], paint: FALSE ]; PlaceChild[data.messageBox, 1, 0, FALSE]; ViewerTools.InhibitUserEdits[data.messageBox]; data.serverName _ server; data.serverPie _ PieViewers.Create[parent: container, x: indent, y: NextY[], total: 1.0]; PlaceChild[data.serverPie, 2, 0, TRUE]; data.serverMsg _ ViewerTools.MakeNewTextViewer[ info: [wx: indent + 40, wy: curY, ww: 350, wh: 16, parent: container, scrollable: TRUE, border: TRUE], paint: FALSE ]; PlaceChild[data.serverMsg, 2, 0, FALSE]; ViewerTools.InhibitUserEdits[data.serverMsg]; data.copiesBox _ Buttons.Create[ info:[name: "Copies: ", wx: indent, wy: NextY[], parent: container, border: FALSE], clientData: data, proc: CopiesButton, fork: FALSE, paint: FALSE, documentation: "Set the number of copies. Gets reset to 1 after each file is sent." ]; PlaceChild[data.copiesBox, 3, 0, TRUE]; data.copiesBox _ ViewerTools.MakeNewTextViewer[ info:[wx: data.copiesBox.wx + data.copiesBox.ww, wy: curY+1, ww: 4*72, wh: data.nameButton.wh, parent: container, scrollable: FALSE, border: FALSE], paint: FALSE ]; PlaceChild[data.copiesBox, 3, 0, TRUE]; data.tempPressLabel _ Buttons.Create[ info:[name: "Temporary Press Files: ", wx: indent , wy: NextY[], parent: container, border: FALSE], clientData: data, proc: TempPressButton, fork: FALSE, paint: FALSE ]; PlaceChild[data.tempPressLabel, 3, 1, TRUE]; data.tempPressLabel _ Labels.Create[ info:[name: "FALSE", wx: data.tempPressLabel.wx+data.tempPressLabel.ww , wy: curY, parent: container, border: FALSE], paint: FALSE ]; PlaceChild[data.tempPressLabel, 3, 1, TRUE]; TempPress[data, UserProfile.Boolean["Hardcopy.TemporaryPressFiles"]]; Containers.ChildXBound[container, data.copiesBox]; ViewerTools.SetContents[data.copiesBox, "1"]; ViewerOps.SetOpenHeight[container, curY+indent/2+baseline]; ViewerOps.PaintViewer[container, all]; ShowMessage[data, "Ready"]; RETURN [data] }; PositionInfoRec: TYPE = RECORD [ nVar: NAT, -- number of stretchy children above this one nFixed: NAT, -- number of fixed-height children above this one fixed: BOOLEAN -- true if this child is fixed in height ]; PlaceChild: PROCEDURE [viewer: ViewerClasses.Viewer, nVar, nFixed: NAT, fixed: BOOLEAN _ TRUE] = { ViewerOps.AddProp[viewer, $TSViewerPositionInfo, NEW[PositionInfoRec _ [nVar, nFixed, fixed]]]; }; SetViewerPosition: PROCEDURE [viewer: ViewerClasses.Viewer, x,y,w,h: INTEGER] = { OPEN viewer; vbs: INTEGER = IF border THEN ViewerSpecs.windowBorderSize ELSE 0; wx _ x; wy _ y; ww _ w; wh _ h; ch _ wh - (vbs+vbs) - (IF column=static OR parent#NIL THEN 0 ELSE ViewerSpecs.captionHeight); IF menu#NIL THEN ch _ ch - (Menus.GetNumberOfLines[menu]*ViewerSpecs.menuHeight); cx _ wx + vbs + (IF scrollable THEN ViewerSpecs.scrollBarW ELSE 0); cy _ wy + vbs; cw _ ww - (cx-wx) - vbs; }; TSViewerAdjust: ViewerClasses.AdjustProc = { varbaseline: NAT _ MAX[baseline, (self.ch-indent-2*baseline)/3]; FOR v: ViewerClasses.Viewer _ self.child, v.sibling UNTIL v=NIL DO WITH ViewerOps.FetchProp[v, $TSViewerPositionInfo] SELECT FROM positionInfo: REF PositionInfoRec => { ViewerOps.EstablishViewerPosition[viewer: v, x: v.wx, y: varbaseline*positionInfo.nVar + baseline*positionInfo.nFixed + indent/2, w: v.ww, h: IF positionInfo.fixed THEN baseline ELSE varbaseline ]; }; ENDCASE => NULL; ENDLOOP; }; TSViewerPaint: ViewerClasses.PaintProc = { drawIcon: PROC ~ { Icons.DrawIcon[flavor: IF self.column = left THEN leftIcon ELSE rightIcon, context: context, x: 0, y: 0, label: self.name]; }; IF self.iconic THEN { Imager.DoSaveAll[context, drawIcon]; IF ViewerPrivate.selectedIcon=self THEN { Imager.SetColor[context, ImagerBackdoor.invert]; Imager.MaskRectangleI[context, 0, 0, ViewerSpecs.iconWidth, ViewerSpecs.iconHeight]; } }; }; ShowMessage: PROCEDURE [tool: Tool, msg: ROPE] = { tool.messageLog _ msg _ tool.messageLog.Cat["\n", msg]; ViewerTools.SetContents[tool.messageBox, msg]; [] _ tool.messageBox.class.scroll[tool.messageBox, thumb, 100]; }; StopButton: Menus.MenuProc = { tool: Tool _ NARROW[clientData]; tool.selfDestruct _ FALSE; IF mouseButton=yellow THEN ShowMessage[tool, doc[Stop]] ELSE Stop[tool] }; Stop: PUBLIC ENTRY PROCEDURE [tool: Tool] = {ENABLE UNWIND => NULL; tool.stop _ TRUE; }; PauseButton: Menus.MenuProc = { tool: Tool _ NARROW[clientData]; tool.selfDestruct _ FALSE; IF mouseButton=yellow THEN ShowMessage[tool, doc[Pause]] ELSE Pause[tool] }; Pause: PUBLIC ENTRY PROCEDURE [tool: Tool] = {ENABLE UNWIND => NULL; tool.pause _ TRUE; }; StopSendingButton: Menus.MenuProc = { tool: Tool _ NARROW[clientData]; tool.selfDestruct _ FALSE; IF mouseButton=yellow THEN ShowMessage[tool, doc[StopSending]] ELSE StopSending[tool] }; StopSending: PUBLIC ENTRY PROCEDURE [tool: Tool] = {ENABLE UNWIND => NULL; tool.stopSending _ TRUE; }; NameButton: ENTRY Buttons.ButtonProc = {ENABLE UNWIND => NULL; tool: Tool _ NARROW[clientData]; tool.selfDestruct _ FALSE; IF mouseButton = blue THEN ViewerTools.SetContents[tool.nameBox, ""]; ViewerTools.SetSelection[tool.nameBox]; }; Copies: PUBLIC PROCEDURE [tool: Tool, copies: NAT] = { ViewerTools.SetContents[tool.copiesBox, Convert.RopeFromInt[copies]]; }; CopiesButton: Buttons.ButtonProc = { tool: Tool _ NARROW[clientData]; tool.selfDestruct _ FALSE; IF mouseButton = blue THEN ViewerTools.SetContents[tool.copiesBox, ""]; ViewerTools.SetSelection[tool.copiesBox]; }; TempPress: PUBLIC PROCEDURE [tool: Tool, temporaryPressFiles: BOOLEAN] = { tool.tempPress _ temporaryPressFiles; Labels.Set[tool.tempPressLabel, IF tool.tempPress THEN "TRUE" ELSE "FALSE"]; }; TempPressButton: Buttons.ButtonProc = { tool: Tool _ NARROW[clientData]; tool.tempPress _ NOT tool.tempPress; tool.selfDestruct _ FALSE; Labels.Set[tool.tempPressLabel, IF tool.tempPress THEN "TRUE" ELSE "FALSE"]; }; GetNames: ENTRY PROCEDURE [tool: Tool] RETURNS [gotIt: BOOLEAN _ TRUE, names: LIST OF ROPE _ NIL] = { ENABLE UNWIND => NULL; rope: ROPE ~ ViewerTools.GetContents[tool.nameBox]; length: NAT ~ rope.Length; i, start: NAT _ 0; c: CHAR; currentName: LIST OF ROPE; IF tool.pause OR tool.stop THEN {tool.process _ NIL; NOTIFY tool.idle; RETURN[FALSE, NIL]}; names _ CONS[NIL, NIL]; currentName _ names; DO WHILE i=length OR (c _ rope.Fetch[i]) = Ascii.SP OR c=Ascii.CR OR c=Ascii.TAB OR c=', OR c='; DO i _ i+1 ENDLOOP; IF i-start <= 0 THEN EXIT; currentName.rest _ CONS[rope.Substr[start: start, len: i-start], NIL]; currentName _ currentName.rest; WHILE i= length OR ~tool.singleOutputFile THEN EXIT; ENDLOOP; ViewerTools.SetContents[tool.nameBox, rope.Substr[start: i]]; names _ names.rest; IF names = NIL OR names.first.IsEmpty[] THEN { tool.process _ NIL; NOTIFY tool.idle; RETURN[FALSE, NIL]; }; }; FindFileViewer: PROC[file: Rope.ROPE] RETURNS[viewer: ViewerClasses.Viewer] = { FindViewer: ViewerOps.EnumProc = { IF Rope.Find[v.file, file, 0, FALSE] = 0 THEN {viewer _ v; RETURN[FALSE]} ELSE RETURN[TRUE]; }; ViewerOps.EnumerateViewers[FindViewer]; }; WaitUntilSaved: PROC [fileName: Rope.ROPE, tool: Tool] = { viewer: ViewerClasses.Viewer _ NIL; viewer _ FindFileViewer[fileName]; IF viewer # NIL AND viewer.newVersion THEN { SomeSaveInProgress: PROC RETURNS[ans: BOOL _ FALSE] = CHECKED { v: ViewerClasses.Viewer _ viewer; IF viewer.saveInProgress THEN RETURN[TRUE]; WHILE (v _ v.link) # NIL AND (v # viewer) DO IF v.saveInProgress THEN RETURN[TRUE]; ENDLOOP; }; IF NOT SomeSaveInProgress[] THEN { IF tool.feedBack = NIL THEN { ShowMessage[tool, Rope.Cat["***Please save ", viewer.name, ". . . \n"]]; } ELSE { tool.feedBack.PutRope[Rope.Cat["***Please save ", viewer.name, ". . . \n"]]; }; }; UNTIL SomeSaveInProgress[] DO Process.Pause[Process.SecondsToTicks[1]]; Process.CheckForAbort[]; ENDLOOP; IF SomeSaveInProgress[] THEN { IF tool.feedBack = NIL THEN { ShowMessage[tool, Rope.Cat["***Waiting for ", viewer.name, " to finish being saved. . . "]]; } ELSE { tool.feedBack.PutRope[Rope.Cat["***Waiting for ", viewer.name, " to finish being saved. . . "]]; }; }; WHILE SomeSaveInProgress[] DO TRUSTED { Process.Pause[Process.SecondsToTicks[1]]; Process.CheckForAbort[]; }; ENDLOOP; IF tool.feedBack = NIL THEN ShowMessage[tool, "ok\n"] ELSE tool.feedBack.PutRope["ok\n"]; }; }; InsureSaved: PROC [tool: Tool, names: LIST OF ROPE] = { wDir: ROPE = FileNames.CurrentWorkingDirectory[]; FOR loopNames: LIST OF ROPE _ names, loopNames.rest UNTIL loopNames = NIL DO currentName: ROPE = loopNames.first; WaitUntilSaved[ IF Rope.Find[currentName, ">"] < 0 AND Rope.Find[currentName, "/"] < 0 THEN FS.ExpandName[currentName, wDir].fullFName ELSE currentName, tool]; ENDLOOP; }; GetPressName: PROCEDURE [tool: Tool] RETURNS [pressName: ROPE] = { nameLen: INT _ 0; cp: FS.ComponentPositions; dirOmitted: BOOLEAN; [tool.currentName, cp, dirOmitted] _ FS.ExpandName[tool.currentName]; IF tool.currentName.Substr[cp.ext.start, cp.ext.length].Equal["Tioga", FALSE] THEN pressName _ tool.currentName.Substr[cp.base.start, cp.base.length] ELSE pressName _ tool.currentName.Substr[cp.base.start, cp.ext.start+cp.ext.length-cp.base.start]; IF tool.singleOutputFile THEN pressName _ pressName.Concat[".etc"]; pressName _ pressName.Concat[".press"]; IF cp.server.length = 0 THEN { pressName _ tool.currentName.Substr[0, cp.base.start].Concat[pressName]; }; IF tool.tempPress THEN pressName _ pressName.Concat["$"]; IF pressName.Equal[tool.pressName] THEN { WaitForSendIdle[tool]; ViewerTools.SetContents[tool.serverMsg, ""] } }; PrintButton: Menus.MenuProc = { tool: Tool _ NARROW[clientData]; tool.selfDestruct _ FALSE; IF mouseButton=yellow THEN ShowMessage[tool, doc[Print]] ELSE Print[tool] }; Print: PUBLIC PROCEDURE [tool: Tool] = { ENABLE UNWIND => NULL; tool.pause _ tool.stop _ tool.stopSending _ FALSE; tool.process _ NIL; TypesetProcess[tool]; }; AllButton: Menus.MenuProc = { tool: Tool _ NARROW[clientData]; tool.selfDestruct _ FALSE; IF mouseButton=yellow THEN ShowMessage[tool, doc[All]] ELSE PrintAll[tool]}; PrintAll: PUBLIC PROCEDURE [tool: Tool] = { tool.singleOutputFile _ TRUE; Print[tool]; }; LeftScreenButton: Menus.MenuProc = { tool: Tool _ NARROW[clientData]; tool.selfDestruct _ FALSE; IF mouseButton=yellow THEN ShowMessage[tool, doc[LeftScreen]] ELSE Screen[tool, leftSide] }; ScreenButton: Menus.MenuProc = { tool: Tool _ NARROW[clientData]; tool.selfDestruct _ FALSE; IF mouseButton=yellow THEN ShowMessage[tool, doc[Screen]] ELSE Screen[tool, bothSides] }; RightScreenButton: Menus.MenuProc = { tool: Tool _ NARROW[clientData]; tool.selfDestruct _ FALSE; IF mouseButton=yellow THEN ShowMessage[tool, doc[RightScreen]] ELSE Screen[tool, rightSide] }; Screen: PUBLIC PROCEDURE [tool: Tool, side: PressScreen.Side] = { pressName: ROPE; TRUSTED {pressName _ PressScreen.NewPressName[]}; IF tool.tempPress THEN pressName _ pressName.Concat["$"]; TRUSTED {PressScreen.PressScreen[pressName, side]}; ShowMessage[tool, pressName.Concat[" completed"]]; IF NOT tool.debug AND NOT tool.stop AND tool.serverName.Length # 0 THEN { tool.pressName _ pressName; StartSending[tool]; }; }; TypesetProcess: PROCEDURE [tool: Tool] = { didNothing: BOOLEAN _ TRUE; gotIt: BOOLEAN; names: LIST OF ROPE; outputHandle: TSOutput.Handle _ NIL; TRUSTED {Process.SetPriority[Process.priorityBackground]}; WHILE ([gotIt: gotIt, names: names] _ GetNames[tool]).gotIt DO didNothing _ FALSE; IF tool.singleOutputFile THEN { tool.currentName _ names.first; ShowMessage[tool, tool.currentName]; tool.pressName _ GetPressName[tool]; IF PressPrinter.IsAPressFile[tool.currentName] THEN { tool.pressName _ tool.currentName; IF NOT tool.debug AND NOT tool.stop AND tool.serverName.Length # 0 THEN StartSending[tool]; } ELSE { InsureSaved[tool, names]; TSFormat.FormatOneOutputFile[tool, names ! ABORTED => CONTINUE]; IF NOT tool.debug AND NOT tool.stop AND tool.serverName.Length # 0 THEN StartSending[tool]; }; } ELSE { -- the "All" button means to format to one output file currentList: LIST OF ROPE _ CONS[NIL, NIL]; currentListTail: LIST OF ROPE _ currentList; tool.pressName _ NIL ; FOR n: LIST OF ROPE _ names, n.rest UNTIL n = NIL DO tool.currentName _ n.first; IF tool.pressName = NIL THEN tool.pressName _ GetPressName[tool]; ShowMessage[tool, tool.currentName]; IF PressPrinter.IsAPressFile[tool.currentName] THEN { IF currentList.rest # NIL THEN { currentList _ currentList.rest; TSFormat.FormatOneOutputFile[tool, currentList ! ABORTED => CONTINUE]; IF NOT tool.debug AND NOT tool.stop AND tool.serverName.Length # 0 THEN StartSending[tool]; }; currentList _ CONS[NIL, NIL]; currentListTail _ currentList; ShowMessage[tool, tool.currentName]; tool.pressName _ tool.currentName; IF NOT tool.debug AND NOT tool.stop AND tool.serverName.Length # 0 THEN StartSending[tool]; tool.pressName _ NIL; } ELSE { ShowMessage[tool, tool.currentName]; InsureSaved[tool, names]; currentListTail.rest _ CONS[n.first, NIL]; currentListTail _ currentListTail.rest; }; ENDLOOP; IF currentList.rest # NIL THEN { currentList _ currentList.rest; TSFormat.FormatOneOutputFile[tool, currentList ! ABORTED => CONTINUE]; IF NOT tool.debug AND NOT tool.stop AND tool.serverName.Length # 0 THEN StartSending[tool]; }; }; ENDLOOP; SafeStorage.ReclaimCollectibleObjects[]; tool.singleOutputFile _ FALSE; IF didNothing THEN ShowMessage[tool, "Ready"]; IF tool.selfDestruct THEN WaitForSendIdle[tool]; IF tool.stop OR tool.stopSending THEN tool.selfDestruct _ FALSE; IF tool.selfDestruct THEN ViewerOps.DestroyViewer[tool.messageBox.parent]; }; QueueRequest: PUBLIC ENTRY PROCEDURE [tool: Tool, documentName: ROPE] = { ENABLE UNWIND => NULL; queue: ROPE _ ViewerTools.GetContents[tool.nameBox]; IF queue.Length = 0 THEN queue _ documentName ELSE queue _ queue.Cat[" ", documentName]; ViewerTools.SetContents[tool.nameBox, queue]; }; GetSelectionButton: Menus.MenuProc = { tool: Tool _ NARROW[clientData, Tool]; tool.selfDestruct _ FALSE; IF mouseButton=yellow THEN ShowMessage[tool, doc[Get]] ELSE { selectedViewer: ViewerClasses.Viewer _ ViewerTools.GetSelectedViewer[]; sourceName: ROPE _ NIL; sourceName _ IF selectedViewer = NIL OR selectedViewer.class.get = NIL THEN NIL ELSE NARROW[selectedViewer.class.get[selectedViewer, $SelChars ! RuntimeError.UNCAUGHT => CONTINUE]]; IF sourceName.Length <=1 THEN { IF (selectedViewer = NIL) THEN {ShowMessage[tool, "Selection not in text viewer"]; sourceName _ NIL} ELSE sourceName _ selectedViewer.name; }; QueueRequest[tool, sourceName]; }; }; WaitForIdle: PUBLIC ENTRY PROCEDURE [tool: Tool] = { ENABLE UNWIND => NULL; WHILE tool.process # NIL DO WAIT tool.idle ENDLOOP; WHILE tool.serverProcess # NIL DO WAIT tool.serverIdle ENDLOOP; }; WaitForSendIdle: PUBLIC ENTRY PROCEDURE [tool: Tool] = { ENABLE UNWIND => NULL; WHILE tool.serverProcess # NIL DO WAIT tool.serverIdle ENDLOOP; }; StartSending: PROCEDURE [tool: Tool] = { IF tool.serverName.Equal["*"] THEN DoShowPress[tool.pressName] ELSE MonitoredStartSending[tool]; }; MonitoredStartSending: ENTRY PROCEDURE [tool: Tool] = { ENABLE UNWIND => NULL; UNTIL tool.serverProcess = NIL DO WAIT tool.serverIdle ENDLOOP; TRUSTED {Process.Detach[tool.serverProcess _ FORK SendingProcess[tool, tool.pressName]]}; }; FinishSending: ENTRY PROCEDURE [tool: Tool] = { ENABLE UNWIND => NULL; tool.serverProcess _ NIL; BROADCAST tool.serverIdle; }; SendingProcess: PROCEDURE [tool: Tool, pressName: ROPE] = { ENABLE ABORTED => {FinishSending[tool]; GOTO Quit}; prevMsg: ROPE _ NIL; AbortablePause: PROC [seconds: CARDINAL] ~ { oneSecond: Process.Ticks ~ Process.SecondsToTicks[1]; THROUGH [0..seconds] DO IF tool.stopSending THEN GO TO Aborted; Process.Pause[oneSecond]; ENDLOOP; EXITS Aborted => DisplayMsg["Transmission aborted"]; }; DisplayMsg: PROC [rope: ROPE] ~ { IF prevMsg # rope THEN { ViewerTools.SetContents[tool.serverMsg, ViewerTools.GetContents[tool.serverMsg].Cat["\n",rope]]; [] _ tool.serverMsg.class.scroll[tool.serverMsg, thumb, 100]; }; prevMsg _ rope; }; tryAgain: BOOL _ FALSE; progressProc: PressPrinter.ProgressProc = { state: PressPrinter.State ~ handle.CurrentState; PieViewers.Set[tool.serverPie, 1.0-handle.CurrentProgress]; IF tryAgain=FALSE OR state#aborted THEN DisplayMsg[handle.CurrentStateMessage]; IF state=serverBusy OR state=serverTimeout THEN {tryAgain _ TRUE; handle.Abort}; IF tool.stopSending THEN {tryAgain _ FALSE; handle.Abort}; }; copies: INT _ 1; copies _ MAX[0, Convert.IntFromRope[ViewerTools.GetContents[tool.copiesBox] ! Convert.Error => CONTINUE]]; IF copies > 0 THEN { printedBy: ROPE _ UserProfile.Token["Hardcopy.PrintedBy", ""]; DO tryAgain _ FALSE; [] _ PressPrinter.SendPressFile[ fileName: pressName, server: tool.serverName, progressProc: progressProc, copies: copies, userName: IF printedBy.Length = 0 THEN UserCredentials.Get[].name ELSE printedBy ]; IF NOT tryAgain THEN EXIT; AbortablePause[30]; ENDLOOP; }; IF TemporaryName[pressName] THEN { FS.Delete[pressName ! FS.Error => { DisplayMsg[error.explanation]; CONTINUE }]; }; FinishSending[tool]; EXITS Quit => {} }; TemporaryName: PROC [rope: ROPE] RETURNS [BOOL] ~ { fullFName: ROPE; cp: FS.ComponentPositions; [fullFName, cp] _ FS.ExpandName[rope]; RETURN [fullFName.Fetch[cp.ext.start+cp.ext.length-1] = '$] }; GetName: PROC [stream: IO.STREAM] RETURNS [name: ROPE] ~ { name _ NIL; name _ IO.GetTokenRope[stream, IO.IDProc ! IO.EndOfStream => CONTINUE].token; }; FileNameBreakProc: PROC [char: CHAR] RETURNS [IO.CharClass] = { IF char = ' OR char = ' OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr]; RETURN [other]; }; GetFileName: PROC [stream: IO.STREAM] RETURNS [name: ROPE] ~ { name _ NIL; name _ IO.GetTokenRope[stream, FileNameBreakProc ! IO.EndOfStream => CONTINUE].token; }; GetLine: PROC [stream: IO.STREAM] RETURNS [line: ROPE] ~ { line _ NIL; line _ IO.GetLineRope[stream ! IO.EndOfStream => CONTINUE]; }; DoShowPress: PROC [pressFileName: ROPE] ~ { [] _ CommandTool.DoCommand[Rope.Concat["ShowPress ", pressFileName], NIL]; }; DragomanStartTSetter: Commander.CommandProc = { tool: Tool; stream: IO.STREAM _ IO.RIS[cmd.commandLine]; serverName: ROPE _ GetName[stream]; files: ROPE _ NIL; WHILE NOT IO.EndOf[stream] DO token: ROPE _ GetFileName[stream]; IF token # NIL THEN { ENABLE FS.Error => {IF error.group=user THEN {cmd.out.PutRope[error.explanation]; cmd.out.PutChar['\n]; CONTINUE} ELSE REJECT}; CatProc: FS.NameProc = { files _ files.Cat[" ", fullFName]; RETURN[TRUE]; }; IF token.Find["*"] = -1 THEN [] _ CatProc[FS.ExpandName[token].fullFName] ELSE { IF token.Find["!"] = -1 THEN token _ token.Concat["!H"]; FS.EnumerateForNames[pattern: token, proc: CatProc]; }; }; ENDLOOP; IF serverName.Length=0 THEN serverName _ UserProfile.Token["Hardcopy.PressPrinter", ""]; tool _ NewTool[serverName]; IF files.Length > 0 THEN {tool.selfDestruct _ TRUE; QueueRequest[tool, files]}; Print[tool]; }; tSViewerClass: ViewerClasses.ViewerClass = NEW[ViewerClasses.ViewerClassRec _ ViewerOps.FetchViewerClass[$Container]^]; tSViewerClass.paint _ TSViewerPaint; tSViewerClass.adjust _ TSViewerAdjust; tSViewerClass.icon _ private; tSViewerClass.bltH _ none; tSViewerClass.bltV _ none; ViewerOps.RegisterViewerClass[$TSetter, tSViewerClass]; Commander.Register[ key: "DragomanStartTSetter", proc: DragomanStartTSetter, doc: "Starts a single Dragoman simulation of TSetter" ]; END. VTSetterStarter.mesa Created by Sindhu, October 18, 1985 5:45:22 pm PST Pradeep Sindhu October 21, 1985 9:49:01 pm PDT IF tool.process=NIL THEN TRUSTED {Process.Detach[tool.process _ FORK TypesetProcess[tool]]}; ViewerTools.SetContents[tool.copiesBox, "1"]; -- should set it to one here only if there is nothing more to print, but I didn't figure out how to determine that yet... The line cache in Tioga 1 is global and used by both scrolling and selection. Invalidate it as a good citizen (guess scrolling was never expected to be asynchronous) TEditSelection.InvalidateLineCache[]; Κ– "Cedar" style˜codešœΟc™K™2K™.—K™šΟk ˜ Kš œžœžœžœžœ˜Kšœžœ˜#Kšœ žœ!˜0Kšœ žœ ˜Kšœ žœ˜Kšœžœ#˜0Kšœ žœ˜*KšžœžœN˜VKšœžœ)˜4Kšœžœ'˜3Kšœžœ ˜KšžœžœVžœžœ˜kKšœžœ˜KšœžœY˜dKšœ žœ˜Kšœ žœw˜‰Kšœ žœ#˜4Kšœ žœ˜Kšœžœ˜KšœžœX˜eKšœžœ ˜Kšœžœ4žœ ˜LKšœ žœžœ˜Kšœ žœ˜.Kšœ žœ˜%Kšœžœ˜Kšœ žœ ˜Kšœ žœ˜Kšœžœ˜Kšœ žœ˜#Kšœžœ>˜QKšœ žœ΄˜ΓKšœžœ˜#Kšœ žœR˜cKšœ žœb˜s—K˜KšΟbœž ˜Kšžœ@žœ!žœΛ˜ΉKšžœ ˜šœžœžœ ˜Kšžœžœžœ˜K˜Kšœžœ˜Kšœ žœ˜K˜HK˜GK˜šΟn œ˜Kšžœžœ žœ˜Dšžœ˜K˜GKšœžœžœ˜š œžœžœžœžœžœž˜Kšžœžœ5˜@Kšœ žœžœ˜$——Kšžœžœ žœ˜'K˜K˜—K˜K˜—Kšœž œ žœžœ ˜,šœ žœU˜cK˜—š  œž œžœž œ žœžœ˜>Kš œžœžœ žœžœ˜ K˜BK˜:K˜.K˜8K˜;K˜5K˜>K˜CK˜8K˜AK˜K˜—š œž œž œ žœ žœžœžœžœ ˜]Kšžœžœžœ˜Kšœ žœžœžœ ˜>Kšœžœ ˜Kš œž œžœžœ˜>˜!˜K˜šœ žœžœ žœ˜=Kšœž˜ K˜—Kšœž˜ K˜——K˜&š œž œžœžœžœžœ žœžœžœžœ žœžœ˜­K˜•Kšœ'˜'K˜—Kšœ4žœ˜TKšœ:žœ#˜aKšœ:žœ˜\Kšœ9žœ"˜_Kšœ4žœ˜TKšœ8žœ˜ZKšœ=žœ˜]KšœDžœ#˜lKšœ6žœ˜XKšœ8žœ˜ZK˜#˜!KšœLžœ˜SK˜K˜Kšœžœ˜ Kšœžœ˜ K˜TK˜—Kšœ"žœ˜(˜-˜`Kšœžœ žœ˜4—Kšœž˜ K˜—Kšœžœ˜&Kšœ1%˜VK˜GKšœžœ˜!K˜RKšœ#žœ˜)˜0KšœRžœ žœ˜fKšœž˜ K˜—Kšœ"žœ˜)K˜.K˜K˜YKšœ!žœ˜'˜/KšœRžœ žœ˜fKšœž˜ K˜—Kšœ!žœ˜(K˜-šœ ˜ KšœLžœ˜SK˜K˜Kšœžœ˜ Kšœžœ˜ K˜SKšœ˜—Kšœ!žœ˜'˜/˜^Kšœžœ žœ˜5—Kšœž˜ K˜—Kšœ!žœ˜'šœ%˜%Kšœ\žœ˜cK˜K˜Kšœžœ˜ Kšœž˜ K˜—Kšœ&žœ˜,˜$Kšœnžœ˜uKšœž˜ K˜—Kšœ&žœ˜,KšœE˜EK˜2K˜-K˜;K˜&K˜Kšžœ˜ Kšœ˜K˜—šœžœžœ˜ Kšœžœ-˜8Kšœžœ1˜>Kšœžœ(˜8K˜K˜—š   œž œ.žœ žœžœ˜bKšœ1žœ+˜_K˜K˜—š œž œ)žœ˜QKšžœ˜ Kš œžœžœžœžœ˜BK˜Kš œžœžœžœžœžœ˜]KšžœžœžœA˜QKšœžœ žœžœ˜CK˜K˜Kšœ˜K˜—š œ˜,Kšœ žœžœ*˜@šžœ1žœžœž˜Bšžœ/žœž˜>šœžœ˜&šœ5˜5KšœK˜KK˜Kšœžœžœ žœ ˜7K˜—Kšœ˜—Kšžœžœ˜—Kšžœ˜—K˜K˜—š  œ˜*šœ žœ˜•StartOfExpansionr[flavor: Icons.IconFlavor, context: Graphics.Context, x: INTEGER _ 0, y: INTEGER _ 0, label: ROPE _ NIL]šœžœžœ žœ ˜JKšœ˜Kšœ˜—Kšœ˜—šžœ žœ˜Kšœ$˜$šžœ žœ˜)Kšœ0˜0KšœT˜TKšœ˜—Kšœ˜—K˜K˜—š  œž œžœ˜2Kšœ7˜7Kšœ.˜.Kšœ?˜?K˜K˜—š  œ˜Kšœ žœ ˜ Kšœžœ˜Kšžœžœ˜7Kšžœ ˜Kšœ˜K˜—š œžœžœž œžœžœžœ˜CKšœ žœ˜K˜K˜—š  œ˜Kšœ žœ ˜ Kšœžœ˜Kšžœžœ˜8Kšžœ ˜Kšœ˜K˜—š œžœžœž œžœžœžœ˜DKšœ žœ˜K˜K˜—š œ˜%Kšœ žœ ˜ Kšœžœ˜Kšžœžœ$˜>Kšžœ˜Kšœ˜K˜—š  œžœžœž œžœžœžœ˜JKšœžœ˜K˜K˜—š   œžœžœžœžœ˜>Kšœ žœ ˜ Kšœžœ˜Kšžœžœ+˜EK˜'K˜K˜—š œžœž œžœ˜6K˜EK˜K˜—š  œ˜$Kšœ žœ ˜ Kšœžœ˜Kšžœžœ-˜GK˜)K˜K˜—š  œžœž œ#žœ˜JK˜%Kšœ žœžœžœ ˜LK˜K˜—š œ˜'Kšœ žœ ˜ Kšœžœ˜$Kšœžœ˜Kšœ žœžœžœ ˜LK˜K˜—š œžœž œžœ žœžœ žœžœž œ˜eJšžœžœžœ˜Jšœžœ)˜3Jšœžœ˜Jšœ žœ˜Jšœžœ˜Jšœ žœžœžœ˜šžœ žœ ž˜Jš œžœžœ žœž œ˜;—Jšœžœžœžœ˜Jšœ˜šž˜šžœ žœžœžœ žœžœ žœžœžœ˜`Jšžœ žœ˜—Jšœ ˜ šžœ žœžœžœ žœžœ žœžœžœ˜^Jšžœ žœ˜—Jšžœžœžœ˜Jšœžœ*žœ˜FJšœ˜šžœ žœžœžœ žœžœ žœžœžœ˜`Jšžœ žœ˜—Jšžœ žœžœžœ˜3Jšžœ˜—J˜=Jšœ˜šžœ žœžœžœ˜.Jšœžœ˜Jšžœ ˜Jšžœžœžœ˜J˜—J˜J˜—code1š œžœ žœ˜%Lšžœ"˜)˜"šžœžœ˜)Lšžœžœžœ˜ Lšžœžœžœ˜—L˜—L˜'L˜L˜—š œžœžœ˜:Lšœžœ˜#Lšœ"˜"šžœ žœžœžœ˜,š  œžœžœžœžœžœ˜@Lšœ!˜!Lšžœžœžœžœ˜+šžœžœžœž˜,Lšžœžœžœžœ˜&Lšžœ˜—L˜—šžœžœžœ˜"šžœžœžœ˜LšœH˜HL˜—šœžœ˜LšœL˜LL˜—L˜—šžœ˜šž˜Lšœ)˜)Lšœ˜—Lšžœ˜—šžœžœ˜šžœžœžœ˜Lšœ\˜\L˜—šœžœ˜Lšœ`˜`L˜—L˜—šžœž˜šžœ˜ Lšœ)˜)Lšœ˜L˜—Lšžœ˜—Lšžœžœžœžœ˜YL˜—L˜L˜—š   œžœžœžœžœ˜7Jšœžœ'˜1š žœ žœžœžœžœ žœž˜LJšœ žœ˜$šœ˜šžœ!žœ!˜GJšžœžœ(˜/Jšžœ ˜—Jšœ˜—Jšžœ˜—J˜J˜—š  œž œžœ žœ˜BKšœ žœ˜Kšœžœ!žœ˜/Kšœ%žŸœ˜EšžœEžœž˜RKšœB˜B—Kšžœ^˜bKšžœžœ&˜CKšœ'˜'šžœžœ˜KšœH˜HK˜—Kšžœžœ#˜9šžœ!žœ˜)K˜K˜+K˜—Kšœ˜K˜—š  œ˜Kšœ žœ ˜ Kšœžœ˜Kšžœžœ˜8Kšžœ ˜Kšœ˜K˜—š œžœž œ˜(Kšžœžœžœ˜Kšœ,žœ˜2Kš žœžœžœžœ žœ™\Kšœžœ˜Kšœ˜Kšœ˜K˜—š  œ˜Kšœ žœ ˜ Kšœžœ˜Kšžœžœ˜6Kšžœ˜K˜—š œžœž œ˜+Kšœžœ˜K˜ K˜K˜—š œ˜$Kšœ žœ ˜ Kšœžœ˜Kšžœžœ#˜=Kšžœ˜Kšœ˜—š  œ˜ Kšœ žœ ˜ Kšœžœ˜Kšžœžœ˜9Kšžœ˜Kšœ˜—š œ˜%Kšœ žœ ˜ Kšœžœ˜Kšžœžœ$˜>Kšžœ˜Kšœ˜K˜—š œžœž œ)˜AKšœ ž˜Kšžœ*˜1Kšžœžœ#˜9Kšžœ,˜3Kšœ2˜2š žœžœ žœžœ žœžœ˜IKšœ˜K˜K˜—K˜K˜—š œž œ˜*Jšœ žœžœ˜Jšœžœ˜Jšœžœžœžœ˜Jšœ žœ˜$Jšžœ3˜:šžœ7ž˜>Jšœ žœ˜šžœžœ˜Jšœ˜J˜$Jšœ$˜$šžœ-žœ˜5J˜"š žœžœ žœžœ žœž˜GJ˜—J˜—šžœ˜J˜Jšœ+žœžœ˜@Jš žœžœ žœžœ žœžœ˜[J˜—J˜—šœžœ6˜>Jš œ žœžœžœžœžœžœ˜+Jšœžœžœžœ˜,Jšœžœ˜š žœžœžœžœžœžœž˜4Jšœ˜Jšžœžœžœ%˜AJ˜$šžœ-žœ˜5šžœžœžœ˜ Jšœ˜Jšœ1žœžœ˜FJš žœžœ žœžœ žœžœ˜[J˜—Jšœžœžœžœ˜Jšœ˜J˜$J˜"š žœžœ žœžœ žœž˜GJ˜—Jšœžœ˜J˜—šžœ˜J˜$J˜Jšœžœ žœ˜*Jšœ'˜'J˜—Jšžœ˜—šžœžœžœ˜ Jšœ˜Jšœ2žœžœ˜GJš žœžœ žœžœ žœžœ˜[J˜—J˜—Jšžœ˜—J˜(Jšœžœ˜Jšžœ žœ˜.Jšžœžœ˜0Jšžœ žœžœžœ˜@Jšžœžœ1˜JJšœ˜J˜—š   œžœžœž œžœ˜IKšžœžœžœ˜Kšœžœ)˜4Kšžœžœ˜-Kšžœ&˜*Kšœ-˜-K˜K˜—š œ˜&Kšœ žœ˜&Kšœžœ˜Kšžœžœ˜6šžœ˜K˜GKšœ žœžœ˜š œ žœžœžœžœžœž˜Ošžœžœ5˜@Kšœ žœžœ˜$——šžœžœ˜šžœžœž˜KšœAžœ˜E—Kšžœ"˜&K˜—K˜K˜—Kšœ˜K˜—š  œžœžœž œ˜4Kšžœžœžœ˜Kš žœžœžœžœ žœ˜3Kš žœžœžœžœžœ˜?K˜K˜—š œžœžœž œ˜8Kšžœžœžœ˜Kš žœžœžœžœžœ˜?K˜K˜—š  œž œ˜(Kšžœžœ˜>Kšžœ˜!K˜K˜—š œžœž œ˜7Kšžœžœžœ˜Kš žœžœžœžœžœ˜?Kšžœ&žœ(˜YK˜K˜—š  œžœž œ˜/Kšžœžœžœ˜Kšœžœ˜Kšž œ˜K™¨K˜K˜—š œž œžœ˜;Kšžœžœžœ˜3Kšœ žœžœ˜š œžœ žœ˜,J˜5šžœž˜Jšžœžœžœžœ ˜'J˜Jšžœ˜—šž˜Jšœ.˜.—J˜—š  œžœžœ˜!šžœžœ˜Kšœ`˜`Kšœ=˜=K™MK™WKšœ%™%Kšœ˜—Kšœ˜K˜—Kšœ žœžœ˜š  œ˜+Kšœ0˜0K˜;Kšžœ žœžœžœ(˜OKšžœžœžœ žœ˜PKšžœžœ žœ˜:K˜—Kšœžœ˜Kšœ žœSžœ˜jšžœ žœ˜Kšœ žœ/˜>šž˜Kšœ žœ˜˜ K˜K˜K˜K˜Kšœ žœžœžœ ˜PK˜—Kšžœž ˜K˜Kšžœ˜—K˜—šžœžœ˜"šžœ!˜#Kšœ˜Kšž˜Kšœ˜—K˜—K˜Kšžœ ˜K˜K˜—š   œžœžœžœžœ˜3Kšœ žœ˜Kšœžœ˜Kšœžœ˜&Kšžœ5˜;K˜K˜—š  œžœ žœžœžœžœ˜:Kšœžœ˜ Kš œžœžœ žœžœ˜MK˜K˜—– "cedar" styleš  œžœžœžœžœ˜?Kšžœ žœ žœ žœ žœ žœžœ˜UKšžœ ˜Kšœ˜K˜—š   œžœ žœžœžœžœ˜>Kšœžœ˜ Kšœžœ*žœžœ˜UK˜K˜—š  œžœ žœžœžœžœ˜:Kšœžœ˜ Kšœžœžœžœ˜;K˜K˜—š  œžœžœ˜+KšœEžœ˜JK˜K˜—šŸœ˜/Kšœ ˜ Kš œžœžœžœžœ˜,Kšœ žœ˜#Kšœžœžœ˜šžœžœžœž˜Kšœžœ˜"šžœ žœžœ˜Kšžœžœ žœžœ<žœžœžœ˜šœ žœ ˜Kšœ"˜"Kšžœžœ˜ K˜—Kšžœžœžœ˜Išžœ˜Kšžœžœ˜8Kšžœ2˜4Kšœ˜—Kšœ˜—Kšž˜—Kšžœžœ=˜XKšœ˜Kšžœžœžœ˜OKšœ ˜ K˜K˜—˜*KšžœI˜L—K˜K˜$K˜&K˜Kšœ˜Kšœ˜K˜7K˜šœ˜Kšœ˜Kšœ˜Kšœ5˜5K˜——K˜Kšžœ˜K™K™K™K™K™K™—…—f†]