DIRECTORY Commander USING [CommandProc, Register], EditedStream, Icons USING [IconFlavor, NewIconFromFile], InputFocus USING [PopInputFocus, PushInputFocus], IO, PopUpMenu, Process, Rope, RuntimeError USING [UNCAUGHT], TerminalIO, TerminalIOExtras, ViewerClasses USING [Viewer], ViewerIO USING [CreateViewerStreams, GetViewerFromStream], ViewerOps USING [PaintViewer, OpenIcon], ViewerTools USING [SetSelection]; TerminalIOImpl: CEDAR MONITOR IMPORTS Commander, EditedStream, Icons, InputFocus, IO, PopUpMenu, Process, Rope, RuntimeError, ViewerIO, ViewerOps, ViewerTools EXPORTS TerminalIO, TerminalIOExtras = BEGIN ROPE: TYPE = Rope.ROPE; UserAbort: PUBLIC SIGNAL = CODE; TimedOut: PUBLIC SIGNAL = CODE; terminalParent: ViewerClasses.Viewer_NIL; messageUsed: BOOL _ FALSE; in, out, editedIn: IO.STREAM _ NIL; terminalIcon: Icons.IconFlavor; inputIcon: Icons.IconFlavor; del: CHAR = LOOPHOLE[127, CHAR]; delRope: ROPE = Rope.FromChar[del]; moduleEntered: BOOL _ FALSE; next: CONDITION; -- the next module might enter the "moduleEntered" region MyLock: ENTRY PROC [] = BEGIN WHILE moduleEntered DO WAIT next; ENDLOOP; moduleEntered _ TRUE; END; ReaderLock: PROC [] = BEGIN terminalParent.icon _ inputIcon; terminalParent.name _ "Terminal [Input Expected]"; ViewerOps.PaintViewer[terminalParent, caption]; END; MyUnLock: ENTRY PROC [] = BEGIN moduleEntered _ FALSE; BROADCAST next; END; ReaderUnLock: PROC [] = BEGIN terminalParent.icon _ terminalIcon; terminalParent.name _ "Terminal"; ViewerOps.PaintViewer[terminalParent, caption]; terminalParent.inhibitDestroy _ FALSE; END; LockList: TYPE = LIST OF PROC; lockList: LockList_NIL; unLockList: LockList_NIL; AddLock: PUBLIC ENTRY PROC [lock, unLock: PROC] = BEGIN ENABLE UNWIND => NULL; unLockList _ CONS[unLock, unLockList]; IF lockList=NIL THEN lockList _ LIST[lock] ELSE FOR l: LockList _ lockList, l.rest DO IF l.rest=NIL THEN {l.rest _ LIST[lock]; EXIT} ENDLOOP; END; Lock: PROC = BEGIN FOR l: LockList _ lockList, l.rest WHILE l#NIL DO l.first[! RuntimeError.UNCAUGHT => CONTINUE] ENDLOOP END; UnLock: PROC = BEGIN FOR l: LockList _ unLockList, l.rest WHILE l#NIL DO l.first[! RuntimeError.UNCAUGHT => CONTINUE] ENDLOOP END; InternalCreateTerminal: PROC [] = BEGIN [in: in, out: out] _ ViewerIO.CreateViewerStreams[name: "Terminal", viewer: NIL, editedStream: FALSE]; [editedIn] _ EditedStream.Create[in: in, echoTo: out]; terminalParent _ ViewerIO.GetViewerFromStream[out]; IF terminalParent=NIL THEN ERROR; IF terminalParent.iconic THEN { terminalParent.column _ right; ViewerOps.OpenIcon[terminalParent]; }; terminalParent.icon _ terminalIcon; END; Done: TYPE = {ok, repeat, intError, abort, timeout, no}; PrepareRequest: PROC [text: ROPE _ NIL] = BEGIN InternalWriteRope[text]; IF terminalParent.iconic THEN { terminalParent.column _ right; ViewerOps.OpenIcon[terminalParent]; }; InputFocus.PushInputFocus[terminalParent]; ViewerTools.SetSelection[terminalParent]; END; RequestRope: PUBLIC PROC [text: ROPE _ NIL] RETURNS [ROPE] = BEGIN ENABLE UNWIND => UnLock[]; done: Done; r: ROPE; DoIt: PROC [] = BEGIN ENABLE BEGIN IO.Error => IF ec=StreamClosed THEN {done_repeat; IO.Reset[editedIn]; CONTINUE}; EditedStream.Rubout => {done_abort; IO.Reset[editedIn]; CONTINUE}; END; PrepareRequest[text]; r _ IO.GetLineRope[editedIn]; InputFocus.PopInputFocus[]; IF Rope.Find[r, delRope]>=0 THEN done_abort; END; Lock[]; DO done _ ok; DoIt[]; IF done=ok THEN {UnLock[]; RETURN [r]} ELSE IF done=repeat THEN {InternalWriteRope["XXX\n"]} ELSE {InternalWriteRope[" ..user abort\n"]; SIGNAL UserAbort} ENDLOOP; END; RequestChar: PUBLIC PROC [text: ROPE _ NIL] RETURNS [CHAR] = BEGIN ENABLE UNWIND => UnLock[]; done: Done; ch: CHAR; DoIt: PROC [] = BEGIN ENABLE BEGIN IO.Error => IF ec=StreamClosed THEN {done_repeat; CONTINUE}; EditedStream.Rubout => {done_abort; IO.Reset[in]; CONTINUE}; END; PrepareRequest[text]; ch _ IO.GetChar[in]; -- returns immediately, no CR to eat InputFocus.PopInputFocus[]; IF ch=del THEN done_abort; END; Lock[]; DO done _ ok; DoIt[]; IF done=ok THEN {UnLock[]; RETURN[ch]} ELSE IF done=repeat THEN {InternalWriteRope["XXX\n"]} ELSE { InternalWriteRope[" ..user abort\n"]; SIGNAL UserAbort }; ENDLOOP; END; RequestInt: PUBLIC PROC [text: ROPE _ NIL] RETURNS [INT] = BEGIN ENABLE UNWIND => UnLock[]; done: Done; i: INT; DoIt: PROC [] = BEGIN ENABLE BEGIN IO.Error => IF ec=StreamClosed THEN {done_repeat; CONTINUE} ELSE IF ec=Overflow THEN {done_intError; CONTINUE} ELSE IF ec=SyntaxError THEN {done_intError; CONTINUE}; EditedStream.Rubout => {done_abort; IO.Reset[editedIn]; CONTINUE}; END; ch: CHAR; PrepareRequest[text]; i _ IO.GetInt[editedIn]; WHILE IO.CharsAvail[editedIn]>0 DO [ch] _ IO.GetChar[editedIn]; IF ch=del THEN done_abort; IF ch#15C AND done#abort THEN done_intError ENDLOOP; InputFocus.PopInputFocus[]; END; Lock[]; DO done _ ok; DoIt[]; IF done=ok THEN {UnLock[]; RETURN[i]} ELSE IF done=repeat THEN {InternalWriteRope["XXX\n"]} ELSE IF done=intError THEN {InternalWriteRope[" ?? (integer), please repeat: \n"]} ELSE {InternalWriteRope[" ..user abort\n"]; SIGNAL UserAbort} ENDLOOP; END; ChoiceError: ERROR = CODE; RequestSelection: PUBLIC PROC [label: ROPE _ NIL, choice: LIST OF ROPE, text: ROPE _ NIL, default: NAT _ 0, timeOut: NAT _ 0] RETURNS [select: INT _ 0] = BEGIN ENABLE UNWIND => UnLock[]; IF (choice=NIL) OR (choice.first=NIL) THEN RETURN WITH ERROR ChoiceError; Lock[]; IF text#NIL THEN InternalWriteRope[text]; IO.Flush[out ! RuntimeError.UNCAUGHT => CONTINUE]; Process.Pause[Process.MsecToTicks[5]]; --SILLY FLUSH DOESN'T WORK select _ PopUpMenu.RequestSelection[label, choice, default, timeOut]; UnLock[]; END; Confirm: PUBLIC PROC [choice: ROPE, label: ROPE _ NIL, timeOut: NAT _ 0, onTimeOut: BOOL _ FALSE] RETURNS [BOOL] = BEGIN RETURN [ SELECT RequestSelection[label: label, choice: LIST[choice], timeOut: timeOut] FROM 1 => TRUE, -1 => onTimeOut, ENDCASE => FALSE ] END; xProcess: PROCESS; xDoneCondition: CONDITION; xDone: Done _ no; xResult: Rope.ROPE; RequestRopeWithTimeout: PUBLIC PROC [text: ROPE _ NIL, timeOut: NAT _ 0] RETURNS [ROPE] = BEGIN IF timeOut=0 THEN RETURN [RequestRope[text]]; RETURN [MyRequestRopeWithTimeout[text, timeOut]]; END; MyRequestRopeWithTimeout: PROC [text: ROPE _ NIL, timeOut: NAT] RETURNS [ROPE_NIL] = BEGIN ENABLE UNWIND => UnLock[]; result: Rope.ROPE_NIL; done: Done; Lock[]; xDone _ no; TRUSTED { Process.SetTimeout[@xDoneCondition, Process.SecondsToTicks[timeOut]] }; StartRopeGetter[text]; TRUSTED {JOIN xProcess}; done _ xDone; result _ xResult; InputFocus.PopInputFocus[]; UnLock[]; IF xDone=abort THEN ERROR UserAbort; IF xDone#ok THEN ERROR TimedOut; IF Rope.Find[result, delRope]>=0 THEN ERROR UserAbort; RETURN [result] END; StartRopeGetter: ENTRY PROC [text: ROPE_NIL] = BEGIN ENABLE UNWIND => NULL; xProcess _ FORK ForkedTryToGetRope[text]; WAIT xDoneCondition; IF xDone#ok AND xDone#abort THEN TRUSTED {Process.Abort[xProcess]}; END; SetDone: ENTRY PROC [done: Done] = BEGIN ENABLE UNWIND => NULL; Process.CheckForAbort[]; xDone _ done; BROADCAST xDoneCondition; END; ForkedTryToGetRope: PROC [text: ROPE_NIL] = BEGIN ReallyTryToGetRope: PROC [text: ROPE] = BEGIN d: Done; DoIt: PROC [] = BEGIN ENABLE { UNWIND => IO.Reset[editedIn]; IO.Error => IF ec=StreamClosed THEN {d_repeat; IO.Reset[editedIn]; CONTINUE}; EditedStream.Rubout => {d_abort; IO.Reset[editedIn]; CONTINUE}; }; InternalWriteRope[text]; IF terminalParent.iconic THEN { terminalParent.column _ right; ViewerOps.OpenIcon[terminalParent]; }; xResult _ IO.GetLineRope[editedIn]; d _ ok; END; --DoIt DO d _ no; DoIt[]; IF d=ok OR d=abort THEN {SetDone[d]; RETURN}; IF d=repeat THEN InternalWriteRope["XXX\n"] ENDLOOP; END; --ReallyTryToGetRope ReallyTryToGetRope[text ! ABORTED => GOTO NeverMind] EXITS NeverMind => NULL; END; InternalWriteRope: PROC [text: ROPE] = BEGIN IF out=NIL THEN InternalCreateTerminal[]; IO.PutRope[out, text ! IO.Error => { IF ec=StreamClosed THEN { InternalCreateTerminal[]; IO.PutRope[out, text]; CONTINUE } }]; END; WriteRope: PUBLIC PROC [text: ROPE] = BEGIN ENABLE UNWIND => MyUnLock[]; MyLock[]; InternalWriteRope[text]; MyUnLock[] END; WriteRopes: PUBLIC PROC [t1, t2, t3: ROPE_NIL] = BEGIN ENABLE UNWIND => NULL; IF t1#NIL THEN WriteRope[t1]; IF t2#NIL THEN WriteRope[t2]; IF t3#NIL THEN WriteRope[t3]; END; WriteLn: PUBLIC PROC [] = BEGIN WriteRope["\n"]; END; WriteChar: PUBLIC PROC [ch: CHAR] = BEGIN WriteRope[Rope.FromChar[ch]]; END; WriteInt: PUBLIC PROC [i: INT] = BEGIN InternalWriteRope[IO.PutFR1[format: " %g", value: IO.int[i]]]; END; Write: PUBLIC PROC [v1, v2, v3: IO.Value] = BEGIN WriteRope[IO.PutR[v1, v2, v3]]; END; Write1: PUBLIC PROC [value: IO.Value] = BEGIN WriteRope[IO.PutR1[value]]; END; WriteF: PUBLIC PROC [format: ROPE _ NIL, v1, v2, v3, v4, v5: IO.Value] = BEGIN WriteRope[IO.PutFR[format, v1, v2, v3, v4, v5]]; END; WriteF1: PUBLIC PROC [format: ROPE _ NIL, value: IO.Value] = BEGIN WriteRope[IO.PutFR[format, value]]; END; TOS: PUBLIC PROC [] RETURNS [stream: IO.STREAM] = BEGIN RETURN[IO.CreateStream[streamProcs: TerminalIOStreamProcs, streamData: NIL]]; END; TerminalIOStreamProcs: REF IO.StreamProcs _ IO.CreateStreamProcs[ variety: $output, class: $TerminalIO, putChar: TerminalIOStreamPutChar, putBlock: TerminalIOStreamPutBlock, unsafePutBlock: TerminalIOStreamUnsafePutBlock, flush: TerminalIOStreamFlush, eraseChar: TerminalIOStreamEraseChar, reset: TerminalIOStreamFlush, close: TerminalIOStreamClose ]; TerminalIOStreamPutChar: ENTRY PROC [self: IO.STREAM, char: CHAR] = { IF out=NIL THEN InternalCreateTerminal[]; IO.PutChar[out, char ! IO.Error => { IF ec=StreamClosed THEN { InternalCreateTerminal[]; IO.PutChar[out, char]; CONTINUE } }]; }; TerminalIOStreamPutBlock: ENTRY PROC [self: IO.STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT] = { IF out=NIL THEN InternalCreateTerminal[]; IO.PutBlock[out, block, startIndex, count ! IO.Error => { IF ec=StreamClosed THEN { InternalCreateTerminal[]; IO.PutBlock[out, block, startIndex, count]; CONTINUE } }]; }; TerminalIOStreamUnsafePutBlock: ENTRY PROC [self: IO.STREAM, block: IO.UnsafeBlock] = { IF out=NIL THEN InternalCreateTerminal[]; IO.UnsafePutBlock[out, block ! IO.Error => { IF ec=StreamClosed THEN { InternalCreateTerminal[]; IO.UnsafePutBlock[out, block]; CONTINUE } }]; }; TerminalIOStreamFlush: PROC [self: IO.STREAM] = { }; TerminalIOStreamEraseChar: PROC [self: IO.STREAM, char: CHAR] = { }; TerminalIOStreamClose: PROC [self: IO.STREAM, abort: BOOL] = { }; CreateTerminal: Commander.CommandProc = BEGIN ENABLE UNWIND => MyUnLock[]; MyLock[]; InternalCreateTerminal[]; MyUnLock[]; END; Init: PROC [] = BEGIN terminalIcon _ Icons.NewIconFromFile["TerminalIO.icons", 0 ! RuntimeError.UNCAUGHT => CONTINUE]; inputIcon _ Icons.NewIconFromFile["TerminalIO.icons", 1 ! RuntimeError.UNCAUGHT => CONTINUE]; AddLock[MyLock, MyUnLock]; AddLock[ReaderLock, ReaderUnLock]; Commander.Register[key: "Terminal", proc: CreateTerminal, doc: "Create terminal viewer if it does not yet exist"]; END; Init[]; END. ώTerminalIOImpl.mesa Copyright c 1983, 1985 by Xerox Corporation. All rights reserved. By Ch. Jacobi August 3, 1983 9:54 am Last edited by Ch. Jacobi October 7, 1985 10:20:30 am PDT -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --Terminals own locking procedures --is set if process releases the monitorlock but waits still for input --conveniant to be here since in all places where UnLock is called -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --Lock, UnLock mechanism -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --creation of viewer -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --input procedures --RequestRope --RequestChar --RequestInt -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --timed out input --ReallyTryToGetRope --ForkedTryToGetRope -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --output procedures --an output stream which writes its output into the terminal -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ΚΛ˜codešœ™Kšœ Οmœ7™BKšœ$™$Kšœ9™9—K˜šΟk ˜ Kšœ žœ˜(Kšœ ˜ Kšœžœ"˜-Kšœ žœ!˜1Kšžœ˜K˜ Kšœ˜Kšœ˜Kšœ žœžœ˜K˜ Kšœ˜Kšœžœ ˜Kšœ žœ,˜:Kšœ žœ˜+Kšœ žœ˜!—K˜šΠblœžœž˜Kšžœ-žœJ˜€Kšžœ˜&—Kšž˜K˜Kšžœžœžœ˜K˜Kšœ žœžœžœ˜!Kšœ žœžœžœ˜ Kšœ%žœ˜)Kšœ žœžœ˜Kšœžœžœžœ˜#K˜K˜K˜Kšœžœžœžœ˜ Kšœ žœ˜#K™Kšœ;™;Kšœ"™"K˜šœžœžœ˜KšœF™F—Kšœž œΟc9˜KK˜šΟnœž œ˜Kšžœ˜šžœž˜Kšžœ˜ Kšžœ˜—Kšœžœ˜Kšžœ˜—K˜š‘ œžœ˜Kšžœ˜K˜ K˜5K˜/Kšžœ˜—K˜š‘œž œ˜Kšžœ˜Kšœžœ˜Kšž œ˜Kšžœ˜—K˜š‘ œžœ˜Kšžœ˜K˜#K˜!K˜/KšœC™CKšœ žœ˜&Kšžœ˜—K˜Kšœ8™8Kšœ™K˜Kš œ žœžœžœžœ˜Kšœžœ˜Kšœžœ˜K˜š ‘œžœžœžœžœ˜1šžœ˜Kšžœžœžœ˜—Kšœ žœ˜&Kšžœ žœžœ žœ˜*šž˜šžœ ž˜%Kš žœžœžœ žœžœ˜.Kšžœ˜——Kšžœ˜—K˜š‘œžœ˜ Kšž˜šžœ žœžœž˜1Kšœžœžœ˜,Kšž˜—Kšžœ˜—K˜š‘œžœ˜Kšž˜šžœ"žœžœž˜3Kšœžœžœ˜,Kšž˜—Kšžœ˜—K˜Kšœ;™;Kšœ™K˜š‘œžœ˜"Kšž˜KšœLžœžœ˜fKšœ6˜6Kšœ3˜3Kšžœžœžœžœ˜!šžœžœ˜Kšœ˜Kšœ#˜#Kšœ˜—K˜#Kšžœ˜—K˜Kšœ8™8Kšœ™K˜Kšœžœ.˜8K˜š‘œžœžœžœ˜)Kšž˜Kšœ˜šžœžœ˜Kšœ˜Kšœ#˜#Kšœ˜—Kšœ*˜*Kšœ)˜)Kšžœ˜—K˜š‘ œžœžœžœžœžœžœ˜<šžœ˜Kšžœžœ ˜—Kšœ ˜ Kšœžœ˜K˜š‘œžœ˜šžœ˜šžœž˜ Kš žœ žœžœžœžœ˜PKšœ$žœžœ˜BKšžœ˜——Kšœ˜Kšœžœ˜K˜Kšžœžœ ˜,Kšžœ˜K˜—Kšœ ™ Kšœ˜šž˜K˜ K˜Kšžœ žœ žœ˜&Kšžœžœ žœ˜5Kšžœ(žœ ˜>Kšžœ˜—Kšžœ˜—K˜š‘ œžœžœžœžœžœžœ˜<šžœ˜Kšžœžœ ˜—Kšœ ˜ Kšœžœ˜ K˜š‘œžœ˜šžœ˜šžœž˜ Kšžœ žœžœžœ˜Kšžœ˜—Kšžœ˜—K˜Kšœ žœžœ˜K˜š‘œžœžœ žœžœ žœžœžœžœžœ žœžœžœ žœ˜™šžœ˜Kšžœžœ ˜—Kšžœ žœžœžœžœžœžœžœ ˜IK˜Kšžœžœžœ˜)šžœžœžœ˜2Kšœ' ˜A—KšœE˜EK˜ Kšžœ˜—K˜š‘œžœžœ žœ žœžœ žœžœžœžœžœ˜rKšžœ˜šžœ˜šžœ(žœž˜RKšœžœ˜ Kšœ˜Kšžœž˜—Kšœ˜—Kšžœ˜—K˜K˜Kšœ8™8K™K™Jšœ žœ˜Jšœž œ˜Jšœ˜Jšœž˜J˜š‘œžœžœžœžœ žœžœžœ˜YJšž˜Kšžœ žœžœ˜-Jšžœ+˜1Jšžœ˜—J˜š‘œžœžœžœ žœžœžœžœ˜TJšž˜Kšžœžœ ˜Kšœ žœžœ˜Kšœ ˜ K˜Jšœ ˜ JšžœJ˜QJšœ˜Jšžœžœ ˜Jšœ ˜ Jšœ˜K˜Kšœ ˜ Jšžœ žœžœ ˜$Jšžœ žœžœ ˜ Kšžœžœžœ ˜6Jšžœ ˜Jšžœ˜—J˜š‘œžœžœžœ˜.Jšžœžœžœžœ˜Jšœ žœ˜)Jšžœ˜Jšžœ žœ žœžœ˜CJšžœ˜J˜—š‘œžœžœ˜"Jšžœžœžœžœ˜Jšœ˜Jšœ ˜ Jšž œ˜Jšžœ˜—J˜š‘œžœžœ˜+Jšž˜J˜š‘œžœžœ˜'Jšž˜Kšœ ˜ J˜š‘œžœ˜šžœ˜šžœ˜Jšžœžœ˜Kš žœ žœžœ žœž œ˜MKšœ!žœžœ˜?J˜——Kšœ˜šžœžœ˜Kšœ˜Kšœ#˜#Kšœ˜—Jšœ žœ˜#Jšœ˜Jšžœ ˜ J˜—Jšœ™šž˜K˜Kšœ˜Kšžœžœ žœžœ˜-Kšžœ žœ˜+Kšžœ˜—Jšžœ ˜—J™Jšœ™Jšœžœžœ ˜4Jšžœžœ˜Jšžœ˜—Kšœ8™8Kšœ™K˜š‘œžœžœ˜'Kšžœ˜Kšžœžœžœ˜)šžœžœ ˜$šžœžœ˜K˜Kšžœ˜Kšž˜K˜—Kšœ˜—Kšžœ˜—K˜š‘ œžœžœžœ˜&Kšžœžœžœ˜"Kšœ ˜ Kšœ˜Kšœ ˜ Kšžœ˜—K˜š ‘ œžœžœžœžœ˜1šžœ˜Kšžœžœžœ˜—Kšžœžœžœ˜Kšžœžœžœ˜Kšžœžœžœ˜Kšžœ˜—K˜š‘œžœžœ˜Kšžœ˜Kšœ˜Kšžœ˜—K˜š‘ œžœžœžœ˜$Kšžœ˜Kšœ˜Kšžœ˜—K˜š‘œžœžœžœ˜!Kšžœ˜Kšœžœžœ ˜>Kšžœ˜—K˜š‘œžœžœžœ ˜+Kšž˜Kšœ žœ˜Kšžœ˜—š‘œžœžœ žœ ˜'Kšž˜Kšœ žœ˜Kšžœ˜—š ‘œžœžœ žœžœžœ ˜HKšž˜Kšœ žœ$˜0Kšžœ˜—š ‘œžœžœ žœžœ žœ ˜žœ˜MKšžœ˜—šœžœžœžœ˜AK˜K˜Kšœ!˜!Kšœ#˜#Kšœ/˜/Kšœ˜Kšœ%˜%Kšœ˜Kšœ˜Kšœ˜—K˜š ‘œžœžœžœžœžœ˜EKšžœžœžœ˜)šžœžœ ˜$šžœžœ˜K˜Kšžœ˜Kšž˜K˜—Kšœ˜—Kšœ˜K˜—š‘œžœžœžœžœ žœžœžœžœ žœ˜qKšžœžœžœ˜)šžœ*žœ ˜9šžœžœ˜K˜Kšžœ)˜+Kšž˜K˜—Kšœ˜—Kšœ˜K˜—š ‘œžœžœžœžœ žœ˜WKšžœžœžœ˜)šžœžœ ˜,šžœžœ˜K˜Kšžœ˜Kšž˜K˜—Kšœ˜—Kšœ˜K˜—š‘œžœžœžœ˜1Kšœ˜K˜—š ‘œžœžœžœžœ˜AKšœ˜K˜—š ‘œžœžœžœ žœ˜>Kšœ˜—K˜Kšœ;™;K˜šΟbœ˜'Kšžœžœžœ˜"K˜ K˜K˜ Kšžœ˜—K˜š‘œžœ˜Kšž˜KšœJžœžœ˜`KšœGžœžœ˜]K˜Kšœ"˜"K˜rKšžœ˜—K˜Kšœ˜Kšžœ˜K˜—…—+fC/