DIRECTORY Atom, IO, IOUtils, Rope, RefText, RuntimeError USING [BoundsFault]; IOCommonImpl: CEDAR PROGRAM IMPORTS IO, IOUtils, Atom, RefText, RuntimeError EXPORTS IO, IOUtils SHARES IO --for representation of StreamProcs = BEGIN STREAM: TYPE = IO.STREAM; ROPE: TYPE = Rope.ROPE; UnsafeBlock: TYPE = IO.UnsafeBlock; CharArrayPtr: TYPE = LONG POINTER TO PACKED ARRAY [0..0) OF CHAR; StreamProcs: TYPE = IO.StreamProcs; TypeOfEraseChar: TYPE = PROC [self: STREAM, char: CHAR]; TypeOfGetLength: TYPE = PROC [self: STREAM] RETURNS [length: INT]; TypeOfSetLength: TYPE = PROC [self: STREAM, length: INT]; Error: PUBLIC ERROR [ec: IO.ErrorCode, stream: STREAM] = CODE; EndOfStream: PUBLIC ERROR [stream: STREAM] = CODE; CreateStreamProcs: PUBLIC PROC [ variety: IO.StreamVariety, class: ATOM, getChar: PROC [self: STREAM] RETURNS [CHAR], getBlock: PROC [self: STREAM, block: REF TEXT, startIndex: NAT, count: NAT] RETURNS [nBytesRead: NAT], unsafeGetBlock: UNSAFE PROC [self: STREAM, block: UnsafeBlock] RETURNS [nBytesRead: INT], endOf: PROC [self: STREAM] RETURNS [BOOL], charsAvail: PROC [self: STREAM, wait: BOOL] RETURNS [INT], backup: PROC [self: STREAM, char: CHAR], putChar: PROC [self: STREAM, char: CHAR], putBlock: PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT], unsafePutBlock: PROC [self: STREAM, block: UnsafeBlock], flush: PROC [self: STREAM], reset: PROC [self: STREAM], close: PROC [self: STREAM, abort: BOOL], getIndex: PROC [self: STREAM] RETURNS [INT], setIndex: PROC [self: STREAM, index: INT], getLength: PROC [self: STREAM] RETURNS [length: INT], setLength: PROC [self: STREAM, length: INT], eraseChar: PROC [self: STREAM, char: CHAR] ] RETURNS [REF StreamProcs] = { streamProcs: REF StreamProcs _ NEW[StreamProcs _ [ variety: variety, class: class, getChar: IF getChar # NIL THEN getChar ELSE IF unsafeGetBlock # NIL THEN GetCharViaUnsafeGetBlock ELSE DefaultGetChar, getBlock: IF getBlock # NIL THEN getBlock ELSE IF unsafeGetBlock # NIL THEN GetBlockViaUnsafeGetBlock ELSE GetBlockViaGetChar, unsafeGetBlock: IF unsafeGetBlock # NIL THEN unsafeGetBlock ELSE UnsafeGetBlockViaGetChar, endOf: IF endOf = NIL THEN DefaultEndOf ELSE endOf, charsAvail: IF charsAvail = NIL THEN DefaultCharsAvail ELSE charsAvail, backup: IF backup = NIL THEN DefaultBackup ELSE backup, putChar: IF putChar # NIL THEN putChar ELSE IF unsafePutBlock # NIL THEN PutCharViaUnsafePutBlock ELSE DefaultPutChar, putBlock: IF putBlock # NIL THEN putBlock ELSE IF unsafePutBlock # NIL THEN PutBlockViaUnsafePutBlock ELSE PutBlockViaPutChar, unsafePutBlock: IF unsafePutBlock # NIL THEN unsafePutBlock ELSE UnsafePutBlockViaPutChar, flush: IF flush = NIL THEN DefaultFlush ELSE flush, reset: IF reset = NIL THEN DefaultReset ELSE reset, close: IF close = NIL THEN DefaultClose ELSE close, getIndex: IF getIndex = NIL THEN DefaultGetIndex ELSE getIndex, setIndex: IF setIndex = NIL THEN DefaultSetIndex ELSE setIndex, propList: NIL]]; IF getLength # NIL THEN IOUtils.StoreProc[streamProcs, $GetLength, NEW[TypeOfGetLength _ getLength]]; IF setLength # NIL THEN IOUtils.StoreProc[streamProcs, $SetLength, NEW[TypeOfSetLength _ setLength]]; IF eraseChar # NIL THEN IOUtils.StoreProc[streamProcs, $EraseChar, NEW[TypeOfEraseChar _ eraseChar]]; RETURN[streamProcs]; }; CreateStream: PUBLIC PROC [ streamProcs: REF StreamProcs, streamData: REF ANY, backingStream: STREAM _ NIL] RETURNS [stream: STREAM] = { RETURN[NEW[IO.STREAMRecord _ [ streamProcs: streamProcs, streamData: streamData, backingStream: backingStream] ]]; }; DefaultGetChar: PROC [self: STREAM] RETURNS [CHAR] = { IF self.backingStream # NIL THEN RETURN[self.backingStream.GetChar[]] ELSE ERROR Error[NotImplementedForThisStream, self]; }; GetCharViaUnsafeGetBlock: PUBLIC PROC [self: STREAM] RETURNS [CHAR] = TRUSTED { buff: PACKED ARRAY [0..1] OF CHAR; IF self.UnsafeGetBlock[[base: @buff, startIndex: 0, count: 1]] = 0 THEN ERROR IO.EndOfStream[self]; RETURN[buff[0]] }; GetBlockViaGetChar: PUBLIC PROC [self: STREAM, block: REF TEXT, startIndex: NAT, count: NAT] RETURNS [nBytesRead: NAT] = { nBytes: NAT = MIN [block.maxLength, IOUtils.AddNAT[startIndex, count]] - startIndex; FOR i: NAT IN [0 .. nBytes) DO block[startIndex+i] _ self.GetChar[ ! EndOfStream => { nBytesRead _ i; EXIT }]; REPEAT FINISHED => nBytesRead _ nBytes; ENDLOOP; block.length _ startIndex + nBytesRead; RETURN[nBytesRead]; }; GetBlockViaUnsafeGetBlock: PUBLIC PROC [ self: IO.STREAM, block: REF TEXT, startIndex: NAT, count: NAT] RETURNS [nBytesRead: NAT] = TRUSTED { nBytesRead _ self.UnsafeGetBlock[[ base: LOOPHOLE[block,LONG POINTER]+TEXT[0].SIZE, startIndex: startIndex, count: MAX[MIN[INT[count], INT[block.maxLength]-startIndex], 0] ]]; block.length _ startIndex + nBytesRead; RETURN[nBytesRead]; }; UnsafeGetBlockViaGetChar: PUBLIC UNSAFE PROC [self: STREAM, block: UnsafeBlock] RETURNS [nBytesRead: INT] = UNCHECKED { nBytesRead _ 0; IF block.startIndex < 0 OR block.count < 0 THEN ERROR RuntimeError.BoundsFault; FOR i: INT IN [0 .. block.count) DO LOOPHOLE[block.base, CharArrayPtr][block.startIndex+i] _ self.GetChar[ ! IO.EndOfStream => { nBytesRead _ i; EXIT }] REPEAT FINISHED => nBytesRead _ block.count; ENDLOOP; RETURN[nBytesRead]; }; DefaultPutChar: PROC [self: STREAM, char: CHAR] = { IF self.backingStream # NIL THEN self.backingStream.PutChar[char] ELSE ERROR IO.Error[$NotImplementedForThisStream, self]; }; PutCharViaUnsafePutBlock: PUBLIC PROC [self: STREAM, char: CHAR] = TRUSTED { buff: PACKED ARRAY [0..1] OF CHAR; buff[0] _ char; self.UnsafePutBlock[[base: @buff, startIndex: 0, count: 1]]; }; PutBlockViaPutChar: PUBLIC PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT] = { stopIndexPlusOne: NAT _ IOUtils.AddNAT[startIndex, count]; IF stopIndexPlusOne > block.maxLength THEN stopIndexPlusOne _ block.length; FOR i: NAT IN [startIndex .. stopIndexPlusOne) DO self.PutChar[block[i]]; ENDLOOP; }; PutBlockViaUnsafePutBlock: PUBLIC PROC [ self: STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT] = TRUSTED { stopIndexPlusOne: NAT _ IOUtils.AddNAT[startIndex, count]; IF stopIndexPlusOne > block.maxLength THEN stopIndexPlusOne _ block.length; self.UnsafePutBlock[[ base: LOOPHOLE[block,LONG POINTER]+TEXT[0].SIZE, startIndex: startIndex, count: MAX[INT[stopIndexPlusOne] - INT[startIndex], 0] ] ] }; UnsafePutBlockViaPutChar: PUBLIC PROC [self: STREAM, block: UnsafeBlock] = { IF block.startIndex < 0 OR block.count < 0 THEN ERROR RuntimeError.BoundsFault; FOR i: INT IN [block.startIndex .. block.startIndex+block.count) DO TRUSTED { self.PutChar[LOOPHOLE[block.base, CharArrayPtr][i]] } ENDLOOP; }; DefaultEndOf: PROC [self: STREAM] RETURNS [BOOL] = { IF self.backingStream # NIL THEN RETURN[self.backingStream.EndOf[]] ELSE ERROR Error[NotImplementedForThisStream, self]; }; DefaultCharsAvail: PROC [self: STREAM, wait: BOOL] RETURNS [INT] = { IF self.backingStream # NIL THEN RETURN[self.backingStream.CharsAvail[wait]] ELSE RETURN[INT.LAST]; }; DefaultFlush: PROC [self: STREAM] = { IF self.backingStream # NIL THEN self.backingStream.Flush[]; }; DefaultReset: PROC [self: STREAM] = { IF self.backingStream # NIL THEN self.backingStream.Reset[]; }; debugClose: BOOL _ TRUE; -- crock until important clients get fixed DefaultClose: PROC [self: STREAM, abort: BOOL _ FALSE] = { IF abort THEN self.Reset[] ELSE self.Flush[]; IF self.backingStream # NIL THEN self.backingStream.Close[abort]; IF NOT debugClose THEN self.streamProcs _ closedStreamProcs; }; DefaultGetIndex: PROC [self: STREAM] RETURNS [index: INT] = { IF self.backingStream # NIL THEN RETURN[self.backingStream.GetIndex[]] ELSE ERROR Error[NotImplementedForThisStream, self]; }; DefaultSetIndex: PROC [self: STREAM, index: INT] = { IF self.backingStream # NIL THEN self.backingStream.SetIndex[index] ELSE ERROR IO.Error[$NotImplementedForThisStream, self]; }; closedStreamProcs: PUBLIC REF StreamProcs _ NEW[StreamProcs _ [ variety: $inputOutput, class: $Closed, getChar: ClosedGetChar, getBlock: ClosedGetBlock, unsafeGetBlock: ClosedUnsafeGetBlock, endOf: ClosedEndOf, charsAvail: ClosedCharsAvail, backup: ClosedBackup, putChar: ClosedPutChar, putBlock: ClosedPutBlock, unsafePutBlock: ClosedUnsafePutBlock, flush: ClosedFlush, reset: ClosedReset, close: ClosedClose, getIndex: ClosedGetIndex, setIndex: ClosedSetIndex, propList: NIL]]; ClosedGetChar: PROC [self: STREAM] RETURNS [CHAR] = { ERROR IO.Error[$StreamClosed, self] }; ClosedGetBlock: PROC [self: STREAM, block: REF TEXT, startIndex: NAT, count: NAT] RETURNS [nBytesRead: NAT] = { ERROR IO.Error[$StreamClosed, self] }; ClosedUnsafeGetBlock: UNSAFE PROC [self: STREAM, block: UnsafeBlock] RETURNS [nBytesRead: INT] = { ERROR IO.Error[$StreamClosed, self] }; ClosedEndOf: PROC [self: STREAM] RETURNS [BOOL] = { ERROR IO.Error[$StreamClosed, self] }; ClosedCharsAvail: PROC [self: STREAM, wait: BOOL] RETURNS [INT] = { ERROR IO.Error[$StreamClosed, self] }; ClosedBackup: PROC [self: STREAM, char: CHAR] = { ERROR IO.Error[$StreamClosed, self] }; ClosedPutChar: PROC [self: STREAM, char: CHAR] = { ERROR Error[$StreamClosed, self] }; ClosedPutBlock: PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT] = { ERROR Error[$StreamClosed, self] }; ClosedUnsafePutBlock: PROC [self: STREAM, block: UnsafeBlock] = { ERROR Error[$StreamClosed, self] }; ClosedFlush: PROC [self: STREAM] = { ERROR Error[$StreamClosed, self] }; ClosedReset: PROC [self: STREAM] = { }; ClosedClose: PROC [self: STREAM, abort: BOOL _ FALSE] = { }; ClosedGetIndex: PROC [self: STREAM] RETURNS [index: INT] = { ERROR Error[$StreamClosed, self] }; ClosedSetIndex: PROC [self: STREAM, index: INT] = { ERROR Error[$StreamClosed, self] }; GetInfo: PUBLIC PROC [stream: STREAM] RETURNS [variety: IO.StreamVariety, class: ATOM] = { RETURN [stream.streamProcs.variety, stream.streamProcs.class]; }; PeekChar: PUBLIC PROC [self: STREAM] RETURNS [char: CHAR] = { char _ self.GetChar[]; self.Backup[char] }; 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; }; GetLength: PUBLIC PROC [self: STREAM] RETURNS [length: INT] = { proc: REF ANY; DO IF self.streamProcs.class = $Closed THEN ERROR IO.Error[$StreamClosed, self]; proc _ InlineLookupProc[self, $GetLength]; IF proc # NIL THEN RETURN[(NARROW[proc, REF TypeOfGetLength])^ [self] ] ELSE IF self.backingStream # NIL THEN self _ self.backingStream ELSE ERROR Error[NotImplementedForThisStream, self]; ENDLOOP; }; SetLength: PUBLIC PROC [self: STREAM, length: INT] = { proc: REF ANY; DO IF self.streamProcs.class = $Closed THEN ERROR IO.Error[$StreamClosed, self]; proc _ InlineLookupProc[self, $SetLength]; IF proc # NIL THEN {(NARROW[proc, REF TypeOfSetLength ])^ [self, length]; RETURN} ELSE IF self.backingStream # NIL THEN self _ self.backingStream ELSE ERROR IO.Error[$NotImplementedForThisStream, self]; ENDLOOP; }; EraseChar: PUBLIC PROC [self: STREAM, char: CHAR] = { proc: REF ANY; DO IF self.streamProcs.class = $Closed THEN ERROR IO.Error[$StreamClosed, self]; proc _ InlineLookupProc[self, $EraseChar]; IF proc # NIL THEN {(NARROW[proc, REF TypeOfEraseChar])^ [self, char]; RETURN} ELSE IF self.backingStream # NIL THEN self _ self.backingStream ELSE {self.PutChar['\\]; self.PutChar[char]; RETURN}; ENDLOOP; }; AmbushStream: PUBLIC PROC [self: STREAM, streamProcs: REF StreamProcs, streamData: REF ANY, reusing: STREAM _ NIL] = { IF reusing = NIL OR reusing = self -- to prevent circularities due to bugs -- THEN reusing _ NEW[IO.STREAMRecord _ [streamProcs: NIL, streamData: NIL]]; reusing^ _ self^; self^ _ [streamProcs: streamProcs, streamData: streamData, propList: reusing.propList, backingStream: reusing]; reusing.propList _ NIL; -- keep only one copy of prop list. }; UnAmbushStream: PUBLIC PROC [self: STREAM] = { propList: Atom.PropList = self.propList; IF self.backingStream = NIL THEN RETURN; self^ _ self.backingStream^; IF self.propList # NIL THEN ERROR; -- access to the backing stream prop list was an error self.propList _ propList; }; BackupData: TYPE = REF BackupRecord; BackupRecord: TYPE = RECORD[stream: STREAM, buffer: REF TEXT]; backupProcs: REF StreamProcs = IO.CreateStreamProcs[ variety: $inputOutput, class: $BackedUp, getChar: BackupGetChar, endOf: BackupEndOf, charsAvail: BackupCharsAvail, reset: BackupReset, backup: BackupBackup ]; DefaultBackup: PROC [self: STREAM, char: CHAR] = { data: BackupData _ NARROW[IOUtils.LookupData[self, $Backup]]; IF data = NIL THEN { data _ NEW[BackupRecord _ [ stream: IO.CreateStream[NIL, NIL], buffer: RefText.New[8]]]; IOUtils.StoreData[self: self, key: $Backup, data: data] }; IF data.stream = self THEN ERROR Error[IllegalBackup, self]; -- while self in backed-up state, client performed self.backingStream.Backup[] (!) AmbushStream[self: self, streamProcs: backupProcs, streamData: data, reusing: data.stream]; self.Backup[char]; }; BackupBackup: PROC [self: STREAM, char: CHAR] = { data: BackupData = NARROW[IOUtils.LookupData[self, $Backup]]; data.buffer _ RefText.InlineAppendChar[data.buffer, char ! RuntimeError.BoundsFault => ERROR IO.Error[BufferOverflow, self]]; }; BackupGetChar: PROC [self: STREAM] RETURNS [char: CHAR] = { data: BackupData = NARROW[self.streamData]; char _ data.buffer[data.buffer.length - 1]; data.buffer.length _ data.buffer.length - 1; IF data.buffer.length = 0 THEN UnAmbushStream[self]; RETURN[char]; }; BackupEndOf: PROC [self: STREAM] RETURNS [BOOL] = { RETURN[FALSE]; }; BackupCharsAvail: PROC [self: STREAM, wait: BOOL] RETURNS [INT] = { data: BackupData = NARROW[self.streamData]; IF data.buffer.length > 0 THEN RETURN [data.buffer.length]; RETURN[self.backingStream.CharsAvail[wait]]; }; BackupReset: PROC [self: STREAM] = { data: BackupData = NARROW[self.streamData]; data.buffer.length _ 0; UnAmbushStream[self]; self.Reset[]; }; END. IOCommonImpl.mesa Last edited by: MBrown on November 15, 1983 5:25 pm Paul Rovner on May 26, 1983 2:00 pm Teitelman on April 20, 1983 2:52 pm TO DO remove "debugClose" flag when no longer needed Errors Creating streams Default Procedures: Get/Put Char/Block Default Procedures: others Closed Stream Procedures Generic procedures with the standard implementation "Standard implementation" means "try property list, then try backing stream, then do something simple (e.g. Error[NotImplementedForThisStream])" Ambush / UnAmbush Stream Default Backup implementation This is the implementation of Backup supplied by CreateStreamProcs when the client does not supply its own. This implementation ambushes the stream self. The stream created by the ambushing is saved so that it can be reused if the stream enters the backed-up state often. -- first time for this particular stream this is the implementation of Backup when a stream is in the backed-up state from a call to BackupFirstChar. Change Log Changed by MBrown on October 25, 1983 1:18 pm Added "IF NOT debugClose THEN self.streamProcs _ closedStreamProcs;" to DefaultClose (default is debugClose = TRUE because compiler and binder break otherwise ...) Changed by MBrown on November 15, 1983 5:25 pm Fixed off-by-one error in BackupGetChar. Κς– "Cedar" style˜headšœ™bodyšœ™Jšœ Οc™#Jšœ™#Jš œ™#——˜™J™.—J˜šΟk ˜ Jšœ˜Jšžœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ žœ˜!J˜——šΠbl œžœžœ˜Jšžœžœ'˜1Jšžœžœ˜Jšžœžœ#˜-Jšž˜Jšžœžœžœžœ˜Jšžœžœžœ˜Jšœ žœžœ ˜#Jšœžœžœžœžœžœžœžœžœ˜AJšœ žœžœ ˜#Iunitš Οnœžœžœžœžœ˜8Jš  œžœžœžœžœ žœ˜BJš  œžœžœžœ žœ˜9—šœ™Jš  œžœžœžœžœ˜>Jš   œžœžœ žœžœ˜2—šœ™š œžœžœ˜ Jšœ˜Jšœžœ˜ Mš œ žœžœžœžœ˜,Jšœ žœžœ žœžœžœ žœžœ žœ˜fJš œžœžœžœžœ žœ˜YJš œžœžœžœžœ˜*Jš œ žœžœžœžœžœ˜:Jšœžœžœžœ˜(Mšœ žœžœžœ˜)Jšœ žœžœ žœžœžœžœ žœ˜UJšœžœžœ˜8Jšœžœžœ˜Mšœžœžœ˜Jšœžœžœ žœ˜(Mš œ žœžœžœžœ˜,Jšœ žœžœ žœ˜*Jš œ žœžœžœ žœ˜5Jšœ žœžœ žœ˜,Jšœ žœžœžœ˜*J˜Jšžœžœ˜šœ žœžœ˜2Jšœ˜J˜ šœ žœ žœžœ˜&Jšžœžœžœžœ˜:Jšžœ˜—šœ žœ žœžœ ˜)Jšžœžœžœžœ˜;Jšžœ˜—šœžœžœžœ˜;Jšžœ˜—Jš œžœ žœžœžœ˜4Jš œ žœžœžœžœ˜KJš œžœ žœžœžœ˜7šœ žœ žœžœ˜&Jšžœžœžœžœ˜:Jšžœ˜—šœ žœ žœžœ ˜)Jšžœžœžœžœ˜;Jšžœ˜—šœžœžœžœ˜;Jšžœ˜—Jš œžœ žœžœžœ˜4Mš œžœ žœžœžœ˜4Jš œžœ žœžœžœ˜4Jš œ žœ žœžœžœ ˜?Jš œ žœ žœžœžœ ˜?Jšœ žœ˜—šžœ žœž˜Jšœ+žœ˜M—šžœ žœž˜Jšœ+žœ˜M—šžœ žœž˜Jšœ+žœ˜M—Jšžœ˜šœ˜J˜——š  œžœžœ˜Jš œ žœžœžœžœžœ˜OJšžœ žœ˜šžœžœžœ˜JšœS˜S—Jšœ˜——šœ&™&š  œžœžœžœžœ˜6Jšžœžœžœžœ˜EJšžœžœ*˜4J˜J˜—š œžœžœžœ˜4Jšžœžœžœ˜Jš œžœžœžœžœ˜"šžœAž˜GJšžœžœ˜—Jšžœ ˜J˜J˜—š œž œžœ žœžœžœ žœ˜\Jšžœ žœ˜Jš Οrž‘Πkr‘œ‘œ‘œ ‘˜Tš’‘’‘’‘’˜Jš‘G’‘˜Oš’˜Jš’‘˜ —Jš’‘˜—Jš‘'˜'Jš’‘ ˜J˜J˜—š œžœžœ˜(Jš œžœžœ žœžœžœ žœ˜>Jšžœ žœž‘œ˜%šœ"˜"Jš œžœžœžœžœžœ˜0Jšœ˜Jš œžœžœžœ žœ%˜C—Jš‘œ ˜'Jšžœ ˜Jšœ˜—J˜š œž œžœžœžœ žœž ’œ˜wJš‘˜š’‘’‘’˜/Jš’‘˜—š’‘’‘’‘’˜#š’‘0˜8Jš‘’‘"’‘˜;—š’˜Jšžœ‘ œ‘ œ˜%—Jš’‘˜—Jš’‘ œ˜Jšœ˜J˜—š œžœžœžœ˜3Jšžœžœžœ!˜AJšžœžœžœ+˜8J˜J˜—š  œžœžœžœžœžœ˜LJš œžœžœžœžœ˜"Jšœ˜Jšœ<˜N˜—š  œžœžœžœžœžœ˜=Nšœ(˜(Nšœ˜—š œžœžœ žœžœžœžœ˜NNšœžœ˜ šžœ6žœžœž˜INšžœžœžœ˜5Nšžœ˜—N˜—š   œžœžœžœžœ žœ˜?Nšœžœžœ˜šž˜Nšžœ"žœžœžœ˜MNšœ*˜*Nš žœžœžœžœžœžœ˜GNšžœžœžœžœ˜?Nšžœžœ*˜4Nšžœ˜—Nšœ˜—š   œžœžœžœ žœ˜6Nšœžœžœ˜šž˜Nšžœ"žœžœžœ˜MNšœ*˜*Nš žœžœžœžœžœ%žœ˜RNšžœžœžœžœ˜?Nšžœž œ*˜8Nšžœ˜—Nšœ˜—š   œžœžœžœžœ˜5Nšœžœžœ˜šž˜Nšžœ"žœžœžœ˜MJšœ*˜*Jš žœžœžœžœžœ"žœ˜NJšžœžœžœžœ˜?Jšžœ)žœ˜5Jšž˜—Jšžœ˜——šœ™š   œžœžœžœžœ ˜FJš œ žœžœ žœžœ˜/š žœ žœžœ*œž˜RJš œ žœžœžœžœ˜E—J˜J˜oJšœžœ#˜;Jšœ˜—š œžœžœžœ˜.J˜)Jšžœžœžœžœ˜(J˜Jš žœžœžœžœ6˜YJšœ˜Jšœ˜——™Mšœ žœžœ˜$Jš œžœžœ žœ žœžœ˜>šœ žœžœ˜4J˜(J˜J˜J˜J˜J˜J˜—š  œžœžœžœ˜2Jšœ•‘œx™‘Jšœžœ$˜=šžœžœžœ˜Jš'œ™(šœžœ˜Jšœžœžœ˜<—Jšœ:˜:—šžœžœžœ˜