DIRECTORY Ascii USING [Lower], Atom USING [EmptyAtom, MakeAtom, MakeAtomFromRefText], Basics USING [BITXOR, LowHalf], BasicTime USING [GMT], FileOps USING [comment, endNode, endOfFile, FormatIndex, IntBytes, LengthByte, look1, look2, look3, looks, looksFirst, LooksIndex, looksLast, numFormats, numLooks, numProps, Op, otherNode, otherNodeShort, otherNodeSpecs, otherNodeSpecsShort, prop, PropIndex, propShort, rope, runs, startNode, startNodeFirst, startNodeLast, terminalTextNode, terminalTextNodeFirst, terminalTextNodeLast, ThirdByte], FileReader USING [FromRope, FromStream, Open, OpenC], FS USING [ComponentPositions, ExpandName, GetName, OpenFile, Position], IO USING [STREAM], NodeProps USING [DoSpecs, PutProp], PGSupport USING [FormatHashIndex, formatHashSize, LooksHashIndex, looksHashSize, noLooks, PGF, PGFBody, PropHashIndex, propHashSize], PrincOps USING [zXOR], PutGet USING [], Rope USING [MaxLen, ROPE, Substr, Translate], RopeEdit USING [MaxLen, Substr], RopeReader USING [Backwards, BumpIndex, Get, GetRope, Position, ReadOffEnd, Ref, SetIndex], Rosary USING [ROSARY, Size], RuntimeError USING [UNCAUGHT], SafeStorage USING [SetCollectionInterval], TextEdit USING [], TextLooks USING [CreateRun, Concat, Looks, LooksBytes, noLooks, Runs], TextNode USING [MaxLen, Node, NodeRep]; GetFileImpl: CEDAR MONITOR IMPORTS Ascii, Atom, Basics, FileReader, FS, NodeProps, Rope, RopeEdit, RopeReader, Rosary, RuntimeError, SafeStorage, TextLooks EXPORTS PGSupport, PutGet SHARES TextLooks = BEGIN OPEN FileOps; FormatHashIndex: TYPE ~ PGSupport.FormatHashIndex; formatHashSize: NAT ~ PGSupport.formatHashSize; LooksHashIndex: TYPE ~ PGSupport.LooksHashIndex; looksHashSize: NAT ~ PGSupport.looksHashSize; PGF: TYPE ~ PGSupport.PGF; PGFBody: TYPE ~ PGSupport.PGFBody; PropHashIndex: TYPE ~ PGSupport.PropHashIndex; propHashSize: NAT ~ PGSupport.propHashSize; Node: TYPE ~ TextNode.Node; ROPE: TYPE = Rope.ROPE; ROSARY: TYPE = Rosary.ROSARY; FromFileError: PUBLIC ERROR = CODE; FromFile: PUBLIC PROC [fileName: ROPE, start: INT _ 0, len: INT _ TextNode.MaxLen] RETURNS [root: Node] = { control, comment, stext: RopeReader.Ref; tiogaFile: BOOL; fh: FS.OpenFile; createDate: BasicTime.GMT; StartRead[]; { ENABLE UNWIND => EndRead[]; [control, comment, stext, tiogaFile, fh, createDate] _ FileReader.Open[fileName, start, len]; root _ Finish[control, comment, stext, tiogaFile]; }; AddFileExtension[root, fh]; AddCreateDate[root, createDate]; EndRead[]; }; FromFileC: PUBLIC PROC [file: FS.OpenFile, start: INT _ 0, len: INT _ TextNode.MaxLen] RETURNS [root: Node] = { control, comment, stext: RopeReader.Ref; tiogaFile: BOOL; createDate: BasicTime.GMT; StartRead[]; { ENABLE UNWIND => EndRead[]; [control, comment, stext, tiogaFile, createDate] _ FileReader.OpenC[file, start, len]; root _ Finish[control, comment, stext, tiogaFile]; }; AddFileExtension[root, file]; AddCreateDate[root, createDate]; EndRead[]; }; AddFileExtension: PROC [root: Node, file: FS.OpenFile] = { ForceLower: PROC [r: ROPE] RETURNS [ROPE] = { ForceCharLower: PROC [old: CHAR] RETURNS [new: CHAR] = { RETURN [Ascii.Lower[old]]; }; RETURN [Rope.Translate[base: r, translator: ForceCharLower]]; }; name: ROPE; cp: FS.ComponentPositions; [fullFName: name, cp: cp] _ FS.ExpandName[name: FS.GetName[file].fullFName]; NodeProps.PutProp[root, $FileExtension, IF cp.ext.length=0 THEN $null ELSE Atom.MakeAtom[ForceLower[name.Substr[cp.ext.start, cp.ext.length]]]]; }; AddCreateDate: PROC [root: Node, createDate: BasicTime.GMT] = { NodeProps.PutProp[root, $FileCreateDate, NEW[BasicTime.GMT _ createDate]]; }; FromRope: PUBLIC PROC [rope: ROPE, start: INT _ 0, len: INT _ TextNode.MaxLen] RETURNS [root: Node] = { control, comment, stext: RopeReader.Ref; tiogaFile: BOOL; StartRead[]; { ENABLE UNWIND => EndRead[]; [control, comment, stext, tiogaFile] _ FileReader.FromRope[rope, start, len]; root _ Finish[control, comment, stext, tiogaFile]; }; EndRead[]; }; FromStream: PUBLIC PROC [stream: IO.STREAM, len: INT _ TextNode.MaxLen] RETURNS [root: Node] = { control, comment, stext: RopeReader.Ref; tiogaFile: BOOL; StartRead[]; { ENABLE UNWIND => EndRead[]; [control, comment, stext, tiogaFile] _ FileReader.FromStream[stream, len]; root _ Finish[control, comment, stext, tiogaFile]; }; EndRead[]; }; collectionInterval: LONG CARDINAL; bigCollectionInterval: LONG CARDINAL = 1000000; startCount: INTEGER _ 0; StartRead: ENTRY PROC = { ENABLE UNWIND => NULL; IF startCount = 0 THEN { collectionInterval _ SafeStorage.SetCollectionInterval[bigCollectionInterval]; }; startCount _ startCount+1; }; EndRead: ENTRY PROC = { -- restore initial collectionInterval when all Get's done ENABLE UNWIND => NULL; IF (startCount _ startCount-1) = 0 THEN [] _ SafeStorage.SetCollectionInterval[collectionInterval]; }; Finish: PROC [control, cmmnt, stext: RopeReader.Ref, tiogaFile: BOOL] RETURNS [root: Node] = { op: Op; parent, node, prev: Node; textNode: Node; terminalNode: BOOL; textLength, runsLength: INT _ 0; formatName: ATOM; propname: ATOM; charProps: REF _ NIL; charSets: REF _ NIL; InsertNode: PROC [node: Node] = { IF prev#NIL THEN prev.next _ node ELSE IF parent#NIL THEN parent.child _ node; prev _ node; }; ReadByte: PROC RETURNS [BYTE] = INLINE { RETURN [LOOPHOLE[ReadChar[]]]; }; ReadChar: PROC RETURNS [CHAR] = { RETURN [RopeReader.Get[control]]; }; ReadProp: PROC = { specs: ROPE _ GetControlRope[]; disaster: BOOL _ FALSE; value: REF; value _ NodeProps.DoSpecs[propname, specs ! RuntimeError.UNCAUGHT => {disaster_TRUE} ]; IF disaster THEN ERROR FromFileError; IF value # NIL THEN { IF propname = $CharProps THEN charProps _ value ELSE IF propname = $CharSets THEN charSets _ value ELSE NodeProps.PutProp[node, propname, value]; }; }; GetRope: PROC [len: INT, rdr: RopeReader.Ref] RETURNS [ROPE] = { rope: ROPE; pos: INT; [rope, pos] _ RopeReader.Position[rdr]; RopeReader.SetIndex[rdr, pos+len]; RETURN [RopeEdit.Substr[rope, pos, len]]; }; GetControlRope: PROC RETURNS [ROPE] = { RETURN [GetRope[ReadLength[], control]]; }; GetText: PROC = { len: NAT; IF (len _ ReadByte[]) > text.maxLength THEN text _ NEW[TEXT[len]]; FOR i: NAT IN [0..len) DO text[i] _ RopeReader.Get[control]; ENDLOOP; text.length _ len; }; GetAtom: PROC RETURNS [ATOM] = { GetText[]; -- get the print name RETURN [IF text.length = 0 THEN NIL ELSE Atom.MakeAtomFromRefText[text]]; }; ReadLength: PROC RETURNS [INT] = { first, second, fourth: LengthByte; third: ThirdByte; card: IntBytes; first _ LOOPHOLE[ReadByte[]]; card.first _ first.data; IF ~first.others THEN RETURN [LOOPHOLE[card]]; second _ LOOPHOLE[ReadByte[]]; card.second _ second.data; IF ~second.others THEN RETURN [LOOPHOLE[card]]; third _ LOOPHOLE[ReadByte[]]; card.thirdBottom _ third.dataBottom; card.thirdTop _ third.dataTop; IF ~third.others THEN RETURN [LOOPHOLE[card]]; fourth _ LOOPHOLE[ReadByte[]]; card.fourth _ fourth.data; RETURN [LOOPHOLE[card]]; }; NextOp: PROC RETURNS [op: Op] = { op _ RopeReader.Get[control ! RopeReader.ReadOffEnd => { op _ endOfFile; CONTINUE }]; }; pgf: PGF _ CreatePGF[]; text: REF TEXT _ NEW[TEXT[32]]; terminalNode _ FALSE; op _ NextOp[]; DO SELECT op FROM IN [terminalTextNodeFirst..terminalTextNodeLast] => { formatName _ RetrieveFormatName[ LOOPHOLE[op-terminalTextNodeFirst, FormatIndex], pgf ! BadIndex => ERROR FromFileError ]; terminalNode _ TRUE; }; IN [startNodeFirst..startNodeLast] => formatName _ RetrieveFormatName[ LOOPHOLE[op-startNodeFirst, FormatIndex], pgf ! BadIndex => ERROR FromFileError ]; endNode => { IF prev#NIL THEN { prev.last _ TRUE; prev.next _ parent;}; prev _ parent; IF (parent _ parent.next)=NIL THEN EXIT; op _ NextOp[]; LOOP; }; startNode => { formatName _ GetAtom[]; [] _ EnterFormatName[formatName, pgf]; }; terminalTextNode => { formatName _ GetAtom[]; [] _ EnterFormatName[formatName, pgf]; terminalNode _ TRUE; }; rope, comment => { reader: RopeReader.Ref; CheckRosary: PROC [val: REF, size: INT] RETURNS [ROSARY] ~ { WITH val SELECT FROM rosary: ROSARY => IF Rosary.Size[rosary]=size THEN RETURN[rosary]; ENDCASE; ERROR FromFileError; }; IF op=rope THEN reader _ stext ELSE { reader _ cmmnt; textNode.comment _ TRUE;}; IF textNode=NIL OR textNode#node THEN ERROR FromFileError; IF (textLength_ReadLength[])>0 THEN textNode.rope _ GetRope[textLength, reader]; IF charProps#NIL THEN textNode.charProps _ CheckRosary[charProps, textLength]; IF charSets#NIL THEN textNode.charSets _ CheckRosary[charSets, textLength]; charProps _ charSets _ NIL; SELECT runsLength FROM 0 => NULL; -- no runs for this rope textLength => runsLength _ 0; -- correct length ENDCASE => ERROR FromFileError; -- mismatch RopeReader.BumpIndex[reader, 1]; -- skip CR at end of rope op _ NextOp[]; LOOP; }; runs => { -- runs, if any, come before corresponding rope lookRuns: TextLooks.Runs; numRuns: INT; pos: INT _ 0; IF textNode=NIL OR textNode#node THEN ERROR FromFileError; numRuns _ ReadLength[]; -- read number of runs FOR i: INT IN [0..numRuns) DO looks: TextLooks.Looks; -- looks for this run length: INT; -- length of this run run: TextLooks.Runs; ReadLookChars: PROC [num: NAT] = { FOR i:NAT IN [0..num) DO looks[ReadChar[]] _ TRUE; ENDLOOP; [] _ EnterLooks[looks, pgf]; }; SELECT op _ NextOp[] FROM IN [looksFirst .. looksLast] => { looks _ RetrieveLooks[ LOOPHOLE[op-looksFirst, LooksIndex], pgf ! BadIndex => ERROR FromFileError ] }; look1 => ReadLookChars[1]; look2 => ReadLookChars[2]; look3 => ReadLookChars[3]; FileOps.looks => { lb: TextLooks.LooksBytes; lb.byte0 _ ReadByte[]; lb.byte1 _ ReadByte[]; lb.byte2 _ ReadByte[]; lb.byte3 _ ReadByte[]; [] _ EnterLooks[looks _ LOOPHOLE[lb], pgf]; }; ENDCASE => ERROR FromFileError; length _ ReadLength[]; run _ TextLooks.CreateRun[length, looks]; lookRuns _ IF lookRuns=NIL THEN run ELSE TextLooks.Concat[lookRuns, run, pos, length]; pos _ pos+length; ENDLOOP; runsLength _ pos; -- for use in checking rope length textNode.charLooks _ lookRuns; op _ NextOp[]; LOOP; }; prop => { [] _ EnterProp[propname _ GetAtom[], pgf]; ReadProp; op _ NextOp[]; LOOP; }; propShort => { propname _ RetrieveProp[ LOOPHOLE[ReadByte[], PropIndex], pgf ! BadIndex => ERROR FromFileError ]; ReadProp; op _ NextOp[]; LOOP; }; otherNode, otherNodeShort, otherNodeSpecs, otherNodeSpecsShort => { ERROR FromFileError; }; endOfFile => { IF parent=NIL THEN EXIT; -- have reached the root [] _ RopeReader.Backwards[control]; -- backup so read endOfFile again op _ endNode; LOOP; }; ENDCASE => ERROR FromFileError; IF charProps # NIL OR charSets # NIL THEN ERROR FromFileError; InsertNode[node _ textNode _ NEW[TextNode.NodeRep]]; node.formatName _ formatName; IF terminalNode THEN terminalNode _ FALSE ELSE { node.next _ parent; parent _ node; prev _ NIL }; op _ NextOp[]; ENDLOOP; IF (root _ prev)=NIL THEN -- don't have a normal tree IF node=NIL THEN root _ NEW[TextNode.NodeRep] -- null file ELSE root _ node; -- single node in file root.last _ TRUE; NodeProps.PutProp[root, $FromTiogaFile, IF tiogaFile THEN $Yes ELSE $No]; FreePGF[pgf]; }; Looks: TYPE ~ TextLooks.Looks; noLooks: Looks ~ TextLooks.noLooks; PropIndex: TYPE ~ FileOps.PropIndex; FormatIndex: TYPE ~ FileOps.FormatIndex; LooksIndex: TYPE ~ FileOps.LooksIndex; CreatePGF: PUBLIC PROC RETURNS [pgf: PGF] = { pgf _ AllocPGF[]; pgf.looksTable[0] _ TextLooks.noLooks; pgf.looksNext _ 1; -- reserve 0 for noLooks FOR i:LooksHashIndex IN LooksHashIndex DO pgf.looksHashKeys[i].looks _ TextLooks.noLooks; ENDLOOP; pgf.formatTable[0] _ NIL; FOR i:FormatHashIndex IN FormatHashIndex DO pgf.formatHashKeys[i].formatName _ NIL; ENDLOOP; pgf.formatNext _ 1; -- reserve 0 for null formatname pgf.propNext _ 1; --reserve 0 for NIL FOR i:PropHashIndex IN PropHashIndex DO pgf.propHashKeys[i].propname _ NIL; ENDLOOP; [] _ EnterProp[$Prefix, pgf]; -- preload system atoms [] _ EnterProp[$Postfix, pgf]; }; pgf1, pgf2, pgf3: PGF _ NIL; AllocPGF: ENTRY PROC RETURNS [pgf: PGF] = { ENABLE UNWIND => NULL; IF pgf3 # NIL THEN { pgf _ pgf3; pgf3 _ NIL } ELSE IF pgf2 # NIL THEN { pgf _ pgf2; pgf2 _ NIL } ELSE IF pgf1 # NIL THEN { pgf _ pgf1; pgf1 _ NIL } ELSE pgf _ NEW[PGFBody] }; FreePGF: PUBLIC ENTRY PROC [pgf: PGF] = { ENABLE UNWIND => NULL; IF pgf3 = pgf OR pgf2 = pgf OR pgf1 = pgf THEN ERROR; IF pgf3 = NIL THEN pgf3 _ pgf ELSE IF pgf2 = NIL THEN pgf2 _ pgf ELSE IF pgf1 = NIL THEN pgf1 _ pgf }; BadIndex: PUBLIC ERROR = CODE; RetrieveFormatName: PUBLIC PROC [index: FormatIndex, pgf: PGF] RETURNS [formatName: ATOM] = { IF index >= pgf.formatNext THEN ERROR BadIndex; RETURN [pgf.formatTable[index]] }; RetrieveLooks: PUBLIC PROC [index: LooksIndex, pgf: PGF] RETURNS [looks: Looks] = { IF index >= pgf.looksNext THEN ERROR BadIndex; RETURN [pgf.looksTable[index]] }; RetrieveProp: PUBLIC PROC [index: PropIndex, pgf: PGF] RETURNS [propname: ATOM] = { IF index >= pgf.propNext THEN ERROR BadIndex; RETURN [pgf.propTable[index]] }; Munch: PROC [key: ATOM] RETURNS [CARDINAL] = TRUSTED MACHINE CODE {PrincOps.zXOR}; true: BOOL[TRUE..TRUE] ~ (SIZE[ATOM]-SIZE[CARDINAL] = 1); EnterFormatName: PUBLIC PROC [formatName: ATOM, pgf: PGF] RETURNS [ok: BOOL, index: FileOps.FormatIndex] = { next: NAT _ pgf.formatNext; initloc, loc: NAT; IF formatName = NIL OR formatName = Atom.EmptyAtom[] THEN RETURN [TRUE, 0]; -- reserved loc _ initloc _ Munch[formatName] MOD formatHashSize; DO SELECT pgf.formatHashKeys[loc].formatName FROM formatName => RETURN [TRUE, pgf.formatHashVals[loc].index]; NIL => EXIT; -- this is an unused entry ENDCASE; SELECT (loc _ loc+1) FROM formatHashSize => IF (loc _ 0)=initloc THEN ERROR; initloc => ERROR; -- should never have full table ENDCASE; ENDLOOP; IF next < FileOps.numFormats THEN -- room left in table BEGIN pgf.formatTable[next] _ formatName; pgf.formatNext _ next+1; pgf.formatHashKeys[loc].formatName _ formatName; pgf.formatHashVals[loc].index _ LOOPHOLE[next]; END; RETURN [FALSE, 0] -- index irrelevant in this case }; EnterLooks: PUBLIC PROC [looks: TextLooks.Looks, pgf: PGF] RETURNS [ok: BOOL, index: FileOps.LooksIndex] = { next: NAT _ pgf.looksNext; initloc, loc: NAT; IF looks = TextLooks.noLooks THEN RETURN [TRUE, 0]; -- reserved loc _ initloc _ LOOPHOLE[ Basics.BITXOR[ LOOPHOLE[looks, TextLooks.LooksBytes].byte0, Basics.BITXOR[LOOPHOLE[looks, TextLooks.LooksBytes].byte1, LOOPHOLE[looks, TextLooks.LooksBytes].byte2]],NAT] MOD looksHashSize; DO SELECT pgf.looksHashKeys[loc].looks FROM looks => RETURN [TRUE, pgf.looksHashVals[loc].index]; TextLooks.noLooks => EXIT; -- this is an unused entry ENDCASE; SELECT (loc _ loc+1) FROM looksHashSize => IF (loc _ 0)=initloc THEN ERROR; initloc => ERROR; -- should never have full table ENDCASE; ENDLOOP; IF next < FileOps.numLooks THEN { pgf.looksTable[next] _ looks; pgf.looksNext _ next+1; pgf.looksHashKeys[loc].looks _ looks; pgf.looksHashVals[loc].index _ LOOPHOLE[next]; }; RETURN [FALSE, 0] -- index irrelevant in this case }; EnterProp: PUBLIC PROC [propname: ATOM, pgf: PGF] RETURNS [ok: BOOL, index: FileOps.PropIndex] = { next: NAT _ pgf.propNext; initloc, loc: NAT; IF propname = NIL THEN RETURN [TRUE, 0]; -- reserved loc _ initloc _ (LOOPHOLE[Basics.LowHalf[LOOPHOLE[propname]],NAT] / 16) MOD propHashSize; DO SELECT pgf.propHashKeys[loc].propname FROM propname => RETURN [TRUE, pgf.propHashVals[loc].index]; NIL => EXIT; -- this is an unused entry ENDCASE; SELECT (loc _ loc+1) FROM propHashSize => IF (loc _ 0)=initloc THEN ERROR; initloc => ERROR; -- should never have full table ENDCASE; ENDLOOP; IF next < FileOps.numProps THEN { pgf.propTable[next] _ propname; pgf.propNext _ next+1; pgf.propHashKeys[loc].propname _ propname; pgf.propHashVals[loc].index _ LOOPHOLE[next]; }; RETURN [FALSE, 0] -- index irrelevant in this case }; END. μGetFileImpl.mesa Copyright Σ 1984, 1985, 1986, 1987, 1988 by Xerox Corporation. All rights reserved. written by Paxton. January 1981 Paxton. December 1, 1982 9:44 am Paul Rovner, August 10, 1983 4:28 pm Russ Atkinson, June 18, 1984 8:29:12 pm PDT Rick Beach, March 28, 1985 9:46:42 am PST Michael Plass, October 19, 1987 9:47:57 am PDT Doug Wyatt, February 17, 1988 5:31:29 pm PST The character properties and character sets are not stored in the node until after the rope is stored, so that we can do a consistency check. MAIN PROGRAM read 4 bytes of looks from control stream if reach here, then want to start a new text node PGSupport implementation -- PGF is the file-level structure for put/get room left in table room left in table Κι˜codešœ™KšœT™TKšœ ™ Kšœ ™ Kšœ$™$Kšœ+™+K™)Kšœ.™.Kšœ,™,—K˜šΟk ˜ Kšœœ ˜Kšœœ-˜7Jšœœœ ˜Kšœ œœ˜Kšœœ‚˜Kšœ œ&˜6Kšœœ@˜HKšœœœ˜Kšœ œ˜$Kšœ œKœ)˜†Jšœ œ˜Kšœœ˜Kšœœ œ˜.Kšœ œ˜!Kšœ œL˜\Kšœœœ ˜Kšœ œœ˜Kšœ œ˜+Kšœ œ˜Kšœ œ7˜FKšœ œ˜'—K˜KšΠbl œœ˜Kšœ"œU˜€Kšœ˜Kšœ ˜šœœœ ˜K˜Kšœœ˜2Kšœœ˜/Kšœœ˜0Kšœœ˜-Kšœœ œ˜Kšœ œ˜"Kšœœ˜.Kšœœ˜+K˜Kšœœ˜Kšœœœ˜Kšœœ œ˜IunitšΟn œœœœ˜#šŸœœœ œ œ œœ˜kK˜(Kšœ œ˜Kšœœ ˜Kšœœ˜K˜ šœœœ˜˜6Kšœ&˜&—Kšœ2˜2K˜—K˜K˜ K˜ K˜—K˜š Ÿ œœœœœ œ˜VKšœ˜K˜(Kšœ œ˜Kšœœ˜K˜ šœœœ˜KšœV˜VKšœ2˜2K˜—K˜K˜ K˜ K˜K˜—šŸœœœ˜:š Ÿ œœœœœ˜-š Ÿœœœœœ˜8Kšœ˜K˜—Kšœ7˜=K˜—Kšœœœ˜&Kšœœœ˜Lšœ(œœ˜EKšœF˜J—K˜—K˜šŸ œœ$œ˜?šœ)˜)Kšœ œ˜!—K˜—K˜KšŸœœ˜š œœ œ œœ˜QK˜(Kšœ œ˜K˜ šœœœ˜KšœM˜MKšœ2˜2K˜—K˜ K˜—K˜KšŸ œœ˜š œ œœœœ˜HK˜(Kšœ œ˜K˜ šœœœ˜KšœJ˜JKšœ2˜2K˜—K˜ K˜—K˜Kšœœœ˜"Kšœœœ ˜/Kšœ œ˜šŸ œœœ˜Kšœœœ˜šœœ˜K˜NK˜—K˜K˜—K˜šŸœœœΟc9˜QKšœœœ˜Kšœ!˜'K˜;K˜—K˜šŸœœ4œœ˜^K˜K˜K˜K˜Kšœœ˜Kšœœ˜ Kšœ œ˜Kšœ œ˜Kšœ œœ˜Kšœ œœ˜K˜šŸ œœ˜!šœœœ˜!Kšœœœœ˜,—K˜ K˜—K˜š Ÿœœœœœ˜(Kšœœ˜K˜—K˜šŸœœœœ˜!Kšœ˜!K˜—K˜šŸœœ˜Kšœœ˜Kšœ œœ˜Kšœœ˜ šœ+˜+Kšœ œœ˜(Kšœ˜—Kšœ œœ˜&šœ œœ˜J™Jšœœ˜/Jšœœœ˜2Jšœ*˜.Jšœ˜—K˜—K˜š Ÿœœœœœ˜@Kšœœ˜ Kšœœ˜ K˜'K˜"Kšœ#˜)K˜—K˜šŸœœœœ˜'Kšœ"˜(K˜—K˜šŸœœ˜Kšœœ˜ Kšœ%œœœ˜Bšœœœ ˜Kšœ"˜"Kšœ˜—Kšœ˜K˜—K˜šŸœœœœ˜ Kšœ  ˜ Kš œœœœœ!˜IK˜—K˜šŸ œœœœ˜"K˜"K˜K˜Kšœœ ˜K˜Kšœœœœ˜.Kšœ œ ˜K˜Kšœœœœ˜/Kšœœ ˜K˜$K˜Kšœœœœ˜.Kšœ œ ˜K˜Kšœœ˜K˜—K˜šŸœœœ˜"K˜KšœIœ˜UK˜—K˜Kšœ ™ Kšœœ˜Kš œœœœœ˜K˜Kšœœ˜K˜š˜šœ˜šœ3˜5šœ ˜ Kšœ,˜4Kšœœ˜!Kšœ˜—Kšœœ˜K˜—Kšœ#˜%šœ ˜ Kšœ%˜-Kšœœ˜!Kšœ˜—˜ Kšœœœœ˜:K˜Kšœœœœ˜(Kšœœ˜K˜—˜K˜K˜&K˜—˜K˜K˜&Kšœœ˜K˜—˜K˜š Ÿ œœœœœœ˜<šœœ˜Kš œœœœœ ˜BKšœ˜—Kšœ˜K˜—Kšœ œœ&œ˜PKš œ œœœœ˜:Kšœœ-˜PKšœ œœ9˜NKšœ œœ7˜KKšœœ˜šœ ˜Kšœœ ˜#Kšœ ˜/Kšœœ  ˜+—Kšœ! ˜:Kšœœ˜K˜—šœ  /˜9K˜Kšœ œ˜ Kšœœ˜ Kš œ œœœœ˜:Kšœ ˜.šœœœ˜Kšœ ˜-Kšœœ ˜"K˜šŸ œœœ˜"Kš œœœ œœœ˜;K˜K˜—šœ˜šœ˜!šœ˜Kšœ ˜(Kšœœ˜!Kšœ˜—Kšœ˜—K˜K˜K˜˜Kšœ)™)K˜K˜-K˜-Kšœœ ˜+K˜—Kšœœ˜—Kšœ˜Kšœ)˜)Kšœ œ œœ˜#Kšœ.˜2Kšœ˜Kšœ˜—Kšœ "˜4K˜Kšœœ˜K˜—˜ K˜*K˜ Kšœœ˜K˜—˜šœ˜Kšœ˜$Kšœœ˜!Kšœ˜—K˜ Kšœœ˜K˜—šœC˜CKšœ˜K˜—˜Kš œœœœ ˜1Kšœ$ !˜EKšœœ˜K˜—Kšœœ˜—Kšœ1™1Kš œ œœ œœœ˜>Kšœœ˜4K˜Kšœœ˜)Kšœ-œ˜7K˜Kšœ˜—Kšœœœ ˜5š œœœœ  ˜:Kšœ ˜(—Kšœ œ˜Kšœ(œ œœ˜IK˜ K˜—K˜—head™Kšœœ˜Kšœ#˜#K˜Kšœ œ˜$Kšœ œ˜(Kšœ œ˜&K™Kšœ.™.K˜š Ÿ œœœœœ˜-Kšœ˜K˜&Kšœ ˜+šœœ˜)Kšœ/˜/Kšœ˜—Kšœœ˜šœœ˜+Kšœ#œ˜'Kšœ˜—Kšœ  ˜4Kšœ ˜%šœœ˜'Kšœœ˜#Kšœ˜—Kšœ ˜5K˜K˜K˜—Kšœœœ˜K˜š Ÿœœœœœ˜+Kšœœœ˜Kšœœœœ˜-Kš œœœœœ˜2Kš œœœœœ˜2Kšœœ ˜Kšœ˜K˜—š Ÿœœœœœ˜)Kšœœœ˜Kš œ œ œ œœ˜5Kšœœœ ˜Kšœœœœ ˜"Kšœœœœ ˜"Kšœ˜K˜—šœ œœœ˜K˜—š Ÿœœœœœœ˜Yš œœœœ œ˜VK˜——š Ÿ œœœœœ˜OKš œœœœ œ˜TK˜—š Ÿ œœœœœ œ˜OKš œœœœ œ˜RK˜—KšŸœœœœœœœœ˜Ršœœœœœœœœ˜9K˜—šŸœœœ œœœœ!˜lKšœœ˜Kšœœ˜Kš œœœœœœ  ˜WKšœ"œ˜5šœœ$˜1Kšœœœ!˜;Kšœœ ˜'Kšœ˜šœ˜Kšœœœœ˜2Kšœ œ ˜1Kšœ˜—Kšœ˜—šœœ ˜7Kš˜K˜#K˜K˜0Kšœ œ˜/Kšœ˜—Kšœœ  ˜2Kšœ˜K˜—š Ÿ œœœœœœ ˜lKšœœ˜Kšœœ˜Kš œœœœ  ˜?šœœ˜šœœ˜šœ$˜,šœœœ$˜:Kšœ&œ˜2———Kšœ˜—š˜šœ˜(Kšœ œœ ˜5Kšœœ ˜5Kšœ˜—šœ˜Kšœœœœ˜1Kšœ œ ˜1Kšœ˜—Kšœ˜—šœœ˜!Kšœ™K˜K˜K˜%Kšœœ˜.Kšœ˜—Kšœœ  ˜2Kšœ˜K˜—šŸ œœœ œœœœ˜bKšœœ˜Kšœœ˜Kš œ œœœœ  ˜4Kš œœœ œœ˜Yš˜šœ ˜*Kšœ œœ˜7Kšœœ ˜'Kšœ˜—šœ˜Kšœœœœ˜0Kšœ œ ˜1Kšœ˜—Kšœ˜—šœœ˜!Kšœ™Kšœ˜K˜K˜*Kšœœ˜-Kšœ˜—Kšœœ  ˜2Kšœ˜K˜——K˜Kšœ˜—…—=,U