DIRECTORY Ascii USING [BS, DEL, BEL, ControlA, TAB, CR, SP], Commander USING [CommandProc, Register], CommandTool USING [ArgumentVector, Failed, Parse], Convert USING [RopeFromCard], EditedStream USING [SetEcho], FS USING [Error, StreamOpen], GPIB USING [DeviceAddr, maxWriteBuffer, ReadDevice, InitializeController, SelectedDeviceClear, InterfaceClear, FinalizeController, WriteDevice], IO, IOClasses USING [CreateDribbleOutputStream], List USING [Length, Remove], Loader USING [BCDBuildTime], Menus USING [AppendMenuEntry, CreateEntry, FindEntry, MenuEntry, MenuProc, ReplaceMenuEntry], Process USING [Abort, Detach, InvalidProcess], RefText USING [AppendChar, New], Rope, RuntimeError USING [BoundsFault], TIPUser USING [InstantiateNewTIPTable, RegisterTIPPredicate, TIPPredicate, TIPTable], TypeScript USING [BackSpace, ChangeLooks, Create, InsertCharAtFrontOfBuffer, TS], ViewerClasses USING [Viewer], ViewerEvents USING [EventProc, EventRegistration, RegisterEventProc, UnRegisterEventProc], ViewerIO USING [CreateViewerStreams], ViewerOps USING [AddProp, FetchProp, PaintViewer], ViewerTools USING [GetSelectedViewer, SetSelection]; IMSCommandImpl: CEDAR MONITOR LOCKS h.LOCK USING h: Handle IMPORTS Commander, CommandTool, Convert, EditedStream, FS, GPIB, IO, IOClasses, List, Loader, Menus, Process, RefText, Rope, RuntimeError, TIPUser, TypeScript, ViewerEvents, ViewerIO, ViewerOps, ViewerTools SHARES Menus, ViewerClasses, ViewerOps = BEGIN Handle: TYPE = REF IMSCommandInstanceRecord; State: TYPE = {idle, starting, running, closing, destroy}; bufferType: TYPE = {sender, receiver}; DisconnectChar: CHAR = 220C; AbortChar: CHAR = 221C; ConnectChar: CHAR = 222C; IMSCommandInstanceRecord: TYPE = MONITORED RECORD [ ts: TypeScript.TS, -- the primary typescript state: State _ idle, lorc: CHAR _ 'c, logFileName: Rope.ROPE, logStream: IO.STREAM, argv: CommandTool.ArgumentVector, pleaseStop: BOOL _ FALSE, DeviceHandlerStopped: BOOL _ FALSE, ControllerStopped: BOOL _ FALSE, inDestroy: BOOL _ FALSE, ControllerToDeviceProcess: PROCESS, deviceName: Rope.ROPE _ "MasterUnit", --default name addr: GPIB.DeviceAddr _ 1, -- default address useOldHost: BOOL _ FALSE, destroyOnClose: BOOL _ FALSE, connectionOpen: BOOL _ FALSE, in: IO.STREAM, origOut: IO.STREAM, out: IO.STREAM, tipTable: TIPUser.TIPTable, oldSplit: Menus.MenuEntry _ NIL ]; logFileNumber: INT _ 0; chatInstanceList: LIST OF REF ANY _ NIL; destroyEvent: ViewerEvents.EventRegistration _ NIL; closeEvent: ViewerEvents.EventRegistration _ NIL; chatTipTable: TIPUser.TIPTable; sendBuffer: REF TEXT _ RefText.New[GPIB.maxWriteBuffer]; recvBuffer: Rope.ROPE; DeviceHandler: INTERNAL PROC [h: Handle] = { ENABLE ANY => GOTO Cleanup; aborting: SIGNAL = CODE; c: CHAR; IF h.pleaseStop OR h.state # running THEN GOTO Cleanup; ClearBuffer[receiver]; TRUSTED {recvBuffer _ GPIB.ReadDevice[h.addr]}; IF Rope.Match["End", recvBuffer] THEN h.out.PutF["%g\n", IO.rope[recvBuffer]] ELSE { FOR i: INT IN [0..Rope.Length[recvBuffer]) DO c _ Rope.Fetch[recvBuffer, i]; IF c = '\l THEN LOOP; SELECT c FROM Ascii.BEL => NULL; Ascii.ControlA, Ascii.BS => TypeScript.BackSpace[h.ts]; Ascii.TAB, Ascii.CR, IN[Ascii.SP..0176C] => h.out.PutChar[c]; ENDCASE => NULL; ENDLOOP; }; EXITS Cleanup => h.DeviceHandlerStopped _ TRUE; }; StartUpConnection: PROC [h: Handle] = { ENABLE UNWIND => h.state _ idle; Laddr: LONG CARDINAL _ h.addr; h.state _ starting; h.pleaseStop _ FALSE; h.DeviceHandlerStopped _ FALSE; h.ControllerStopped _ FALSE; ViewerTools.SetSelection[h.ts, NIL]; h.out.PutF["\nIMSCommand Viewer of %t.\n", IO.time[Loader.BCDBuildTime[]]]; IF h.logStream # NIL THEN h.out.PutF["Log file: %g\n", IO.rope[h.logFileName]] ELSE h.out.PutF["No log file.\n"]; OpenConnection[h]; h.state _ running; IF h.connectionOpen THEN PutPrompt[h]; }; OpenConnection: PROC [h: Handle] = TRUSTED { ENABLE {ANY => GOTO attemptFailed}; Laddr: LONG CARDINAL _ h.addr; h.out.PutF["Opening connection to %g@gpib[%g%g]... ", IO.rope[h.deviceName], IO.rope[IF h.addr<9 THEN "0" ELSE ""], IO.card[Laddr]]; IF GPIB.InitializeController[] THEN { GPIB.InterfaceClear[]; GPIB.SelectedDeviceClear[h.addr]; h.out.PutF["open.\n"]; h.connectionOpen _ TRUE; -- in viewer herald SetName[h, Rope.Cat["IMS Commander for ", h.deviceName, IF h.addr<9 THEN "@gpib[0" ELSE "@gpib[", Convert.RopeFromCard[Laddr], "]"]]; } ELSE { h.out.PutF["\nUnknown GPIB address.\n"]; h.connectionOpen _ FALSE;}; EXITS attemptFailed => { h.out.PutF[" I don't see any XBus on this machine! ... Connection attempt aborted.\n"]; h.connectionOpen _ FALSE; }; }; CloseConnection: PROC [h: Handle, print: BOOL] = TRUSTED { {ENABLE ANY => GOTO failed;}; IF NOT h.connectionOpen AND print THEN { h.out.PutF["\nNo connection opened!\n"]; RETURN; }; h.pleaseStop _ TRUE; IF print THEN h.out.PutF["\nClosing connection to %s", IO.rope[h.deviceName] ! IO.Error => CONTINUE]; IF h.connectionOpen THEN GPIB.FinalizeController[]; IF print THEN h.out.PutF[" ... Closed.\n" ! IO.Error => CONTINUE]; IF h.logStream # NIL THEN h.logStream.Flush[]; h.state _ idle; SetName[h, "IMS Commander"]; h.connectionOpen _ FALSE; EXITS failed => NULL; }; SetName: PROC [h: Handle, r: Rope.ROPE] = { -- in Viewer herald InternalSetName: PROC [v: ViewerClasses.Viewer] = { v.name _ r; ViewerOps.PaintViewer[viewer: v, hint: caption]}; EnumerateSplits[h.ts, InternalSetName ! ANY => CONTINUE]; }; IMSCommandMain: Commander.CommandProc = TRUSTED { ENABLE RuntimeError.BoundsFault => GOTO invalidGPIB; h: Handle _ NEW[IMSCommandInstanceRecord _ []]; execOut: IO.STREAM _ cmd.out; switchChar: CHAR; i: NAT _ 2; h.argv _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; CONTINUE; }]; IF h.argv = NIL THEN RETURN; WHILE i < h.argv.argc DO IF h.argv[i].Length[] > 1 THEN SELECT h.argv[i].Fetch[0] FROM '- => { switchChar _ h.argv[i].Fetch[1]; SELECT switchChar FROM '@ => h.addr _ IO.GetCard[IO.RIS[h.argv[i+1]]]; 'd => h.destroyOnClose _ TRUE; ENDCASE => h.lorc _ switchChar; }; ENDCASE => execOut.PutF["IMSCommander: unknown command: %s.\n", IO.rope[h.argv[i]]]; i _ i + 1; ENDLOOP; IF h.logFileName.Length[] = 0 THEN { h.logFileName _ IO.PutFR["IMSCommander%d.log", IO.int[logFileNumber]]; logFileNumber _ logFileNumber + 1; }; h.ts _ TypeScript.Create[info: [name: "IMS Commander", iconic: FALSE], paint: TRUE]; TypeScript.ChangeLooks[h.ts, 'f]; -- look fixed pitch Gacha h.ts.file _ h.logFileName; h.ts.icon _ typescript; h.logStream _ FS.StreamOpen[fileName: h.logFileName, accessOptions: $create ! FS.Error => IF error.group = user THEN { execOut.PutF["IMSCommander : Cannot open %s\n", IO.rope[h.logFileName]]; CONTINUE; }]; chatTipTable.link _ h.ts.tipTable; chatTipTable.opaque _ FALSE; h.tipTable _ h.ts.tipTable _ chatTipTable; [in: h.in, out: h.origOut] _ ViewerIO.CreateViewerStreams[name: "IMSCommander.log", viewer: h.ts, editedStream: FALSE]; h.out _ h.origOut; IF h.logStream # NIL THEN h.out _ IOClasses.CreateDribbleOutputStream[output1: h.origOut, output2: h.logStream]; EditedStream.SetEcho[h.in, NIL]; IF h.argv.argc > 1 THEN { h.deviceName _ h.argv[1]; h.useOldHost _ TRUE; IF h.lorc = 'c THEN TypeScript.InsertCharAtFrontOfBuffer[ts: h.ts, char: ConnectChar]; }; IF List.Length[chatInstanceList] = 0 THEN { destroyEvent _ ViewerEvents.RegisterEventProc[proc: MyDestroy, event: destroy] }; chatInstanceList _ CONS[h, chatInstanceList]; Menus.AppendMenuEntry[menu: h.ts.menu, entry: Menus.CreateEntry[name: "Disconnect", proc: MyDisconnect, clientData: h, fork: TRUE, documentation: "Close GPIB connection"]]; Menus.AppendMenuEntry[menu: h.ts.menu, entry: Menus.CreateEntry[name: "Connect", proc: MyConnect, clientData: h, documentation: "Open GPIB Connection to selected host"]]; Menus.AppendMenuEntry[menu: h.ts.menu, entry: Menus.CreateEntry[name: "FlushLog", proc: MyFlushLog, clientData: h, documentation: "Flush log file to disk."]]; Menus.AppendMenuEntry[menu: h.ts.menu, entry: Menus.CreateEntry[name: "STOP!", proc: MyStop, clientData: h, fork: TRUE, documentation: "Stop everything!"]]; h.oldSplit _ Menus.FindEntry[menu: h.ts.menu, entryName: "Split"]; Menus.ReplaceMenuEntry[menu: h.ts.menu, oldEntry: h.oldSplit, newEntry: Menus.CreateEntry[name: "Split", proc: MySplit, fork: TRUE, clientData: h, documentation: "Split window"]]; ViewerOps.AddProp[h.ts, $IMSCommandToolData, h]; ViewerOps.PaintViewer[viewer: h.ts, hint: all]; h.ControllerToDeviceProcess _ FORK ControllerToDevice[h]; Process.Detach[h.ControllerToDeviceProcess]; EXITS invalidGPIB => cmd.out.PutF["IMSCommand: Invalid GPIB address!\n"]; }; PutPrompt: PROC [h: Handle] = { h.out.PutF["%lIM$:%l ", IO.rope["b"], IO.rope["B"]]; ClearBuffer[sender]; ClearBuffer[receiver]; }; ControllerToDevice: ENTRY PROC [h: Handle] = TRUSTED {{ -- watches keyboard & viewer buttons char: CHAR; waitingForEnd: BOOL _ FALSE; ClearBuffer[sender]; DO ENABLE { ABORTED => GOTO abort; IO.Error => { IF h.connectionOpen THEN CloseConnection[h, FALSE]; GOTO ioError; }}; char _ h.in.GetChar[]; IF h.inDestroy THEN { CloseConnection[h, FALSE]; GOTO destroy}; SELECT char FROM AbortChar => { IF h.state = running THEN CloseConnection[h, TRUE]}; DisconnectChar => { IF h.state = running THEN CloseConnection[h, TRUE]}; ConnectChar => { IF h.state = idle THEN { h.lorc _ 'c; StartUpConnection[h]; }}; Ascii.BS, Ascii.DEL => { IF sendBuffer.length = 0 THEN LOOP; --avoid smashing prompt TypeScript.BackSpace[h.ts]; sendBuffer.length _ sendBuffer.length-1}; ENDCASE => { SELECT h.state FROM running => { h.out.PutChar[char]; sendBuffer _ RefText.AppendChar[sendBuffer, char]; IF char = '\n THEN { --IMS strips this sendBuffer _ RefText.AppendChar[sendBuffer, '\l]; --IMS terminator --handle a multi-line commands IF Rope.Match["*#TXT*", Rope.FromRefText[sendBuffer], FALSE] AND NOT waitingForEnd THEN { waitingForEnd _ TRUE; GPIB.WriteDevice[h.addr, Rope.FromRefText[sendBuffer]]; ClearBuffer[sender]; LOOP; }; IF waitingForEnd THEN { IF Rope.Match["*END*", Rope.FromRefText[sendBuffer], FALSE] THEN { waitingForEnd _ FALSE; } ELSE { --ship current line of multi-line command GPIB.WriteDevice[h.addr, Rope.FromRefText[sendBuffer]]; ClearBuffer[sender]; LOOP}; }; GPIB.WriteDevice[h.addr, Rope.FromRefText[sendBuffer]]; ClearBuffer[sender]; DeviceHandler[h]; PutPrompt[h]}}; ENDCASE => h.out.PutChar[char]; }; ENDLOOP; EXITS ioError, abort, destroy => {IF h.logStream # NIL THEN h.logStream.Close[]}; }}; ClearBuffer: PRIVATE PROC [buffer: bufferType] = { SELECT buffer FROM sender => {sendBuffer.length _ 0}; receiver => { }; ENDCASE; }; MyDestroy: ViewerEvents.EventProc = { h: Handle _ NARROW[ViewerOps.FetchProp[viewer, $IMSCommandToolData]]; IF h = NIL THEN RETURN; IF NumSplit[viewer] = 1 THEN { -- last one h.inDestroy _ TRUE; chatInstanceList _ List.Remove[h, chatInstanceList]; IF List.Length[chatInstanceList] = 0 THEN { ViewerEvents.UnRegisterEventProc[proc: destroyEvent, event: destroy]; }; } ELSE IF NumSplit[viewer] > 1 THEN { IF viewer = h.ts THEN { Another: PROC [v: ViewerClasses.Viewer] = { IF v # viewer THEN h.ts _ v; }; EnumerateSplits[viewer, Another]; }}; }; MyClose: ViewerEvents.EventProc = { h: Handle _ NARROW[ViewerOps.FetchProp[viewer, $IMSCommandToolData]]; IF h = NIL THEN RETURN; TypeScript.InsertCharAtFrontOfBuffer[ts: h.ts, char: DisconnectChar]; }; MyConnect: Menus.MenuProc = { viewer: TypeScript.TS _ NARROW[parent]; h: Handle _ NARROW[clientData]; h.ts _ viewer; -- "primary" copy h.useOldHost _ mouseButton # red; TypeScript.InsertCharAtFrontOfBuffer[ts: h.ts, char: ConnectChar]; }; MyDisconnect: Menus.MenuProc = { h: Handle _ NARROW[clientData]; TypeScript.InsertCharAtFrontOfBuffer[ts: h.ts, char: DisconnectChar]; }; MyStop: Menus.MenuProc = TRUSTED { h: Handle _ NARROW[clientData]; Process.Abort[h.ControllerToDeviceProcess ! Process.InvalidProcess => CONTINUE]; }; MyFlushLog: Menus.MenuProc = { h: Handle _ NARROW[clientData]; IF h.logStream # NIL THEN h.logStream.Flush[]; }; MySplit: Menus.MenuProc = { h: Handle _ NARROW[clientData]; CheckIMSCommandProperties: PROC [v: ViewerClasses.Viewer] = { IF ViewerOps.FetchProp[v, $IMSCommandToolData] = NIL THEN ViewerOps.AddProp[v, $IMSCommandToolData, h]; v.tipTable _ h.tipTable}; h.oldSplit.proc[parent: parent, clientData: h.oldSplit.clientData, mouseButton: mouseButton, shift: shift, control: control]; EnumerateSplits[NARROW[parent, ViewerClasses.Viewer], CheckIMSCommandProperties]; }; ConnectionOpen: TIPUser.TIPPredicate = { h: Handle; viewer: ViewerClasses.Viewer _ ViewerTools.GetSelectedViewer[]; IF viewer=NIL THEN RETURN [FALSE]; -- no primary selection h _ NARROW[ViewerOps.FetchProp[viewer, $IMSCommandToolData]]; IF h = NIL THEN RETURN [FALSE]; -- not a chat tool RETURN [h.state = running]; -- connection open? }; EnumerateSplits: PROC [v: ViewerClasses.Viewer, p: PROC [v: ViewerClasses.Viewer]] = { v2: ViewerClasses.Viewer _ v; IF v = NIL THEN RETURN; DO p[v2]; IF v2.link = NIL OR v2.link = v THEN RETURN; v2 _ v2.link; ENDLOOP; }; NumSplit: PROC [v: ViewerClasses.Viewer] RETURNS [count: INT _ 0] = { Counter: PROC [v2: ViewerClasses.Viewer] = { count _ count + 1}; EnumerateSplits[v, Counter]; }; Init: PROC = { Commander.Register[key: "IMSCommander", proc: IMSCommandMain, doc: "\n\n\tSimple command interface to IMS Logic Master 1000. \n\tUsage: IMSCommander devName [-@ gpibAddr].\n\n\nFor more detailed information see: /datools/datools*/IMS/IMSCommanderDoc.tioga.\n", interpreted: FALSE]; chatTipTable _ TIPUser.InstantiateNewTIPTable["IMSCommander.TIP"]; TIPUser.RegisterTIPPredicate[$ConnectionOpen, ConnectionOpen]; }; Init[]; END... of IMSCommandImpl ψIMSCommandImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Created by: Neil Gunther on September 23, 1985 1:05:17 pm PDT Last edited by Neil Gunther, December 12, 1985 4:16:48 pm PST create log file plug in IMSCommander TIP table. closeEvent _ ViewerEvents.RegisterEventProc[proc: MyClose, event: close]; last viewer destroyed ! Close connection and exit --ship each line out asap to avoid buffer o/flow --ship multi-line header --multi-line trailer; treat as normal command line --Menu & Window procs This EventProc exits only to keep h.ts pointing to a valid copy of the typescript viewer. It is only needed for the use of TypeScript.InsertCharAtFrontOfBuffer. ViewerEvents.UnRegisterEventProc[proc: closeEvent, event: close]; Κ\˜šœ™Icodešœ Οmœ1™<—Jšœ>™>Jšœ=™=˜JšΟk ˜ Jšœžœžœžœžœ žœžœžœ˜2Jšœ žœ˜(Jšœ žœ!˜2Jšœžœ˜Jšœ žœ ˜Jšžœžœ˜Jšœžœ†˜Jšžœ˜Jšœ žœ˜,Jšœžœ˜Jšœžœ˜JšœžœU˜`Jšœžœ!˜.Jšœžœ˜ Jšœ˜Jšœ žœ˜!JšœžœH˜UJšœ žœ=žœ˜QJšœžœ ˜Jšœ žœH˜ZJšœ žœ˜%Jšœ žœ#˜2Jšœ žœ#˜4J˜—š Πbxœžœžœžœžœžœ ˜:Jšžœ0žœžœŒ˜Ο—šžœ#ž˜0Jšœžœžœ˜,Jšœžœ/˜:Jšœ žœ˜&Jšœžœ˜Jšœ žœ˜Jšœ žœ˜J˜šœžœž œžœ˜3JšœžœΟc˜,J˜Jšœžœ˜Jšœžœ˜Jšœ žœžœ˜Jšœ!˜!Jšœ žœžœ˜Jšœžœžœ˜#Jšœžœžœ˜ Jšœ žœžœ˜Jšœžœ˜#Jšœžœ ˜5Jšœžœ ˜1Jšœ žœžœ˜Jšœžœžœ˜Jšœžœžœ˜Jšœžœžœ˜Jšœ žœžœ˜Jšœžœžœ˜J˜Jšœž˜J˜—J˜Jšœžœ˜Jš œžœžœžœžœžœ˜(Jšœ/žœ˜3Jšœ-žœ˜1Jšœ˜Jšœ žœžœžœ˜8Jšœžœ˜—J˜šΟn œž œ˜,Jšžœžœžœ ˜Jšœ ž˜Jšœž˜Jšžœžœž œ ˜7Jšœ˜Jšžœžœ˜/Jšžœžœžœ˜Mšž˜Jšžœžœžœž˜-Jšœ˜Jšžœ žœžœ˜šžœž˜ Jšœžœžœ˜Jšœžœ˜7Jš œžœžœžœžœ˜>Jšžœž˜—Jšž˜Jšœ˜—Jšž˜Jšœ$ž˜)Jšžœ˜J˜—š‘œžœž˜'Jšžœžœ˜ Jšœžœžœ ˜Jšœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜$Jšœ+žœ˜KJšžœžœžœžœ˜NJšžœ˜"J˜Jšœ˜Jšžœžœ˜&Jšžœ˜—š‘œžœžœ˜,Jšž œžœ˜#Jšœžœžœ ˜Jš œ6žœžœžœ žœžœžœ˜„šžœžœžœ˜%Jšžœ˜Jšžœ˜!Jšœ˜Jšœžœ˜JšœΟi˜Jšœ8žœ žœ žœ/˜†Jšœ˜—Jšžœ?žœ˜Kšž˜šœ˜JšœW˜WJšœžœ˜J˜——J˜J˜—š‘œžœžœžœ˜:Jšœžœžœžœ ˜šžœžœžœžœ˜(Jšœ(˜(Jšžœ˜J˜—Jšœžœ˜Jš žœžœ*žœžœ žœ˜eJšžœž œ˜3Jšžœžœžœ žœ˜BJšžœžœžœ˜.J˜Jšœ˜Jšœžœ˜šž˜Jšœ žœ˜—J˜J˜—š‘œžœžœ ’˜@š‘œžœ˜3J˜=—Jšœ(žœžœ˜:J˜—šΟbœžœ˜2Jšžœžœ ˜4Jšœ žœ ˜/Jšœ žœžœ ˜Jšœ žœ˜Jšœžœ˜ JšœHžœ˜UJšžœ žœžœžœ˜šžœž˜šžœž˜šžœž˜˜J˜ šžœ ž˜Jšœžœ žœžœ˜0Jšœžœ˜Jšžœ˜—J˜—Jšžœ9žœ˜T——J˜ Jšžœ˜—šžœžœ˜$Jšœžœžœ˜FJ˜"J˜—Jšœ?žœ žœ˜TJšœ# œ˜=J˜J˜Jšœ™š œžœ>žœ žœžœ˜vJšœ0žœ˜HJšžœ˜ J˜—Jšœ™J˜"Jšœžœ˜J˜*Jšœpžœ˜wJ˜JšžœžœžœW˜pJšœžœ˜ šžœžœ˜J˜Jšœžœ˜Jšžœ žœC˜VJšœ˜—šžœ#žœ˜+JšœI™IJ˜NJ˜—Jšœžœ˜-Jšœ}žœ+˜¬J˜ͺJ˜žJšœržœ&˜œJ˜J˜BJšœ~žœ1˜³Jšœ0˜0J˜/Jšœžœ˜9Jšœ,˜,šžœ˜JšœC˜C—Jšœ˜J˜—š‘ œžœ˜Jšœžœ žœ ˜5Jšœ˜J˜J˜J˜—š‘œž œžœ˜7Jšœ’!˜$Jšœžœ˜ Jšœžœžœ˜Jšœ˜šžœžœ˜ Jšžœžœ˜šžœ ˜ šœ™Jšœ™Jšžœžœžœ˜3Jšžœ ˜ J˜———J˜šžœ žœ˜Jšœžœ˜Jšžœ ˜—šžœž˜šœ˜Jšžœžœžœ˜4˜Jšžœžœžœ˜4——˜šžœžœ˜J˜ Jšœ˜J˜——šœžœžœ˜šžœžœžœ ˜;Jšœ˜Jšœ)˜)——šžœ˜ Jšžœ ž˜˜Jšœ˜Jšœ3˜3šžœ žœ’˜'šœ2 ˜BJšœ’˜Jšœ0™0—šžœ4žœžœ ž˜YJšœžœ˜Jšœ™Jšžœ4 ˜9Jšœ˜Jšžœ˜J˜—šžœž˜šžœ3žœžœ˜BJšœžœ˜Jšœ2™2Jšœ˜—šžœ )˜0Jšžœ4 ˜9Jšœ˜Jšžœ˜—J˜J˜——Jšžœ4 ˜9Jšœ˜J˜Jšœ˜—Jšžœ˜ J˜Jšžœ˜—Jšž˜Jšœžœžœžœ˜KJšœ˜—J˜—š‘ œžœžœ˜4Jšžœžœ˜Jšœ"˜"Jšœ˜Jšžœ˜Jšœ˜J˜Jšœ™J˜%JšœQ™QšœO™OJšœ žœ3˜EJšžœžœžœžœ˜šžœžœ  ˜*Jšœžœ˜J˜4šžœ#žœ˜+J˜EJšœA™AJ˜—J˜—šžœžœžœ˜#šžœžœ˜š‘œžœ˜+Jšžœ žœ ˜J˜—J˜!J˜——J˜J˜—˜#Jšœ žœ3˜EJšžœžœžœžœ˜J˜EJ˜J˜—˜Jšœžœžœ ˜'Jšœ žœ ˜Jšœ ˜ J˜"J˜BJ˜J˜—˜ Jšœ žœ ˜J˜EJ˜J˜—šœžœ˜"Jšœ žœ ˜JšœFžœ˜PJ˜J˜—˜Jšœ žœ ˜Jšžœžœžœ˜.J˜J˜—šœ˜Jšœ žœ ˜š‘œžœ˜=Jšžœ/žœžœ.˜gJ˜—J˜}Jšœžœ;˜QJ˜——š‘œ˜(J˜ J˜?Jš žœžœžœžœžœ ˜:Jšœžœ3˜=Jš žœžœžœžœžœ ˜2Jšžœ ˜/J˜—š‘œžœžœ˜VJ˜Jšžœžœžœžœ˜šž˜Jš œžœ žœžœ žœžœ˜A—Jšžœ˜J˜—š‘œžœžœ žœ ˜Eš‘œžœ˜,J˜—J˜J˜—š‘œžœ˜Jšœ’žœ˜™JšœB˜BJ˜>J˜J˜J˜—J˜Jšžœ˜J˜J˜—…—5$Gx