DIRECTORY IO, IOUtils, NodeProps, Rope, TextNode, TiogaFileOps, TiogaStreams, TiogaStreamsExtras; TiogaStreamsImpl: CEDAR PROGRAM IMPORTS IO, IOUtils, NodeProps, Rope, TextNode, TiogaFileOps EXPORTS TiogaStreams, TiogaStreamsExtras = BEGIN OPEN TN: TextNode, TFO: TiogaFileOps; ROPE: TYPE = Rope.ROPE; CommentHandling: TYPE = TiogaStreams.CommentHandling; FullCommentHandling: TYPE = TiogaStreamsExtras.FullCommentHandling; DepthOp: TYPE = TiogaStreams.DepthOp; NotNow: PUBLIC ERROR [s: IO.STREAM] = CODE; BadDepth: PUBLIC ERROR [s: IO.STREAM, depth: INT] = CODE; CallerBug: PUBLIC ERROR [s: IO.STREAM, message: ROPE] = CODE; IsATS: PUBLIC PROC [s: IO.STREAM] RETURNS [is: BOOLEAN] = {is _ s # NIL AND s.streamData # NIL AND ( ISTYPE[s.streamData, TiogaInStreamData] OR ISTYPE[s.streamData, TiogaOutStreamData]); }; TiogaInStreamData: TYPE = REF TiogaInStreamDataRep; TiogaInStreamDataRep: TYPE = RECORD [ ch: FullCommentHandling, end: BOOLEAN _ FALSE, next, nodeLen, nodeRLen, nodeUrLen, nodePrefixLength: INT _ 0, depth, indexAtNodeStart, index: INT _ 0, nodeRope: ROPE _ NIL, levelPrefix: ROPE, node, root: TN.Ref]; CreateInput: PUBLIC PROC [from: TN.Ref, commentHandling: CommentHandling _ discard, levelPrefix: ROPE _ NIL] RETURNS [in: IO.STREAM] ~ { RETURN FullCreateInput[ from, SELECT commentHandling FROM discard => [FALSE[]], useDirectly => [TRUE[NIL, NIL]], prefixWithDashDash => [TRUE["--", NIL]], ENDCASE => ERROR, levelPrefix]}; FullCreateInput: PUBLIC PROC [from: TN.Ref, commentHandling: FullCommentHandling _ [FALSE[]], levelPrefix: ROPE _ NIL] RETURNS [in: IO.STREAM] = BEGIN sd: TiogaInStreamData _ NEW [TiogaInStreamDataRep _ [ ch: commentHandling, levelPrefix: levelPrefix, node: NIL, root: from ]]; GoToBeginning[sd]; in _ IO.CreateStream[streamProcs: tiogaInStreamProcs, streamData: sd]; END; GoToBeginning: PROC [sd: TiogaInStreamData] = { dd: INT; IF sd.root = NIL THEN {sd.end _ TRUE; RETURN}; [sd.node, dd] _ TN.Forward[sd.root]; IF sd.node = NIL THEN {sd.end _ TRUE; RETURN}; SELECT dd FROM <1 => {sd.end _ TRUE; RETURN}; =1 => { sd.end _ FALSE; sd.depth _ 1; sd.indexAtNodeStart _ 0; NodeHello[sd]; }; ENDCASE => ERROR; }; TryForNextChar: PROC [sd: TiogaInStreamData] = BEGIN IF sd.end THEN RETURN; WHILE sd.next >= sd.nodeLen DO dd: INT; next: TN.Ref; [next, dd] _ TN.Forward[sd.node]; IF sd.depth+dd <= 0 OR next = NIL THEN {sd.end _ TRUE; RETURN}; sd.next _ sd.next - sd.nodeLen; sd.depth _ sd.depth + dd; sd.indexAtNodeStart _ sd.indexAtNodeStart + sd.nodeLen; sd.node _ next; NodeHello[sd]; ENDLOOP; END; NodeHello: PROC [sd: TiogaInStreamData] = BEGIN tn: TN.RefTextNode _ sd.node; Use: PROC [prefix, suffix: ROPE] = { IF sd.levelPrefix.Length[] # 0 THEN THROUGH [1 .. sd.depth) DO prefix _ sd.levelPrefix.Concat[prefix]; ENDLOOP; sd.nodePrefixLength _ prefix.Length[]; sd.nodeRope _ prefix.Concat[TN.NodeRope[tn]].Concat[suffix]; sd.nodeRLen _ sd.nodeRope.Length[]; sd.nodeUrLen _ TN.NodeRope[tn].Length[]; sd.nodeLen _ sd.nodeRLen + 1}; IF tn.comment THEN TRUSTED {WITH x: sd.ch SELECT FROM FALSE => { sd.nodeRope _ NIL; sd.nodeRLen _ sd.nodeUrLen _ sd.nodeLen _ sd.nodePrefixLength _ 0}; TRUE => Use[x.prefix, x.suffix]; ENDCASE => ERROR} ELSE Use[NIL, NIL]; END; tiogaInStreamProcs: REF IO.StreamProcs _ IO.CreateStreamProcs[variety: input, class: $TiogaInStream, getChar: GetChar, endOf: EndOf, backup: BackupIn, getIndex: GetInIndex, setIndex: SetInIndex]; GetChar: PROC [self: IO.STREAM] RETURNS [char: CHAR] = { sd: TiogaInStreamData _ NARROW[self.streamData]; TryForNextChar[sd]; IF sd.end THEN ERROR IO.EndOfStream[self]; char _ IF sd.next 0, TRUE => rawSize + 1 + prefix.Length[] + suffix.Length[], ENDCASE => ERROR}; [next, dd] _ TN.Forward[of]; IF dd > 1 THEN ERROR; IF dd < 1 THEN RETURN; dd _ dd - 1; WHILE dd = 0 DO ddi: INT; [next, dd, ddi] _ Work[next]; di _ di + ddi; ENDLOOP; dd _ dd + 1; }; new: TN.Ref; dd, di, newStart: INT; TryForNextChar[sd]; [new, dd, di] _ Work[sd.node]; newStart _ sd.indexAtNodeStart + di; IF newStart < sd.index THEN ERROR; sd.index _ newStart; IF sd.depth+dd <= 0 OR new = NIL THEN {sd.end _ TRUE; RETURN}; sd.node _ new; sd.indexAtNodeStart _ newStart; sd.depth _ sd.depth + dd; sd.next _ 0; NodeHello[sd]; }; TiogaOutStreamData: TYPE = REF TiogaOutStreamDataRep; TiogaOutStreamDataRep: TYPE = RECORD [ breakAtNewline, parsePrefix, flexilevel, tabsWhite, adjApp, adjFmt: BOOL, levelPrefix: ROPE, spacesPerTab, nni, mini, maxi: INT, root: TFO.Ref _ NIL, nodes: LIST OF TFO.Ref _ NIL, indents: LIST OF INT _ NIL, --indents.first goes with nodes.first ready: BOOLEAN _ FALSE, lpCharsSeen, lpLength: INT _ 0, nodeDepth: INT _ 0, --actual Tioga depth of nodes.first userDepth: INT _ 0, --where user thinks she is cpl, csl, cbl: INT _ 0, --len of comment prefix, suffix, both nextDepth, deltaDepth, indent: INT _ 0, ch: FullCommentHandling, fmts: RopeSeq _ NIL, contents: ROPE _ NIL, defaultFormat: ROPE _ NIL, comment: BOOL _ FALSE, looks: ARRAY Look OF LooksRuns _ ALL[NIL]]; RopeSeq: TYPE ~ REF RopeSequence; RopeSequence: TYPE ~ RECORD [elts: SEQUENCE length: NAT OF ROPE]; LooksRuns: TYPE = LIST OF LooksRun; LooksRun: TYPE = RECORD [first, afterLast: INT]; Look: TYPE = CHAR['a .. 'z]; notClosed: INT = -1; CreateOutput: PUBLIC PROC [to: TFO.Ref, breakAtNewline: BOOL _ FALSE, levelPrefix, defaultFormat: ROPE _ NIL, flexilevel: BOOL _ FALSE, spacesPerTab, normalNestIndent: INT _ 0] RETURNS [out: IO.STREAM] ~ {RETURN FullCreateOutput[to, breakAtNewline, levelPrefix, defaultFormat, flexilevel, spacesPerTab, normalNestIndent]}; FullCreateOutput: PUBLIC PROC [to: TFO.Ref, breakAtNewline: BOOL _ FALSE, levelPrefix, defaultFormat: ROPE _ NIL, flexilevel: BOOL _ FALSE, spacesPerTab, normalNestIndent, minFmtIndent: INT _ 0, maxFmtIndent: INT _ -1, commentHandling: FullCommentHandling _ [FALSE[]] ] RETURNS [out: IO.STREAM] = BEGIN adjFmt: BOOL ~ maxFmtIndent>=minFmtIndent; sd: TiogaOutStreamData _ NEW [TiogaOutStreamDataRep _ [ breakAtNewline: breakAtNewline, parsePrefix: levelPrefix#NIL OR flexilevel, flexilevel: flexilevel, tabsWhite: spacesPerTab>0, adjApp: normalNestIndent>0 AND NOT adjFmt, adjFmt: adjFmt, levelPrefix: levelPrefix, spacesPerTab: spacesPerTab, nni: normalNestIndent, mini: minFmtIndent, maxi: maxFmtIndent, root: to, nodes: LIST[to], indents: LIST[-(IF normalNestIndent>0 THEN normalNestIndent ELSE 1)], lpLength: levelPrefix.Length[], nextDepth: 1, userDepth: 1, ch: commentHandling, defaultFormat: defaultFormat ]]; pfp: IOUtils.PFProcs; IF adjFmt THEN { sd.fmts _ NEW [RopeSequence[1+maxFmtIndent-minFmtIndent]]; FOR i: NAT IN [0..sd.fmts.length) DO sd.fmts[i] _ NIL ENDLOOP}; TRUSTED {WITH x: sd.ch SELECT FROM FALSE => NULL; TRUE => sd.cbl _ (sd.cpl _ x.prefix.Length) + (sd.csl _ x.suffix.Length); ENDCASE => ERROR}; out _ IO.CreateStream[streamProcs: tiogaOutStreamProcs, streamData: sd]; pfp _ IOUtils.CopyPFProcs[out]; [] _ IOUtils.SetPFCodeProc[pfProcs: pfp, char: 'l, codeProc: FormatL]; [] _ IOUtils.SetPFCodeProc[pfProcs: pfp, char: 'n, codeProc: FormatN]; [] _ IOUtils.SetPFProcs[stream: out, pfProcs: pfp]; PrepareForChar[out, sd]; END; tiogaOutStreamProcs: REF IO.StreamProcs _ IO.CreateStreamProcs[variety: output, class: $TiogaOutStream, putChar: PutChar, putBlock: PutBlock, close: CloseOut]; PutChar: PROC [self: IO.STREAM, char: CHAR] = BEGIN sd: TiogaOutStreamData _ NARROW[self.streamData]; SELECT TRUE FROM sd.breakAtNewline AND IsLB[char] => {EndNode[self, reset, FALSE]; RETURN}; sd.ready OR NOT sd.parsePrefix => NULL; sd.flexilevel => IF char=' OR sd.tabsWhite AND char='\t THEN { sd.indent _ sd.indent + (IF char#' THEN sd.spacesPerTab ELSE 1); RETURN}; char = sd.levelPrefix.Fetch[sd.lpCharsSeen] => { sd.lpCharsSeen _ sd.lpCharsSeen + 1; IF sd.lpCharsSeen = sd.lpLength THEN {sd.lpCharsSeen _ 0; sd.nextDepth _ sd.nextDepth + 1}; RETURN}; ENDCASE => NULL; PrepareForChar[self, sd]; sd.contents _ sd.contents.Concat[Rope.FromChar[char]]; END; PutBlock: PROC [self: IO.STREAM, block: REF READONLY TEXT, startIndex, count: NAT] = BEGIN sd: TiogaOutStreamData _ NARROW[self.streamData]; next: NAT _ startIndex; afterLast: NAT _ startIndex + count; WHILE next < afterLast DO nextCR, subsize: NAT; WHILE (NOT sd.ready) OR IsLB[block[next]] DO PutChar[self, block[next]]; next _ next + 1; IF next >= afterLast THEN RETURN; ENDLOOP; FOR nextCR _ next, nextCR + 1 WHILE nextCR < afterLast AND ~IsLB[block[nextCR]] DO NULL ENDLOOP; IF (subsize _ nextCR - next) # 0 THEN { sd.contents _ sd.contents.Concat[RopeFromSubText[block, next, subsize]]; next _ nextCR; }; ENDLOOP; END; CloseOut: PROC [self: IO.STREAM, abort: BOOL _ FALSE] = BEGIN EndNode[self]; IOUtils.AmbushStream[self: self, streamProcs: IOUtils.closedStreamProcs, streamData: NIL]; END; CurOutNode: PUBLIC PROC [s: IO.STREAM] RETURNS [n: TFO.Ref] = BEGIN sd: TiogaOutStreamData _ NARROW[s.streamData]; n _ sd.nodes.first; END; SetFormat: PUBLIC PROC [of: IO.STREAM, format: ROPE] = BEGIN n: TFO.Ref _ CurOutNode[of]; TFO.SetFormat[n, format]; END; FormatL: PROC [stream: IO.STREAM, val: IO.Value, format: IOUtils.Format, char: CHAR] = { sd: TiogaOutStreamData _ NARROW[stream.streamData]; PrepareForChar[stream, sd]; WITH val SELECT FROM rv: IO.Value[rope] => LooksWork[stream, sd, rv.value]; ENDCASE => ERROR IO.Error[PFUnprintableValue, stream]; }; FormatN: PROC [stream: IO.STREAM, val: IO.Value, format: IOUtils.Format, char: CHAR] = { sd: TiogaOutStreamData _ NARROW[stream.streamData]; PrepareForChar[stream, sd]; WITH val SELECT FROM x: IO.Value[boolean] => sd.comment _ x.value; ENDCASE => ERROR IO.Error[PFUnprintableValue, stream]; }; LooksWork: PROC [stream: IO.STREAM, sd: TiogaOutStreamData, chars: ROPE] = { index: INT _ sd.contents.Length[]; FOR i: INT IN [0 .. chars.Length[]) DO c: CHAR _ chars.Fetch[i]; SELECT c FROM ' => LooksWork[stream, sd, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"]; IN ['a .. 'z] => { IF sd.looks[c] = NIL OR sd.looks[c].first.afterLast # notClosed THEN sd.looks[c] _ CONS[[first: index, afterLast: notClosed], sd.looks[c]] }; IN ['A .. 'Z] => {l: Look _ c + ('a - 'A); IF sd.looks[l] # NIL AND sd.looks[l].first.afterLast = notClosed THEN sd.looks[l].first.afterLast _ index; }; ENDCASE => ERROR IO.Error[PFUnprintableValue, stream]; ENDLOOP; }; EndNode: PUBLIC PROC [s: IO.STREAM, depthOp: DepthOp _ reset, idempotently: BOOLEAN _ FALSE] = BEGIN sd: TiogaOutStreamData ~ NARROW[s.streamData]; cl: INT ~ sd.contents.Length[]; pref, suf: INT _ 0; cmt: BOOL _ sd.comment; IF NOT sd.ready THEN BEGIN IF idempotently THEN RETURN; PrepareForChar[s, sd]; END; TRUSTED {WITH x: sd.ch SELECT FROM FALSE => NULL; TRUE => IF cl>=sd.cbl AND x.prefix.EqualSubstrs[s2: sd.contents, len2: sd.cpl] AND x.suffix.EqualSubstrs[s2: sd.contents, start2: cl-sd.csl] THEN {cmt _ TRUE; pref _ sd.cpl; suf _ sd.csl}; ENDCASE => ERROR}; TFO.SetContents[sd.nodes.first, sd.contents.Substr[start: pref, len: cl-pref-suf]]; IF cmt THEN SetTFOComment[sd.nodes.first]; SetLooks[sd, pref, suf]; sd.ready _ FALSE; sd.lpCharsSeen _ sd.deltaDepth _ sd.indent _ 0; sd.contents _ NIL; sd.nextDepth _ SELECT depthOp FROM same => sd.userDepth, reset => 1, ENDCASE => ERROR; END; SetLooks: PROC [sd: TiogaOutStreamData, pre, suf: INT] = { len: INT _ sd.contents.Length[]; FOR l: Look IN Look DO FOR lr: LooksRuns _ sd.looks[l], lr.rest WHILE lr # NIL DO start: INT ~ MAX[lr.first.first, pre]; afterLast: INT _ IF lr.first.afterLast = notClosed THEN len ELSE lr.first.afterLast; afterLast _ MIN[len-suf, afterLast]; IF afterLast>start THEN TFO.AddLooks[x: sd.nodes.first, start: start-pre, len: afterLast - start, look: l, root: sd.root]; ENDLOOP; ENDLOOP; sd.looks _ ALL[NIL]; }; ChangeDepth: PUBLIC PROC [s: IO.STREAM, deltaDepth: INTEGER _ 0, autoEndNode: BOOLEAN _ TRUE, idempotently: BOOLEAN _ FALSE] = BEGIN sd: TiogaOutStreamData _ NARROW[s.streamData]; IF autoEndNode THEN EndNode[s, same, idempotently]; IF sd.ready THEN ERROR NotNow[s]; IF sd.flexilevel THEN ERROR CallerBug[s, "can't ChangeDepth[a flexilevel stream]"]; sd.deltaDepth _ sd.deltaDepth + deltaDepth; END; AdjCacheIndex: TYPE ~ INTEGER [-5 .. 100]; AdjCache: TYPE ~ ARRAY AdjCacheIndex OF REF ANY; adjCache: REF AdjCache _ NEW [AdjCache _ ALL[NIL]]; PrepareForChar: PROC [s: IO.STREAM, sd: TiogaOutStreamData] = { adjProp: REF ANY _ NIL; fmt: ROPE _ sd.defaultFormat; GetFmt: PROC [n: INT] RETURNS [ROPE] ~ { i: NAT ~ n - sd.mini; IF sd.fmts[i] = NIL THEN sd.fmts[i] _ IO.PutFR["%g%g", [rope[sd.defaultFormat]], [integer[n]] ]; RETURN [sd.fmts[i]]}; GetAdj: PROC [delta: INT] RETURNS [REF ANY] ~ { IF delta IN AdjCacheIndex THEN { IF adjCache[delta]=NIL THEN adjCache[delta] _ NodeProps.DoSpecs[$Postfix, IO.PutFR["%g sp bigger leftIndent", [integer[delta]]]]; RETURN [adjCache[delta]]} ELSE RETURN [NodeProps.DoSpecs[$Postfix, IO.PutFR["%g sp bigger leftIndent", [integer[delta]]]]]}; IF sd.ready THEN RETURN; IF sd.flexilevel THEN { delta: INT; sd.nextDepth _ sd.nodeDepth; WHILE sd.indents.first > sd.indent DO sd.indents _ sd.indents.rest; sd.nextDepth _ sd.nextDepth - 1; ENDLOOP; IF sd.indents.first < sd.indent THEN { sd.indents _ CONS[sd.indent, sd.indents]; sd.nextDepth _ sd.nextDepth + 1}; IF sd.adjFmt THEN {delta _ sd.indent - sd.indents.rest.first; IF deltasd.maxi THEN {fmt _ GetFmt[sd.maxi]; adjProp _ GetAdj[delta-sd.maxi]} ELSE fmt _ GetFmt[delta]} ELSE IF sd.adjApp AND (delta _ sd.indent - (sd.indents.rest.first+sd.nni)) # 0 THEN adjProp _ GetAdj[delta]; } ELSE { sd.nextDepth _ sd.nextDepth + sd.deltaDepth; }; IF sd.nextDepth < 0 THEN ERROR BadDepth[s, sd.nextDepth]; WHILE sd.nextDepth < sd.nodeDepth DO sd.nodes _ sd.nodes.rest; sd.nodeDepth _ sd.nodeDepth - 1; ENDLOOP; IF sd.nextDepth > sd.nodeDepth THEN { sd.nodes _ CONS[TFO.InsertAsLastChild[x: sd.nodes.first], sd.nodes]; sd.nodeDepth _ sd.nodeDepth + 1} ELSE { sd.nodes.first _ TFO.InsertNode[x: sd.nodes.first, child: FALSE]; }; IF adjProp#NIL THEN NodeProps.PutProp[NARROW[AsRef[sd.nodes.first]], $Postfix, adjProp]; IF fmt#NIL THEN TFO.SetFormat[sd.nodes.first, fmt]; sd.contents _ NIL; sd.ready _ TRUE; sd.userDepth _ sd.nodeDepth; WHILE sd.userDepth < sd.nextDepth DO sd.contents _ sd.contents.Concat[sd.levelPrefix]; sd.userDepth _ sd.userDepth + 1; ENDLOOP; IF sd.lpCharsSeen > 0 THEN { sd.contents _ sd.contents.Concat[sd.levelPrefix.Substr[len: sd.lpCharsSeen]]; }; }; AsRef: PROC [r: REF ANY] RETURNS [REF ANY] ~ INLINE {RETURN [r]}; SetTFOComment: PROC [tfo: TFO.Ref] ~ { tn: TN.RefTextNode ~ NARROW[AsRef[tfo]]; NodeProps.PutProp[n: tn, name: $Comment, value: NodeProps.true]}; CopyChildren: PUBLIC PROC [from: TN.Ref, to: TFO.Ref] = BEGIN Work: PROC [from: TN.Ref, to: TFO.Ref] RETURNS [next: TN.Ref, dd: INT] = TRUSTED { last: TFO.Ref _ to; lastIsParent: BOOLEAN _ TRUE; [next, dd] _ TN.Forward[from]; IF dd > 1 THEN ERROR; IF dd < 1 THEN RETURN; dd _ dd - 1; WHILE dd = 0 DO toKid: TFO.Ref; tn: TN.RefTextNode _ next; r: ROPE _ TN.NodeRope[tn]; toKid _ last.InsertNode[child: lastIsParent]; toKid.SetContents[r]; IF tn.comment THEN SetTFOComment[toKid]; last _ toKid; lastIsParent _ FALSE; [next, dd] _ Work[next, toKid]; ENDLOOP; dd _ dd + 1; }; [] _ Work[from, to]; END; RopeFromSubText: PROC [text: REF READONLY TEXT, startIndex, count: NAT] RETURNS [rope: ROPE] = { rope _ Rope.FromRefText[text, startIndex, count]; }; IsLB: PROC [c: CHAR] RETURNS [BOOL] ~ INLINE {RETURN [c='\r OR c='\l]}; END. TiogaStreamsImpl.Mesa Copyright Σ 1990 by Xerox Corporation. All rights reserved. Last Edited by: Spreitzer, September 18, 1985 5:59:06 pm PDT Last tweaked by Mike Spreitzer on April 25, 1990 10:57:31 am PDT Mike Spreitzer April 24, 1990 8:52 am PDT ΚT•NewlineDelimiter – "cedar" style˜codešœ™K™Kšœ œ˜(Kšœ œœ˜Kšœ œ˜Kšœ œ˜—K˜šŸ œœœœ?œœœœœ˜ˆšœ˜K˜šœ˜Kšœ œ˜Kšœœœœ˜ Kšœœœ˜(Kšœœ˜—Kšœ˜——K˜šŸœœœœ.œœœœœœ˜Kš˜šœœ˜5Kšœ˜K˜Kšœœ˜ Kšœ ˜ Kšœ˜—Kšœ˜Kšœœ?˜FKšœ˜—K˜šŸ œœ˜/Kšœœ˜Kš œ œœ œœ˜.Kšœœ˜$Kš œ œœ œœ˜.šœ˜Kšœœœ˜˜Kšœ œ˜K˜ Kšœ˜Kšœ˜K˜—Kšœœ˜—K˜—K˜šŸœœ˜.Kš˜Kšœœœ˜šœ˜Kšœœ˜Kšœœ˜ Kšœ œ˜!Kš œœœœ œœ˜?K˜K˜Kšœ7˜7K˜Kšœ˜Kšœ˜—Kšœ˜—K˜šŸ œœ˜)Kš˜Kšœœ˜šŸœœœ˜$šœœœ˜>Kšœ'˜'Kšœ˜—K˜&Kšœœ˜K˜Kšœ˜K˜K˜ K˜Kšœ˜—K˜Kšœœœ˜5šœœœ˜&KšœDœ˜IKšœ œ˜Kšœœ˜#Kšœœœ˜Kš œœœœœ˜Kš œ œœœœ %˜AKšœœœ˜Kšœœ˜Kšœ œ #˜7Kšœ œ ˜.Kšœœ %˜=Kšœœ˜'K˜Kšœœ˜Kšœ œœ˜Kšœœœ˜Kšœ œœ˜Kš œœœ œœ˜+—K˜Kšœ œœ˜!Kš œœœœ œœœ˜AK˜Kšœ œœœ ˜#Kšœ œœœ˜0Kšœœœ ˜Kšœ œ˜K˜šŸ œœœœœœœœœœ"œœœœ˜ΙKšœœo˜x—K˜š Ÿœœœœœœœœœœ0œœ/œœœœ˜¨Kš˜Kšœœ˜*šœœ˜7Kšœ˜Kšœœœ ˜+K˜Kšœ˜Kšœœœ˜*Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ'˜'Kšœ ˜ Kšœœ˜Kš œ œœœœ˜EKšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜—K˜šœœ˜Kšœ œ-˜:Kš œœœœœœ˜?—šœœ œ˜"Kšœœ˜KšœE˜IKšœœ˜—Kšœœ@˜HK˜K˜FK˜FK˜3K˜Kšœ˜—K˜Kšœœœœs˜ŸK˜š Ÿœœœœœ˜-Kš˜Kšœœ˜1šœœ˜Kšœœ%œœ˜JKšœ œœœ˜'š œœ œœ œ˜?Kšœœ œœ˜AKšœ˜—šœ0˜0Kšœ$˜$Kšœœ7˜[Kšœ˜—Kšœœ˜—K˜K˜6Kšœ˜—K˜šŸœœœœ œœœœ˜TKš˜Kšœœ˜1Kšœœ˜Kšœ œ˜$šœ˜Kšœœ˜šœœ œ˜,K˜K˜Kšœœœ˜!Kšœ˜—Kš œœœœœœ˜`šœœ˜'KšœH˜HK˜K˜—Kšœ˜—Kšœ˜—K˜š Ÿœœœœ œœ˜7Kš˜K˜KšœUœ˜ZKšœ˜—K˜šŸ œœœœœœœ˜=Kš˜Kšœœ˜.K˜Kšœ˜—K˜š Ÿ œœœœœ œ˜6Kš˜Kšœœ˜Kšœ˜Kšœ˜—K˜š Ÿœœ œœœ&œ˜XKšœœ˜3K˜šœœ˜Kšœœ0˜6Kšœœœ#˜6—K˜—K˜š Ÿœœ œœœ&œ˜XKšœœ˜3K˜šœœ˜Kšœœ(˜-Kšœœœ#˜6—K˜—K˜š Ÿ œœ œœ!œ˜LKšœœ˜"šœœœ˜&Kšœœ˜šœ˜ K˜:šœ˜Kš œœœ)œœ3˜ŠK˜—šœ(˜*Kšœœœ)œ%˜jK˜—Kšœœœ#˜6—Kšœ˜—K˜—K˜šŸœœœœœ*œœ˜^Kš˜Kšœœ˜.Kšœœ˜Kšœ œ˜Kšœœ˜šœœ ˜Kš˜Kšœœœ˜K˜Kšœ˜—šœœ œ˜"Kšœœ˜Kš œœ œ6œ;œœ˜ΌKšœœ˜—KšœP˜SKšœœ˜*K˜Kšœ œ˜Kšœ/˜/Kšœœ˜šœœ ˜"K˜K˜ Kšœœ˜—Kšœ˜—K˜šŸœœ$œ˜:Kšœœ˜ šœ œ˜šœ&œœ˜:Kšœœœ˜&Kš œ œœ œœ˜TKšœ œ˜$Kšœœœ_˜zKšœ˜—Kšœ˜—Kšœ œœ˜K˜—K˜šŸ œœœœœœœœœœ˜~Kš˜Kšœœ˜.Kšœ œ ˜3Kšœ œœ ˜!Kšœœœ8˜SKšœ+˜+Kšœ˜—K˜Kšœœœ ˜*Kš œ œœœœœ˜0Kš œ œ œ œœ˜3K˜šŸœœœœ˜?Kšœ œœœ˜Kšœœ˜š Ÿœœœœœ˜(Kšœœ˜Kšœœœœ8˜`Kšœ˜—š Ÿœœ œœœœ˜/šœœœ˜ Kšœœœ/œ5˜Kšœ˜—Kšœœœ7˜b—Kšœ œœ˜šœœ˜Kšœœ˜ Kšœ˜šœ˜%K˜Kšœ ˜ Kšœ˜—šœœ˜&Kšœ œ˜)Kšœ!˜!—šœ œ,˜=Kšœœ9˜NKšœœœ9˜SKšœ˜—Kšœœ œ:œ˜lK˜—šœ˜Kšœ,˜,K˜—Kšœœœ˜9šœ˜$K˜Kšœ ˜ Kšœ˜—šœ˜šœ˜Kšœ œœ1˜DKšœ ˜ —šœ˜Kšœœ&œ˜AKšœ˜——Kšœ œœœ,˜XKšœœœœ ˜3Kšœœ˜Kšœ œ˜Kšœ˜šœ˜$Kšœ1˜1K˜ Kšœ˜—šœœ˜KšœM˜MK˜—Kšœ˜—K˜KšŸœœœœœœœœœ˜AK˜šŸ œœœ ˜&Kšœœœ ˜(KšœA˜A—K˜š Ÿ œœœœ œ˜7Kš˜K˜šŸœœœ œœœ œœ˜RKšœœ ˜Kšœœœ˜Kšœ œ˜Kšœœœ˜Kšœœœ˜K˜ šœ˜Kšœœ˜Kšœœ˜Kšœœœ˜K˜-Kšœ˜Kšœ œ˜(Kšœœ˜#K˜Kšœ˜—K˜ Kšœ˜—K˜K˜Kšœ˜—K˜šŸœœœœœœœœ˜`K˜1K˜—K˜š Ÿœœœœœ˜#Kšœœœœ ˜#—K˜Kšœ˜—…—Cn\Δ