DIRECTORY Ascii, Atom, FS USING [StreamOpen], EditedStream, IO, IOClasses USING [CreateDribbleOutputStream], IOUtils, MessageWindow USING [Append, Clear], RefText, Rope, TiogaOps USING [GetRope, GetTextKey, LastLocWithin, Location, PutTextKey, Ref, ViewerDoc], TypeScript USING [BackSpace, ChangeLooks, CharsAvailable, Create, Destroyed, Flush, GetChar, IsATypeScript, PutChar, TypeIn, WaitUntilCharsAvail], ViewerClasses USING [Viewer], ViewerEvents USING [EventProc, RegisterEventProc], ViewerIO USING [], ViewerOps USING [AddProp, FetchProp]; ViewerIOImpl: CEDAR PROGRAM IMPORTS Atom, EditedStream, FS, IO, IOClasses, IOUtils, MessageWindow, RefText, Rope, TiogaOps, TypeScript, ViewerEvents, ViewerOps EXPORTS ViewerIO = BEGIN STREAM: TYPE = IO.STREAM; ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; StreamProcs: TYPE = IO.StreamProcs; DeliverWhenProc: TYPE = EditedStream.DeliverWhenProc; TypeOfGetDeliverWhen: TYPE = PROC [self: STREAM] RETURNS [proc: DeliverWhenProc, context: REF ANY]; TypeOfSetDeliverWhen: TYPE = PROC [self: STREAM, proc: DeliverWhenProc, context: REF ANY]; TypeOfAppendBufferChars: TYPE = PROC [stream: STREAM, chars: ROPE]; TypeOfUnAppendBufferChars: TYPE = PROC [stream: STREAM, nChars: NAT]; TypeOfSetMode: TYPE = PROC [stream: STREAM, stuff: ROPE, pendingDelete: BOOL, echoAsterisks: BOOL]; ViewerStreamData: TYPE = REF ViewerStreamDataRecord; ViewerStreamDataRecord: TYPE = RECORD [ viewer: Viewer, echoStream: STREAM _ NIL ]; ViewerInStreamProcs: REF StreamProcs; ViewerOutStreamProcs: REF StreamProcs; ViewerOutPFProcs: IOUtils.PFProcs; CreateViewerStreams: PUBLIC PROC [ name: ROPE, viewer: Viewer, backingFile: ROPE, editedStream: BOOL] RETURNS [in: STREAM, out: STREAM] = { streams: LIST OF STREAM; IF viewer = NIL THEN viewer _ TypeScript.Create[info: [name: name, iconic: FALSE]] ELSE IF NOT TypeScript.IsATypeScript[viewer] THEN ERROR IO.Error[$Failure, NIL]; in _ IO.CreateStream[ streamProcs: ViewerInStreamProcs, streamData: NEW[ViewerStreamDataRecord _ [viewer: viewer]]]; IOUtils.StoreData[in, $Name, name]; out _ IO.CreateStream[ streamProcs: ViewerOutStreamProcs, streamData: NEW[ViewerStreamDataRecord _ [viewer: viewer]]]; IOUtils.StoreData[out, $Name, name]; [] _ IOUtils.SetPFProcs[out, ViewerOutPFProcs]; IF backingFile # NIL THEN out _ IOClasses.CreateDribbleOutputStream[ output1: out, output2: FS.StreamOpen[fileName: backingFile, accessOptions: $create]]; streams _ NARROW[ViewerOps.FetchProp[viewer: viewer, prop: $Streams]]; streams _ CONS[in, CONS[out, streams]]; ViewerOps.AddProp[viewer: viewer, prop: $Streams, val: streams]; IF editedStream THEN in _ CreateEditedViewerStream[in: in, echoTo: out, deliverWhen: EditedStream.IsACR] ELSE EditedStream.SetEcho[self: in, echoTo: out]; }; GetViewerFromStream: PUBLIC PROC [stream: STREAM] RETURNS [Viewer] = { WHILE stream # NIL DO WITH stream.streamData SELECT FROM r: ViewerStreamData => RETURN[r.viewer] ENDCASE => stream _ stream.backingStream; ENDLOOP; RETURN [NIL]; }; WasAStreamViewerDestroyed: ViewerEvents.EventProc = { streams: LIST OF STREAM = NARROW[ViewerOps.FetchProp[viewer, $Streams]]; v: Viewer _ viewer; IF streams = NIL THEN RETURN; WHILE (v _ v.link) # NIL AND (v # viewer) DO -- split viewer IF NOT v.destroyed THEN { FOR l: LIST OF STREAM _ streams, l.rest UNTIL l = NIL DO data: ViewerStreamData = NARROW[l.first.streamData]; data.viewer _ v; ENDLOOP; ViewerOps.AddProp[v, $Streams, streams]; RETURN; }; ENDLOOP; }; ViewerGetChar: PROC [self: STREAM] RETURNS [char: CHAR] = { data: ViewerStreamData = NARROW[self.streamData]; IF data.viewer.destroyed THEN ERROR IO.Error[$StreamClosed, self]; char _ TypeScript.GetChar[data.viewer ! TypeScript.Destroyed => IF data.viewer.destroyed THEN ERROR IO.Error[$StreamClosed, self] ELSE RETRY]; IF data.echoStream # NIL THEN data.echoStream.PutChar[char]; }; ViewerEndOf: PROC [self: STREAM] RETURNS [BOOL] = CHECKED { data: ViewerStreamData = NARROW[self.streamData]; IF data.viewer.destroyed THEN ERROR IO.Error[$StreamClosed, self]; RETURN[FALSE]; }; ViewerCharsAvail: PROC [self: STREAM, wait: BOOL] RETURNS [INT] = { data: ViewerStreamData = NARROW[self.streamData]; viewer: Viewer _ data.viewer; IF viewer = NIL OR viewer.destroyed THEN ERROR IO.Error[$StreamClosed, self]; IF wait THEN { TypeScript.WaitUntilCharsAvail[viewer ! TypeScript.Destroyed => IF viewer.destroyed THEN ERROR IO.Error[StreamClosed, self] ELSE RETRY]; RETURN[1] } ELSE RETURN[IF TypeScript.CharsAvailable[viewer] THEN 1 ELSE 0]; }; ViewerSetEcho: PROC [self: STREAM, echoTo: STREAM] = { data: ViewerStreamData = NARROW[self.streamData]; IF data.viewer.destroyed THEN ERROR IO.Error[$StreamClosed, self]; data.echoStream _ echoTo; }; ViewerGetEcho: PROC [self: STREAM] RETURNS [oldEcho: STREAM] = { data: ViewerStreamData = NARROW[self.streamData]; IF data.viewer.destroyed THEN ERROR IO.Error[$StreamClosed, self]; RETURN [data.echoStream]; }; ViewerPutChar: PROC[self: STREAM, char: CHAR] = { data: ViewerStreamData = NARROW[self.streamData]; IF data.viewer.destroyed THEN ERROR IO.Error[$StreamClosed, self]; TypeScript.PutChar[data.viewer, char ! TypeScript.Destroyed => IF data.viewer.destroyed THEN ERROR IO.Error[$StreamClosed, self] ELSE RETRY]; }; ViewerFlush: PROC[self: STREAM] = { data: ViewerStreamData = NARROW[self.streamData]; IF data.viewer.destroyed THEN ERROR IO.Error[$StreamClosed, self]; TypeScript.Flush[data.viewer]; }; ViewerEraseChar: PROC[self: STREAM, char: CHAR] = { data: ViewerStreamData = NARROW[self.streamData]; WHILE data.viewer.destroyed DO IF data.viewer.link # NIL THEN data.viewer _ data.viewer.link ELSE ERROR IO.Error[$StreamClosed, self]; ENDLOOP; TypeScript.BackSpace[data.viewer]; }; ViewerReset: PROC [self: STREAM] = { ENABLE TypeScript.Destroyed => GO TO bye; data: ViewerStreamData = NARROW[self.streamData]; viewer: Viewer = data.viewer; IF viewer = NIL OR viewer.destroyed THEN RETURN; TypeScript.ChangeLooks[viewer, ' ]; DO IF NOT TypeScript.CharsAvailable[viewer] THEN GO TO bye; [] _ TypeScript.GetChar[viewer]; ENDLOOP; EXITS bye => {}; }; ViewerSetLooks: IOUtils.PFCodeProc = { viewer: Viewer = GetViewerFromStream[stream]; looks: ROPE _ NIL; IF viewer = NIL THEN ERROR IO.Error[$NotImplementedForThisStream, stream]; TRUSTED { WITH v: val SELECT FROM null => NULL; atom => looks _ Atom.GetPName[v.value]; rope => looks _ v.value; character => looks _ Rope.FromChar[v.value]; ENDCASE => ERROR IO.Error[$NotImplementedForThisStream, stream] }; FOR i: INT IN [0..Rope.Length[looks]) DO TypeScript.ChangeLooks[viewer, Rope.Fetch[looks, i]]; ENDLOOP; }; Location: TYPE = TiogaOps.Location; EditedViewerStreamData: TYPE = REF EditedViewerStreamRecord; EditedViewerStreamRecord: TYPE = RECORD[ ready: REF TEXT, readyPos: INT _ 0, -- ready[readyPos .. ready.length) are the already-activated characters buffer: REF TEXT, echoStream: STREAM, deliverWhen: DeliverWhenProc, context: REF ANY, bufferIsConsistent: BOOL _ FALSE, viewer: Viewer, node: TiogaOps.Ref ]; EditedViewerStreamProcs: REF StreamProcs; CreateEditedViewerStream: PROC [ in: STREAM, echoTo: STREAM, deliverWhen: DeliverWhenProc, context: REF ANY _ NIL] RETURNS [STREAM] = { data: EditedViewerStreamData; data _ NEW[EditedViewerStreamRecord _ [ buffer: NEW[TEXT[256]], ready: NEW[TEXT[256]], readyPos: 0, echoStream: echoTo, deliverWhen: deliverWhen, context: context, viewer: NARROW[in.streamData, ViewerStreamData].viewer, node: NIL]]; RETURN [IO.CreateStream[ streamProcs: EditedViewerStreamProcs, streamData: data, backingStream: in]] }; GetBuffer: PUBLIC PROC [editedViewerStream: STREAM] RETURNS [REF TEXT] = { data: EditedViewerStreamData = NARROW[editedViewerStream.streamData]; GetCurrentBuffer1[data]; RETURN [data.buffer]; }; TypeChars: PUBLIC PROC [editedViewerStream: STREAM, chars: ROPE] = { data: EditedViewerStreamData = NARROW[editedViewerStream.streamData]; TypeScript.TypeIn[data.viewer, chars]; }; GetCurrentBuffer: PROC [data: EditedViewerStreamData] = INLINE { IF data.bufferIsConsistent THEN RETURN ELSE GetCurrentBuffer1[data]; }; GetCurrentBuffer1: PROC [data: EditedViewerStreamData] = { r: ROPE; loc: Location; data.buffer.length _ 0; data.bufferIsConsistent _ TRUE; IF data.node = NIL THEN RETURN; TypeScript.Flush[data.viewer]; r _ TiogaOps.GetRope[data.node]; loc _ TiogaOps.GetTextKey[node: data.node, key: data]; IF loc.node # data.node THEN ERROR; { Put: PROC [c: CHAR] RETURNS [quit: BOOL] = { data.buffer _ RefText.InlineAppendChar[data.buffer, c]; RETURN [quit: FALSE] }; [] _ Rope.Map[base: r, start: loc.where + 1, len: INT.LAST, action: Put]; }; }; EditedViewerStreamAppendBufferChars: PROC [stream: STREAM, chars: ROPE] = { data: EditedViewerStreamData = NARROW[stream.streamData]; Append1: PROC [c: CHAR] RETURNS [quit: BOOL] = { AppendBufferChar[data, c]; RETURN [quit: FALSE] }; GetCurrentBuffer1[data]; [] _ chars.Map[action: Append1]; }; AppendBufferChar: PROC [data: EditedViewerStreamData, char: CHAR] = INLINE { loc: Location; data.buffer _ RefText.InlineAppendChar[data.buffer, char]; IF data.node = NIL THEN { TypeScript.Flush[data.viewer]; loc _ TiogaOps.LastLocWithin[TiogaOps.ViewerDoc[data.viewer]]; IF loc.where = 0 THEN data.echoStream.PutChar[' ] ELSE loc.where _ loc.where - 1; }; data.echoStream.PutChar[char]; IF data.node = NIL THEN { TypeScript.Flush[data.viewer]; TiogaOps.PutTextKey[node: loc.node, where: loc.where, key: data]; data.node _ loc.node; }; }; EditedViewerStreamUnAppendBufferChars: PROC [stream: STREAM, nChars: NAT] = { data: EditedViewerStreamData = NARROW[stream.streamData]; GetCurrentBuffer1[data]; FOR i: NAT IN [0 .. MIN[nChars, data.buffer.length]) DO UnAppendBufferChar[data] ENDLOOP; }; UnAppendBufferChar: PROC [data: EditedViewerStreamData] = INLINE { char: CHAR = data.buffer[data.buffer.length - 1]; data.echoStream.EraseChar[char]; data.buffer.length _ data.buffer.length - 1; IF data.buffer.length = 0 THEN data.node _ NIL; }; EditedViewerStreamSetMode: PROC [stream: STREAM, stuff: ROPE, pendingDelete: BOOL, echoAsterisks: BOOL] = { data: EditedViewerStreamData = NARROW[stream.streamData]; data.buffer.length _ 0; data.readyPos _ data.ready.length; EditedViewerStreamAppendBufferChars[stream, stuff]; }; EditedViewerStreamGetDeliverWhen: PROC [self: STREAM] RETURNS [proc: DeliverWhenProc, context: REF ANY] = { data: EditedViewerStreamData = NARROW[self.streamData]; RETURN [data.deliverWhen, data.context]; }; EditedViewerStreamSetDeliverWhen: PROC [self: STREAM, proc: DeliverWhenProc, context: REF ANY] = { data: EditedViewerStreamData = NARROW[self.streamData]; data.deliverWhen _ proc; data.context _ context; }; EditedViewerStreamGetChar: PROC [self: STREAM] RETURNS [char: CHAR] = { data: EditedViewerStreamData = NARROW[self.streamData]; IsEditCommand: PROC [char: CHAR] RETURNS [BOOL] = { RETURN [SELECT char FROM Ascii.DEL, Ascii.ControlA, Ascii.BS, Ascii.ControlW, Ascii.ControlQ => TRUE, ENDCASE => FALSE]; }; BackChar: PROC = { IF data.buffer.length > 0 THEN { UnAppendBufferChar[data]; } }; BackWord: PROC = { alphaSeen: BOOL _ FALSE; UNTIL data.buffer.length = 0 DO SELECT data.buffer[data.buffer.length - 1] FROM IN ['A..'Z], IN ['a..'z], IN ['0..'9] => alphaSeen _ TRUE; ENDCASE => IF alphaSeen THEN EXIT; UnAppendBufferChar[data]; ENDLOOP; }; BackLine: PROC = { UNTIL data.buffer.length = 0 DO IF data.buffer[data.buffer.length - 1] = IO.CR THEN EXIT; UnAppendBufferChar[data]; ENDLOOP; }; DO IF data.readyPos < data.ready.length THEN { char _ data.ready[data.readyPos]; data.readyPos _ data.readyPos + 1; RETURN [char]; }; { appendChar, activate: BOOL; char _ self.backingStream.GetChar[ ! IO.EndOfStream => IF data.buffer.length = 0 THEN REJECT ELSE GOTO activateBuffer]; [appendChar: appendChar, activate: activate] _ data.deliverWhen[char, NIL --data.buffer--, self, data.context]; IF appendChar THEN { SELECT char FROM Ascii.DEL => { ENABLE UNWIND => data.buffer.length _ 0; ERROR EditedStream.Rubout[self]; }; Ascii.ControlA, Ascii.BS => { GetCurrentBuffer1[data]; BackChar[] }; Ascii.ControlW => { GetCurrentBuffer1[data]; BackWord[] }; Ascii.ControlQ => { GetCurrentBuffer1[data]; BackLine[] }; Ascii.ESC => { GetCurrentBuffer1[data]; IF data.buffer.length = 0 THEN { FOR i: NAT IN [0..data.ready.length-1) DO AppendBufferChar[data, data.ready[i]]; ENDLOOP } }; ENDCASE => { IF data.buffer.length = 0 THEN GetCurrentBuffer1[data]; AppendBufferChar[data, char]; } }; IF activate THEN GOTO activateBuffer; EXITS activateBuffer => { GetCurrentBuffer1[data]; data.ready.length _ 0; data.ready _ RefText.Append[data.ready, data.buffer]; data.readyPos _ 0; data.buffer.length _ 0; data.node _ NIL; } } ENDLOOP; }; EditedViewerStreamEndOf: PROC [self: STREAM] RETURNS [BOOL] = { data: EditedViewerStreamData = NARROW[self.streamData]; RETURN[data.readyPos = data.ready.length AND self.backingStream.EndOf[]]; }; EditedViewerStreamCharsAvail: PROC [self: STREAM, wait: BOOL] RETURNS [INT] = { data: EditedViewerStreamData = NARROW[self.streamData]; IF data.readyPos < data.ready.length THEN RETURN [data.ready.length-data.readyPos]; RETURN[self.backingStream.CharsAvail[wait]]; }; EditedViewerStreamBackup: PROC [self: STREAM, char: CHAR] = { data: EditedViewerStreamData = NARROW[self.streamData]; IF data.readyPos = 0 OR data.ready[data.readyPos - 1] # char THEN ERROR IO.Error[$IllegalBackup, self]; data.readyPos _ data.readyPos - 1; }; EditedViewerStreamSetEcho: PROC [self: STREAM, echoTo: STREAM] = { data: EditedViewerStreamData = NARROW[self.streamData]; IF echoTo = NIL THEN RETURN; -- ignore request to turn off echoing IF data.echoStream # echoTo THEN ERROR IO.Error[$Failure, self]; }; EditedViewerStreamGetEcho: PROC [self: STREAM] RETURNS [STREAM] = { data: EditedViewerStreamData = NARROW[self.streamData]; RETURN [data.echoStream]; }; EditedViewerStreamReset: PROC [self: STREAM] = { data: EditedViewerStreamData = NARROW[self.streamData]; data.node _ NIL; data.buffer.length _ 0; data.ready.length _ 0; data.readyPos _ 0; self.backingStream.Reset[]; data.echoStream.Reset[]; }; MessageWindowStreamProcs: REF StreamProcs; CreateMessageWindowStream: PUBLIC PROC [] RETURNS [STREAM] = { RETURN[IO.CreateStream[ streamProcs: MessageWindowStreamProcs, backingStream: IO.ROS[], streamData: NIL]]; }; MessageWindowStreamFlush: PROC[self: STREAM] = { r: ROPE _ self.backingStream.RopeFromROS[close: FALSE]; i: INT _ 0; self.backingStream.Reset[]; WHILE (i _ Rope.Find[s1: r, s2: "\n", pos1: i]) # -1 DO r _ Rope.Replace[base: r, start: i, len: 1, with: " "]; ENDLOOP; MessageWindow.Append[message: r, clearFirst: TRUE] }; MessageWindowStreamReset: PROC[self: STREAM] = { self.backingStream.Reset[]; MessageWindow.Clear[] }; [] _ ViewerEvents.RegisterEventProc [ proc: WasAStreamViewerDestroyed, filter: $Typescript, event: $destroy]; ViewerInStreamProcs _ EditedStream.AddStreamProcs[to: IO.CreateStreamProcs[ variety: $input, class: $ViewersInput, getChar: ViewerGetChar, endOf: ViewerEndOf, charsAvail: ViewerCharsAvail, reset: ViewerReset], setEcho: ViewerSetEcho, getEcho: ViewerGetEcho]; ViewerOutStreamProcs _ IO.CreateStreamProcs[ variety: $output, class: $ViewersOutput, putChar: ViewerPutChar, flush: ViewerFlush, eraseChar: ViewerEraseChar, reset: ViewerReset]; ViewerOutPFProcs _ IOUtils.CopyPFProcs[NIL]; [] _ IOUtils.SetPFCodeProc[ViewerOutPFProcs, 'l, ViewerSetLooks]; EditedViewerStreamProcs _ EditedStream.AddStreamProcs[to: IO.CreateStreamProcs[ variety: $input, class: $EditedViewer, getChar: EditedViewerStreamGetChar, endOf: EditedViewerStreamEndOf, charsAvail: EditedViewerStreamCharsAvail, backup: EditedViewerStreamBackup, reset: EditedViewerStreamReset], setEcho: EditedViewerStreamSetEcho, getEcho: EditedViewerStreamGetEcho]; IOUtils.StoreProc[EditedViewerStreamProcs, $GetDeliverWhen, NEW[TypeOfGetDeliverWhen _ EditedViewerStreamGetDeliverWhen]]; IOUtils.StoreProc[EditedViewerStreamProcs, $SetDeliverWhen, NEW[TypeOfSetDeliverWhen _ EditedViewerStreamSetDeliverWhen]]; IOUtils.StoreProc[EditedViewerStreamProcs, $AppendBufferChars, NEW[TypeOfAppendBufferChars _ EditedViewerStreamAppendBufferChars]]; IOUtils.StoreProc[EditedViewerStreamProcs, $UnAppendBufferChars, NEW[TypeOfUnAppendBufferChars _ EditedViewerStreamUnAppendBufferChars]]; IOUtils.StoreProc[EditedViewerStreamProcs, $SetMode, NEW[TypeOfSetMode _ EditedViewerStreamSetMode]]; MessageWindowStreamProcs _ IO.CreateStreamProcs[ variety: $output, class: $MessageWindow, flush: MessageWindowStreamFlush, reset: MessageWindowStreamReset ]; END. ”ViewerIOImpl.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. MBrown on January 13, 1984 1:42 pm Russ Atkinson, November 5, 1984 8:56:31 pm PST Doug Wyatt, April 9, 1985 4:39:37 pm PST -- CreateViewerStreams should not raise IO.Error[$Failure], should not raise FS.Error? -- Should Destroy of a viewer cause implicit Close? -- WasAStreamViewerDestroyed seems to require monitor protection in its access to the stream. -- Why is Close not implemented for Viewer streams? -- What if node goes away in AppendBufferChar? -- Edited stream backup does not allow backup past ready chars, should it? -- SetEcho with stream in the backed-up state should be some sort of error? Viewer Input and Output Streams (Typescript) Types This type is used for both input and output stream; the echoStream field is ignored for output streams. A ViewerStreamDataRecord is not shared between multiple streams. Creation make all streams attached to the viewer about to be destroyed attached to this undestroyed child Input procs If a split viewer is destroyed while a process is inside of a call to TypeScript.GetChar on that viewer, TypeScript.Destroyed is raised in that process. Before TypeScript.Destroyed is raised, data.viewer on any stream for this viewer will have been replaced by one of the other viewers (viewers calls WasAStreamViewerDestroyed below); hence the RETRY will call TypeScript.GetChar on another viewer. The same logic is used in ViewerCharsAvail and ViewerPutChar. Output procs Note, we cannot use TypeScript.Flush, since it tosses all of our nice state on the floor. Put the looks back into their ground state. Edited Viewer Input Stream (Editable Typescript) in is a Viewer input stream and EditedStream.GetEcho[in] = NIL. echoTo is a Viewer output stream for the same viewer as in, or is a dribble stream. Called from EditedViewerStreamAppendBufferChars, EditedViewerStreamUnAppendBufferChars, EditedViewerStreamGetChar Makes data.buffer consistent with current state of the underlying viewer This is the only proc that tests the state of data.bufferIsConsistent -- RefText.AppendRope[to: data.buffer, from: r, start: loc.where + 1]; Assumes data.buffer is consistent What if node goes away? What if node goes away? Assumes data.buffer is consistent erases last character, if any, in buffer erases last "word" (consecutive run of letters and numbers), if any, in buffer erases buffer back to (not including) previous CR, if any GetCurrentBuffer[data]; looks wrong ... why can't you backup past ready chars? Can't change echo stream, because "truth" about buffered characters is stored in Tioga document behind echo stream. Message Window Stream Module Initialization ΚA– "Cedar" style˜codešœ™Kšœ Οmœ7™BKšœ Οc™"K™.K™(K™KšžV™VKšž3™3Kšž]™]Kšž3™3Kšž.™.KšžJ™JKšžK™K—K˜šΟk ˜ Kšœ˜Kšœ˜KšŸœŸœ˜Kšœ ˜ KšŸœ˜Kšœ Ÿœ˜,Kšœ˜KšœŸœ˜$Kšœ ˜ Kšœ˜Kšœ ŸœL˜ZKšœ Ÿœ‚˜’KšœŸœ ˜Kšœ Ÿœ ˜2Kšœ Ÿœ˜Kšœ Ÿœ˜%—K˜KšΠbl œŸœŸ˜KšŸœŸœŸœa˜ƒKšŸœ ˜šœŸ˜K˜KšŸœŸœŸœŸœ˜KšŸœŸœŸœ˜K˜KšœŸœ˜$Kšœ ŸœŸœ ˜#KšœŸœ ˜5KšΟnœŸœŸœŸœŸœ"ŸœŸœ˜cKš ‘œŸœŸœŸœ"ŸœŸœ˜ZKš ‘œŸœŸœ Ÿœ Ÿœ˜CKš ‘œŸœŸœ Ÿœ Ÿœ˜Eš ‘ œŸœŸœ Ÿœ ŸœŸœ˜MKšœŸœ˜——™,šœ™šœŸœŸœ˜4Kšœ©™©—šœŸœŸœ˜'K˜Kšœ ŸœŸ˜K˜—KšœŸœ ˜%KšœŸœ ˜&Kšœ"˜"—™š‘œŸœŸœ˜"KšœŸœŸœŸœ˜BKšŸœŸœŸœ˜%Kšœ ŸœŸœŸœ˜KšŸœ ŸœŸœ7Ÿœ˜RKšŸœŸœŸœ"ŸœŸœŸœŸœ˜PšœŸœ˜Kšœ!˜!Kšœ Ÿœ-˜<—Kšœ#˜#šœŸœ˜Kšœ"˜"Kšœ Ÿœ-˜<—Kšœ$˜$Kšœ/˜/šŸœŸœŸœ+˜DKšœ ˜ Kšœ Ÿœ<˜G—Kšœ Ÿœ6˜FKšœ ŸœŸœ˜'Kšœ@˜@šŸœŸ˜KšœS˜S—KšŸœ-˜1K˜—š ‘œŸœŸœ ŸœŸœ ˜FšŸœ ŸœŸ˜šŸœŸœŸ˜"KšœŸœ ˜'KšŸœ"˜)—KšŸœ˜—KšŸœŸœ˜ K˜—šΟbœ˜5Kš œ ŸœŸœŸœŸœ(˜HK˜KšŸœ ŸœŸœŸœ˜š ŸœŸœŸœŸœž˜<šŸœŸœ Ÿœ˜Kšœa™aš ŸœŸœŸœŸœŸœŸœŸ˜8KšœŸœ˜4K˜KšŸœ˜—Kšœ)˜)KšŸœ˜K˜—KšŸœ˜ —K˜——™ š ‘ œŸœŸœŸœŸœ˜˜>Kš ŸœŸœŸœŸœŸœŸœ˜N—Kšœ˜—š‘ œŸœŸœ˜#KšœŸœ˜1KšŸœŸœŸœŸœ˜BK˜Kšœ˜—š‘œŸœŸœŸœ˜3KšœŸœ˜1šŸœŸ˜KšŸœŸœŸœ˜=KšŸœŸœŸœ˜)KšŸœ˜—K˜"Kšœ˜—š‘ œŸœŸœ˜$KšœY™YKšŸœŸœŸœ˜)KšœŸœ˜1K˜Kš Ÿœ ŸœŸœŸœŸœ˜0šœ$˜$Kšœ+™+—šŸ˜Kš ŸœŸœ#ŸœŸœŸœ˜8Kšœ ˜ KšŸœ˜—KšŸœ ˜Kšœ˜—š’œ˜'K˜-KšœŸœŸœ˜Kš Ÿœ ŸœŸœŸœŸœ-˜JšŸœŸœŸœŸ˜!KšœŸœ˜ K˜'K˜K˜,KšŸœŸœŸœ/˜B—šŸœŸœŸœŸ˜(Kšœ5˜5KšŸœ˜—K˜———™0Kšœ Ÿœ˜#KšœŸœŸœ˜<šœŸœŸœ˜(KšœŸœŸœ˜Kšœ ŸœžG˜ZKšœŸœŸœ˜Kšœ Ÿœ˜K˜Kšœ ŸœŸœ˜KšœŸœŸœ˜!Kšœ˜Kšœ˜K˜—KšœŸœ ˜)š‘œŸœ˜ Kš œŸœ Ÿœ)ŸœŸœŸœ˜QKšŸœŸœ˜Kšœ;Ÿœ™?KšœS™SKšœ˜šœŸœ˜(KšœŸœŸœ˜KšœŸœŸœ˜Kšœ ˜ Kšœ˜Kšœ+˜+KšœŸœ)˜7KšœŸœ˜ —šŸœŸœ˜KšœK˜K—Kšœ˜—š‘ œŸœŸœŸœŸœŸœŸœ˜JKšœŸœ ˜EKšœ˜KšŸœ˜Kšœ˜—š ‘ œŸœŸœŸœ Ÿœ˜DKšœŸœ ˜EKšœ&˜&Kšœ˜—š‘œŸœ"Ÿœ˜@Kšœq™qKšœH™HKšœE™EKšŸœŸœŸœŸœ˜DKšœ˜—š‘œŸœ#˜:KšœŸœ˜Kšœ˜KšœŸœ˜KšŸœ ŸœŸœŸœ˜Kšœ˜Kšœ ˜ Kšœ6˜6KšŸœŸœŸœ˜#šœ˜KšœF™Fš ‘œŸœŸœŸœŸœ˜,Kšœ7˜7KšŸœŸœ˜Kšœ˜—Kšœ2ŸœŸœ˜IKšœ˜—K˜—š‘#œŸœ Ÿœ Ÿœ˜KKšœŸœ˜9š ‘œŸœŸœŸœŸœ˜0KšœŸœŸœ˜2—Kšœ˜Kšœ ˜ K˜—š‘œŸœ&ŸœŸœ˜LKšœ!™!K˜K˜:šŸœ ŸœŸœ˜Kšœ˜šœ>˜>Kšœ™—KšŸœŸœŸœ˜QKšœ˜—Kšœ˜šŸœ ŸœŸœ˜Kšœ˜šœA˜AKšœ™—Kšœ˜K˜—Kšœ˜—š‘%œŸœ Ÿœ Ÿœ˜MKšœŸœ˜9Kšœ˜š ŸœŸœŸœŸœŸ˜7Kšœ˜KšŸœ˜—K˜—š‘œŸœ"Ÿœ˜BKšœ!™!KšœŸœ'˜1Kšœ ˜ K˜,KšŸœŸœ Ÿœ˜/Kšœ˜—š ‘œŸœ Ÿœ ŸœŸœŸœ˜lKšœŸœ˜9K˜Kšœ"˜"Kšœ3˜3K˜—š ‘ œŸœŸœŸœ"ŸœŸœ˜kKšœŸœ˜7KšŸœ"˜(K˜—š ‘ œŸœŸœ"ŸœŸœ˜bKšœŸœ˜7Kšœ1˜1K˜—š ‘œŸœŸœŸœŸœ˜GKšœŸœ˜7š ‘ œŸœŸœŸœŸœ˜3šŸœŸœŸ˜KšœŸœŸœ$Ÿœ˜LKšŸœŸœ˜—Kšœ˜—š‘œŸœ˜Kšœ(™(šŸœŸœ˜ K˜Kšœ˜—Kšœ˜—š‘œŸœ˜KšœN™NKšœ ŸœŸœ˜šŸœŸ˜šŸœ%Ÿ˜/KšŸœ Ÿœ ŸœŸœ˜:KšŸœŸœ ŸœŸœ˜"—K˜KšŸœ˜—Kšœ˜—š‘œŸœ˜Kšœ/Ÿœ™9šŸœŸ˜Kš Ÿœ'ŸœŸœŸœŸœ˜9K˜KšŸœ˜—Kšœ˜—šŸ˜šŸœ#Ÿœ˜+Kšœ!˜!K˜"KšŸœ˜Kšœ˜—˜KšœŸœ˜šœ%Ÿœ˜6Kš ŸœŸœŸœŸœŸœ˜@—Kšœ™šœ.˜.KšœŸœžœ˜@—šŸœ Ÿœ˜šŸœŸ˜šœŸœŸœŸœ˜7KšŸœ˜ K˜—KšœŸœ,˜DKšœ:˜:Kšœ:˜:šœŸœ˜Kšœ˜šŸœŸœ˜ šŸœŸœŸœŸ˜)K˜&KšŸ˜—K˜—K˜—šŸœ˜ KšŸœŸœ˜7Kšœ˜K˜——K˜—KšŸœ ŸœŸœ˜%šŸœ˜Kšœ˜Kšœ˜K˜5Kšœ˜K˜Kšœ Ÿœ˜K˜—K˜—KšŸœ˜—Kšœ˜—š ‘œŸœŸœŸœŸœ˜?KšœŸœ˜7KšŸœ#Ÿœ˜JKšœ˜—š ‘œŸœŸœŸœŸœŸœ˜OKšœŸœ˜7KšŸœ#ŸœŸœ#˜SKšŸœ&˜,Kšœ˜—š‘œŸœŸœŸœ˜=Kšœ6™6KšœŸœ˜7šŸœŸœ&Ÿ˜AKšŸœŸœ˜%—Kšœ"˜"Kšœ˜—š‘œŸœŸœ Ÿœ˜BKšœŸœ˜7Kš Ÿœ ŸœŸœŸœž%˜CšŸœŸœŸœŸœ˜@Kšœs™s—Kšœ˜—š ‘œŸœŸœŸœŸœ˜CKšœŸœ˜7KšŸœ˜Kšœ˜—š‘œŸœŸœ˜0KšœŸœ˜7Kšœ Ÿœ˜K˜K˜K˜K˜Kšœ˜Kšœ˜——™šœŸœ ˜*K˜—š ‘œŸœŸœŸœŸœ˜?šŸœŸœ˜Kšœ6ŸœŸœŸœ˜R—Kšœ˜—K˜š‘œŸœŸœ˜0KšœŸœ)Ÿœ˜7KšœŸœ˜ Kšœ˜šŸœ0Ÿ˜7Kšœ7˜7KšŸœ˜—Kšœ-Ÿœ˜2Kšœ˜—K˜š‘œŸœŸœ˜0Kšœ˜Kšœ˜Kšœ˜——™˜%K˜G—šœ6Ÿœ˜KKšœ&˜&K˜K˜K˜Kšœ˜Kšœ˜Kšœ˜—šœŸœ˜,Kšœ(˜(K˜K˜Kšœ˜Kšœ˜—Kšœ'Ÿœ˜,KšœA˜Ašœ:Ÿœ˜OK˜&K˜#K˜K˜)K˜!K˜ Kšœ#˜#Kšœ$˜$šœ*˜*KšœŸœ;˜O—šœ*˜*KšœŸœ;˜O—šœ*˜*KšœŸœA˜X—šœ*˜*KšœŸœE˜^—šœ*˜*Kšœ Ÿœ-˜:——šœŸœ˜0Kšœ(˜(K˜ K˜K˜——K˜KšŸœ˜—…—@L`!