DIRECTORY Ascii, Atom, EditedStream, IO, IOUtils, Rope, RefText, RuntimeError USING [BoundsFault]; IOEditedStreamImpl: CEDAR PROGRAM IMPORTS IO, IOUtils, RefText, Rope, RuntimeError EXPORTS EditedStream SHARES IO --for representation of StreamProcs = BEGIN STREAM: TYPE = IO.STREAM; ROPE: TYPE = Rope.ROPE; StreamProcs: TYPE = IO.StreamProcs; TypeOfSetEcho: TYPE = PROC [self: STREAM, echoTo: STREAM]; TypeOfGetEcho: TYPE = PROC [self: STREAM] RETURNS [oldEcho: STREAM]; 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 _ NIL]; 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]; InlineLookupProc: PROC [self: STREAM, operation: ATOM] RETURNS [proc: REF ANY] = INLINE { FOR l: Atom.PropList _ self.streamProcs.propList, l.rest UNTIL l = NIL DO IF l.first.key = operation THEN RETURN[l.first.val]; ENDLOOP; }; GetDeliverWhen: PUBLIC PROC [self: STREAM] RETURNS [proc: DeliverWhenProc, context: REF ANY] = { p: REF ANY = InlineLookupProc[self, $GetDeliverWhen]; IF p # NIL THEN { [proc, context] _ (NARROW[p, REF TypeOfGetDeliverWhen])^ [self]; RETURN } ELSE ERROR IO.Error[$NotImplementedForThisStream, self]; }; SetDeliverWhen: PUBLIC PROC [self: STREAM, proc: DeliverWhenProc, context: REF ANY] = { p: REF ANY = InlineLookupProc[self, $SetDeliverWhen]; IF p # NIL THEN { (NARROW[p, REF TypeOfSetDeliverWhen])^ [self, proc, context]; RETURN } ELSE ERROR IO.Error[$NotImplementedForThisStream, self]; }; AppendBufferChars: PUBLIC PROC [stream: STREAM, chars: ROPE] = { p: REF ANY = InlineLookupProc[stream, $AppendBufferChars]; IF p # NIL THEN { (NARROW[p, REF TypeOfAppendBufferChars])^ [stream, chars]; RETURN } ELSE ERROR IO.Error[$NotImplementedForThisStream, stream]; }; UnAppendBufferChars: PUBLIC PROC [stream: STREAM, nChars: NAT] = { p: REF ANY = InlineLookupProc[stream, $UnAppendBufferChars]; IF p # NIL THEN { (NARROW[p, REF TypeOfUnAppendBufferChars])^ [stream, nChars]; RETURN } ELSE ERROR IO.Error[$NotImplementedForThisStream, stream]; }; SetMode: PUBLIC PROC [stream: STREAM, stuff: ROPE, pendingDelete: BOOL, echoAsterisks: BOOL] = { p: REF ANY = InlineLookupProc[stream, $SetMode]; IF p # NIL THEN { (NARROW[p, REF TypeOfSetMode])^ [stream, stuff, pendingDelete, echoAsterisks]; RETURN } ELSE ERROR IO.Error[$NotImplementedForThisStream, stream]; }; Rubout: PUBLIC ERROR [stream: STREAM] = CODE; EditedStreamData: TYPE = REF EditedStreamRecord; EditedStreamRecord: TYPE = RECORD[ ready: REF TEXT, readyPos: INT _ 0, -- ready[readyPos .. ready.length) are the already-activated characters buffer: REF TEXT, echoStream: STREAM _ NIL, deliverWhen: DeliverWhenProc, context: REF ANY, echoAsterisks: BOOL _ FALSE, pendingDelete: BOOL _ FALSE ]; EditedStreamProcs: REF StreamProcs; IsACR: PUBLIC DeliverWhenProc = { RETURN [appendChar: TRUE, activate: char = IO.CR] }; Create: PUBLIC PROC [in: STREAM, echoTo: STREAM, deliverWhen: DeliverWhenProc, context: REF ANY] RETURNS [STREAM] = { h: STREAM _ IO.CreateStream[ streamProcs: EditedStreamProcs, streamData: NEW[EditedStreamRecord _ [ buffer: NEW[TEXT[256]], ready: NEW[TEXT[256]], deliverWhen: deliverWhen, context: context]], backingStream: in ]; SetEcho[in, NIL]; SetEcho[h, echoTo]; RETURN [h] }; EditedStreamAppendBufferChars: PROC [stream: STREAM, chars: ROPE] = { data: EditedStreamData = NARROW[stream.streamData]; Append1: PROC [c: CHAR] RETURNS [quit: BOOL] = { AppendBufferChar[data, c]; RETURN [quit: FALSE] }; [] _ chars.Map[action: Append1]; }; AppendBufferChar: PROC [data: EditedStreamData, char: CHAR] = INLINE { data.buffer _ RefText.InlineAppendChar[data.buffer, char]; IF data.echoStream # NIL THEN { IF data.echoAsterisks AND char > IO.SP THEN data.echoStream.PutChar['*] ELSE data.echoStream.PutChar[char]; }; }; EditedStreamUnAppendBufferChars: PUBLIC PROC [stream: STREAM, nChars: NAT] = { data: EditedStreamData = NARROW[stream.streamData]; FOR i: NAT IN [0 .. MIN[nChars, data.buffer.length]) DO UnAppendBufferChar[data] ENDLOOP; }; UnAppendBufferChar: PROC [data: EditedStreamData] = INLINE { IF data.echoStream # NIL THEN { char: CHAR = data.buffer[data.buffer.length - 1]; IF data.echoAsterisks AND char > IO.SP THEN data.echoStream.EraseChar['*] ELSE data.echoStream.EraseChar[char] }; data.buffer.length _ data.buffer.length - 1; }; EditedStreamSetMode: PROC [stream: STREAM, stuff: ROPE, pendingDelete: BOOL, echoAsterisks: BOOL] = { data: EditedStreamData = NARROW[stream.streamData]; data.buffer.length _ 0; data.readyPos _ data.ready.length; data.pendingDelete _ pendingDelete; data.echoAsterisks _ echoAsterisks; AppendBufferChars[stream, stuff]; }; EditedStreamGetDeliverWhen: PROC [self: STREAM] RETURNS [proc: DeliverWhenProc, context: REF ANY] = { data: EditedStreamData = NARROW[self.streamData]; RETURN [data.deliverWhen, data.context]; }; EditedStreamSetDeliverWhen: PROC [self: STREAM, proc: DeliverWhenProc, context: REF ANY] = { data: EditedStreamData = NARROW[self.streamData]; data.deliverWhen _ proc; data.context _ context; }; EditedStreamGetChar: PROC [self: STREAM] RETURNS [char: CHAR] = { data: EditedStreamData = 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, data.buffer, self, data.context]; IF data.pendingDelete THEN { data.pendingDelete _ FALSE; IF NOT activate AND appendChar AND NOT IsEditCommand[char] THEN UnAppendBufferChars[self, data.buffer.length]; }; IF appendChar THEN { SELECT char FROM Ascii.DEL => { ENABLE UNWIND => data.buffer.length _ 0; ERROR Rubout[self]; }; Ascii.ControlA, Ascii.BS => BackChar[]; Ascii.ControlW => BackWord[]; Ascii.ControlQ => BackLine[]; Ascii.ESC => IF data.buffer.length = 0 THEN { FOR i: NAT IN [0..data.ready.length-1) DO AppendBufferChar[data, data.ready[i]]; ENDLOOP }; ENDCASE => AppendBufferChar[data, char]; }; IF activate THEN GOTO activateBuffer; EXITS activateBuffer => { data.ready.length _ 0; data.ready _ RefText.Append[data.ready, data.buffer]; data.readyPos _ 0; data.buffer.length _ 0; data.echoAsterisks _ FALSE; } } ENDLOOP; }; EditedStreamEndOf: PROC [self: STREAM] RETURNS [BOOL] = { data: EditedStreamData = NARROW[self.streamData]; RETURN[data.readyPos = data.ready.length AND self.backingStream.EndOf[]]; }; EditedStreamCharsAvail: PROC [self: STREAM, wait: BOOL] RETURNS [INT] = { data: EditedStreamData = NARROW[self.streamData]; IF data.readyPos < data.ready.length THEN RETURN [data.ready.length-data.readyPos]; RETURN[self.backingStream.CharsAvail[wait]]; }; EditedStreamBackup: PROC [self: STREAM, char: CHAR] = { data: EditedStreamData = NARROW[self.streamData]; IF data.readyPos = 0 OR data.ready[data.readyPos - 1] # char THEN IO.Error[$IllegalBackup, self]; data.readyPos _ data.readyPos - 1; }; EditedStreamSetEcho: PROC [self: STREAM, echoTo: STREAM] = { data: EditedStreamData = NARROW[self.streamData]; data.echoStream _ echoTo; }; EditedStreamGetEcho: PROC [self: STREAM] RETURNS [STREAM] = { data: EditedStreamData = NARROW[self.streamData]; RETURN [data.echoStream]; }; EditedStreamReset: PROC [self: STREAM] = { data: EditedStreamData = NARROW[self.streamData]; data.buffer.length _ 0; data.ready.length _ 0; data.readyPos _ 0; self.backingStream.Reset[]; IF data.echoStream # NIL THEN data.echoStream.Reset[]; }; SetEchoData: TYPE = REF SetEchoRecord; SetEchoRecord: TYPE = RECORD [echoStream: STREAM, buffer: REF TEXT]; setEchoProcs: REF StreamProcs; SetEcho: PUBLIC PROC [self: STREAM, echoTo: STREAM] = { origSelf: STREAM _ self; DO proc: REF ANY _ InlineLookupProc[self, $SetEcho]; IF proc # NIL THEN { (NARROW[proc, REF TypeOfSetEcho])^ [self, echoTo]; RETURN; } ELSE IF self.backingStream # NIL THEN self _ self.backingStream ELSE EXIT; ENDLOOP; IF echoTo = NIL THEN RETURN; IOUtils.AmbushStream[ self: origSelf, streamProcs: setEchoProcs, streamData: NEW[SetEchoRecord _ [echoStream: NIL, buffer: RefText.New[8]]]]; DefaultSetEchoSetEcho[origSelf, echoTo]; }; GetEcho: PUBLIC PROC [self: STREAM] RETURNS [oldEcho: STREAM] = { origSelf: STREAM _ self; DO proc: REF ANY _ InlineLookupProc[self, $GetEcho]; IF proc # NIL THEN RETURN[(NARROW[proc, REF TypeOfGetEcho])^ [self] ] ELSE IF self.backingStream # NIL THEN self _ self.backingStream ELSE EXIT; ENDLOOP; RETURN [NIL]; }; DefaultSetEchoSetEcho: PROC [self: STREAM, echoTo: STREAM] = { data: SetEchoData = NARROW[self.streamData]; data.echoStream _ echoTo; IF echoTo = NIL AND data.buffer.length = 0 THEN IOUtils.UnAmbushStream[self]; }; DefaultSetEchoGetEcho: PROC [self: STREAM] RETURNS [oldEcho: STREAM] = { data: SetEchoData = NARROW[self.streamData]; RETURN[data.echoStream]; }; DefaultSetEchoBackup: PROC [self: STREAM, char: CHAR] = { data: SetEchoData = NARROW[self.streamData]; data.buffer _ RefText.InlineAppendChar[data.buffer, char ! RuntimeError.BoundsFault => ERROR IO.Error[$BufferOverflow, self]]; }; DefaultSetEchoGetChar: PROC [self: STREAM] RETURNS [char: CHAR] = { data: SetEchoData = NARROW[self.streamData]; IF data.buffer.length > 0 THEN { data.buffer.length _ data.buffer.length - 1; char _ data.buffer[data.buffer.length]; RETURN[char]; }; char _ self.backingStream.GetChar[]; IF data.echoStream # NIL THEN data.echoStream.PutChar[char]; }; DefaultSetEchoGetBlock: PROC [self: STREAM, block: REF TEXT, startIndex: NAT, count: NAT] RETURNS [nBytesRead: NAT] = { data: SetEchoData = NARROW[self.streamData]; nBytesRead _ 0; WHILE data.buffer.length > 0 DO IF count = 0 OR startIndex >= block.maxLength THEN RETURN [nBytesRead]; data.buffer.length _ data.buffer.length - 1; block[startIndex] _ data.buffer[data.buffer.length]; startIndex _ startIndex + 1; count _ count - 1; nBytesRead _ nBytesRead + 1; ENDLOOP; nBytesRead _ nBytesRead + self.backingStream.GetBlock[block, startIndex, count]; IF data.echoStream # NIL THEN data.echoStream.PutBlock[block, startIndex, block.length-startIndex]; RETURN [nBytesRead]; }; DefaultSetEchoUnsafeGetBlock: UNSAFE PROC [self: STREAM, block: IO.UnsafeBlock] RETURNS [nBytesRead: INT] = UNCHECKED { data: SetEchoData = NARROW[self.streamData]; nBytesRead _ 0; IF block.startIndex < 0 OR block.count < 0 THEN ERROR RuntimeError.BoundsFault; WHILE data.buffer.length > 0 DO IF block.count = 0 THEN RETURN [nBytesRead]; data.buffer.length _ data.buffer.length - 1; block.base^[block.startIndex] _ data.buffer[data.buffer.length]; block.startIndex _ block.startIndex + 1; block.count _ block.count - 1; nBytesRead _ nBytesRead + 1; ENDLOOP; block.count _ self.backingStream.UnsafeGetBlock[block]; IF data.echoStream # NIL THEN data.echoStream.UnsafePutBlock[block]; RETURN [nBytesRead + block.count]; }; DefaultSetEchoEndOf: PROC [self: STREAM] RETURNS [BOOL] = { data: SetEchoData = NARROW[self.streamData]; RETURN[data.buffer.length = 0 AND self.backingStream.EndOf[]]; }; DefaultSetEchoCharsAvail: PROC [self: STREAM, wait: BOOL] RETURNS [INT] = { data: SetEchoData = NARROW[self.streamData]; IF data.buffer.length > 0 THEN RETURN [data.buffer.length]; RETURN[self.backingStream.CharsAvail[wait]]; }; DefaultSetEchoReset: PROC [self: STREAM] = { data: SetEchoData = NARROW[self.streamData]; data.buffer.length _ 0; self.backingStream.Reset[]; }; AddStreamProcs: PUBLIC PROC [ to: REF IO.StreamProcs, setEcho: PROC [self: STREAM, echoTo: STREAM], getEcho: PROC [self: STREAM] RETURNS [oldEcho: STREAM] ] RETURNS [REF IO.StreamProcs] = { IF setEcho # NIL THEN IOUtils.StoreProc[to, $SetEcho, NEW[TypeOfSetEcho _ setEcho]]; IF getEcho # NIL THEN IOUtils.StoreProc[to, $GetEcho, NEW[TypeOfGetEcho _ getEcho]]; RETURN [to]; }; EditedStreamProcs _ AddStreamProcs[to: IO.CreateStreamProcs[ variety: $input, class: $Edited, getChar: EditedStreamGetChar, endOf: EditedStreamEndOf, charsAvail: EditedStreamCharsAvail, backup: EditedStreamBackup, reset: EditedStreamReset], setEcho: EditedStreamSetEcho, getEcho: EditedStreamGetEcho]; IOUtils.StoreProc[EditedStreamProcs, $GetDeliverWhen, NEW[TypeOfGetDeliverWhen _ EditedStreamGetDeliverWhen]]; IOUtils.StoreProc[EditedStreamProcs, $SetDeliverWhen, NEW[TypeOfSetDeliverWhen _ EditedStreamSetDeliverWhen]]; IOUtils.StoreProc[EditedStreamProcs, $AppendBufferChars, NEW[TypeOfAppendBufferChars _ EditedStreamAppendBufferChars]]; IOUtils.StoreProc[EditedStreamProcs, $UnAppendBufferChars, NEW[TypeOfUnAppendBufferChars _ EditedStreamUnAppendBufferChars]]; IOUtils.StoreProc[EditedStreamProcs, $SetMode, NEW[TypeOfSetMode _ EditedStreamSetMode]]; setEchoProcs _ AddStreamProcs[to: IO.CreateStreamProcs[ variety: $inputOutput, class: $SetEcho, getChar: DefaultSetEchoGetChar, getBlock: DefaultSetEchoGetBlock, unsafeGetBlock: DefaultSetEchoUnsafeGetBlock, endOf: DefaultSetEchoEndOf, charsAvail: DefaultSetEchoCharsAvail, backup: DefaultSetEchoBackup, reset: DefaultSetEchoReset], setEcho: DefaultSetEchoSetEcho, getEcho: DefaultSetEchoGetEcho]; END. @IOEditedStreamImpl.mesa -- 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? -- Break out separate proc to read up to activation, return buffer length Last edited by: MBrown on December 9, 1983 11:24 am Errors Edited Input Stream 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 looks wrong ... why can't you backup past ready chars? Default SetEcho implementation Default implementation: ambush the stream (it will be un-ambushed when self.SetEcho[NIL] is performed). To prevent backed-up chars from being echoed twice (see SetEchoGetChar below). Implementing a stream class Module Initialization Κζ– "Cedar" style˜headšΠblœ ™Ibody™ΰšœ™Jšœ Οc™#——˜šΟk ˜ Jšœ˜Jšœ˜Jšœ ˜ JšŸœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ Ÿœ˜!J˜——šœŸœŸœ˜#JšŸœŸœ&˜0JšŸœ ˜JšŸœŸœž#˜-JšŸ˜JšŸœŸœŸœŸœ˜JšŸœŸœŸœ˜Jšœ ŸœŸœ ˜#Jš Οn œŸœŸœŸœ Ÿœ˜:Jš   œŸœŸœŸœŸœ Ÿœ˜DIunitšœŸœ ˜5Mš œŸœŸœŸœŸœ"ŸœŸœ˜cJš œŸœŸœŸœ"Ÿ œ˜`Jš œŸœŸœ Ÿœ Ÿœ˜CJš œŸœŸœ Ÿœ Ÿœ˜Eš œŸœŸœ Ÿœ ŸœŸœ˜MIcodešœŸœ˜—š œŸœŸœ ŸœŸœŸœŸœ˜NNšœŸœ˜ šŸœ6ŸœŸœŸ˜INšŸœŸœŸœ˜5NšŸœ˜—N˜—š œŸœŸœŸœŸœ"ŸœŸœ˜`JšœŸœŸœ+˜5š ŸœŸœŸœŸœŸœ ˜RJšŸœ˜—JšŸœŸœŸœ+˜8J˜—š  œŸœŸœŸœ"ŸœŸœ˜WJšœŸœŸœ+˜5š ŸœŸœŸœŸœŸœ/˜OJšŸœ˜—JšŸœŸœŸœ+˜8J˜—š  œŸœŸœ Ÿœ Ÿœ˜@JšœŸœŸœ0˜:š ŸœŸœŸœŸœŸœ,˜LJšŸœ˜—JšŸœŸœŸœ-˜:J˜—š  œŸœŸœ Ÿœ Ÿœ˜BJšœŸœŸœ2˜<š ŸœŸœŸœŸœŸœ/˜OJšŸœ˜—JšŸœŸœŸœ-˜:J˜—š  œŸœŸœ Ÿœ ŸœŸœ˜GNšœŸœ˜JšœŸœŸœ&˜0š ŸœŸœŸœŸœŸœ@˜`JšŸœ˜—JšŸœŸœŸœ-˜:J˜——šœ™Jš  œŸœŸœ ŸœŸœ˜-—™MšœŸœŸœ˜0šœŸœŸœ˜"JšœŸœŸœ˜Jšœ ŸœžG˜ZJšœŸœŸœ˜Jšœ ŸœŸ˜J˜Jšœ ŸœŸœ˜JšœŸœŸœ˜JšœŸœŸ˜J˜—MšœŸœ ˜#š œŸœ˜!NšŸœ ŸœŸœ˜1Nšœ˜—š  œŸœŸœŸœ Ÿœ)Ÿœ˜`JšŸœŸœ˜šœŸœ˜J˜šœ Ÿœ˜(JšœŸœŸœ˜JšœŸœŸœ˜Jšœ-˜-—J˜J˜—Jšœ Ÿœ˜Jšœž˜JšŸœ˜ Jšœ˜—š œŸœ Ÿœ Ÿœ˜EJšœŸœ˜3š  œŸœŸœŸœŸœ˜0JšœŸœŸœ˜2—Jšœ ˜ J˜—š œŸœ ŸœŸœ˜FJ˜:šŸœŸœŸœ˜Jš ŸœŸœŸœŸœŸœ˜GJšŸœ˜#Jšœ˜—Jšœ˜—š  œŸœŸœ Ÿœ Ÿœ˜NJšœŸœ˜3š ŸœŸœŸœŸœŸ˜7Jšœ˜JšŸœ˜—J˜—š œŸœŸœ˜<šŸœŸœŸœ˜JšœŸœ'˜1Jš ŸœŸœŸœŸœŸœ˜IJšŸœ ˜$J˜—J˜,Jšœ˜—š  œŸœ Ÿœ ŸœŸœ˜LNšœŸœ˜JšœŸœ˜3J˜Jšœ"˜"Jšœ#˜#Jšœ#˜#Jšœ!˜!N˜—š  œŸœŸœŸœ"Ÿœ˜eJšœŸœ˜1JšŸœ"˜(N˜—š œŸœŸœ"Ÿœ˜\JšœŸœ˜1Jšœ1˜1N˜—š  œŸœŸœŸœŸœ˜AJšœŸœ˜1š   œŸœŸœŸœŸœ˜3šŸœŸœŸ˜JšœŸœŸœ$Ÿœ˜LJšŸœŸœ˜—Jšœ˜—š œŸœ˜Jšœ)™)šŸœŸœ˜ J˜Jšœ˜—Jšœ˜—š œŸœ˜JšœN™NNšœ ŸœŸœ˜šŸœŸ˜šŸœ%Ÿ˜/NšŸœ Ÿœ ŸœŸœ˜:NšŸœŸœ ŸœŸœ˜"—J˜NšŸœ˜—Nšœ˜—š œŸœ˜Jšœ/Ÿœ™9šŸœŸ˜JšŸœ'ŸœŸœŸœ˜9J˜JšŸœ˜—Jšœ˜—šŸ˜šŸœ#Ÿœ˜+Jšœ!˜!J˜"JšŸœ˜Jšœ˜—˜JšœŸœ˜šœ%Ÿœ˜6Jš ŸœŸœŸœŸœŸœ˜@—šœ.˜.Jšœ8˜8—šŸœŸœ˜JšœŸœ˜š ŸœŸœ Ÿœ ŸœŸœŸ˜?Jšœ.˜.—J˜—šŸœ Ÿœ˜šŸœŸ˜šœŸœŸœŸœ˜7JšŸœ˜J˜—JšœŸœ˜'J˜Jšœ˜šœŸœŸœŸœ˜-šŸœŸœŸœŸ˜)J˜&JšŸ˜—J˜—JšŸœ!˜(—J˜—JšŸœ ŸœŸœ˜%šŸœ˜Jšœ˜J˜5Jšœ˜J˜JšœŸœ˜J˜—J˜—JšŸœ˜—Jšœ˜—š  œŸœŸœŸœŸœ˜9JšœŸœ˜1JšŸœ#Ÿœ˜JJšœ˜—š  œŸœŸœŸœŸœŸœ˜IJšœŸœ˜1JšŸœ#ŸœŸœ#˜SJšŸœ&˜,Jšœ˜—š œŸœŸœŸœ˜7Jšœ6™6JšœŸœ˜1šŸœŸœ&Ÿ˜AJšœ˜—Jšœ"˜"Jšœ˜—š œŸœŸœ Ÿœ˜JšœŸœ˜,Jšœ˜JšŸœ ŸœŸœŸœ˜MJšœ˜—š  œŸœŸœŸœ Ÿœ˜HJšœŸœ˜,JšŸœ˜Jšœ˜—š œŸœŸœŸœ˜9JšœN™NJšœŸœ˜,šœ:˜:JšœŸœŸœ˜C—Jšœ˜—š  œŸœŸœŸœŸœ˜CJšœŸœ˜,šŸœŸœ˜ Jšœ,˜,Jšœ'˜'JšŸœ˜ Jšœ˜—J˜$JšŸœŸœŸœ˜Jšœ˜—š  œŸœŸœŸœŸœŸœ˜KJšœŸœ˜,JšŸœŸœŸœ˜;JšŸœ&˜,Jšœ˜—š œŸœŸœ˜-JšœŸœ˜,Jšœ˜J˜Jšœ˜——šœ™š œŸœŸœ˜JšœŸœŸœ ˜Jšœ ŸœŸœ Ÿœ˜-Jš œ ŸœŸœŸœ Ÿœ˜6Jšœ˜JšŸœŸœŸœ˜ šŸœ ŸœŸ˜Jšœ Ÿœ˜>—šŸœ ŸœŸ˜Jšœ Ÿœ˜>—JšŸœ˜ Jšœ˜——™šœŸœ)˜