DIRECTORY Atom USING [MakeAtomFromRefText], FS, Imager USING [Context, ShowText], ImagerFont USING [MapText, XStringProc], Interpress USING [AddMaster, LogProc, OpenMaster, OpenMasterRep], IO, IPInterpreter USING [Apply, Call, Context, Count, DoSaveAll, Env, Frame, Identifier, IdentifierRep, Integer, Mark, Marker, MasterError, MasterWarning, NoPool, Operator, OperatorClass, OperatorClassRep, OperatorRep, Pool, PopToActiveMark, PopVector, PushIdentifier, PushNum, PushVector, Ref, Rep, StackArrayRep, topFrameSize, Unmark, Vector, VectorFromBits, VectorFromBytes, VectorFromString, ZeroVec], IPMaster USING [Block, Body, BodyRep, BYTE, GetHeader, GetSkeleton, GetToken, IntFromSequenceData, Node, NodeRep, RealFromSequenceData, SequenceType, Skeleton, SkipBytes, SkipToEndOfBody, Token], RefText USING [ReserveChars], RopeFile, Rope; IPExecImpl: CEDAR PROGRAM IMPORTS Atom, FS, IO, Imager, ImagerFont, Interpress, IPInterpreter, IPMaster, RefText, Rope, RopeFile EXPORTS Interpress, IPInterpreter ~ BEGIN OPEN IPInterpreter, IPMaster; ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; Token: TYPE ~ IPMaster.Token; Body: TYPE ~ IPMaster.Body; Block: TYPE ~ IPMaster.Block; Node: TYPE ~ IPMaster.Node; NodeRep: TYPE ~ IPMaster.NodeRep; BYTE: TYPE ~ IPMaster.BYTE; MarkRecovery: PUBLIC ERROR ~ CODE; Bug: PUBLIC ERROR ~ CODE; Run: TYPE ~ RECORD[start, len: INT]; RunList: TYPE ~ LIST OF Run; DoString: PROC [self: Ref, text: REF TEXT] ~ { string: ImagerFont.XStringProc ~ { ImagerFont.MapText[text: text, charAction: charAction] }; PushVector[self, VectorFromString[string]]; }; DoIdentifier: PROC [self: Ref, text: REF TEXT] ~ { len: NAT ~ text.length; id: Identifier ~ NEW[IdentifierRep _ [atom: NIL, rope: NIL]]; warn: BOOL _ FALSE; id.rope _ Rope.FromRefText[text]; -- before conversion to lower case FOR i: NAT IN[0..len) DO char: CHAR ~ text[i]; SELECT char FROM IN['a..'z] => NULL; IN['A..'Z] => text[i] _ char+('a-'A); -- force lower case IN['0..'9], '- => IF i=0 THEN warn _ TRUE; ENDCASE => warn _ TRUE; ENDLOOP; IF len=0 THEN warn _ TRUE; id.atom _ Atom.MakeAtomFromRefText[text]; PushIdentifier[self, id]; IF warn THEN MasterWarning[$invalidEncoding, "Invalid Identifier"]; }; DoInteger: PROC [self: Ref, text: REF TEXT] ~ { len: NAT ~ text.length; IF len<=4 THEN { val: INT ~ IPMaster.IntFromSequenceData[text]; PushNum[self, [int[val]]]; } ELSE { val: REAL ~ IPMaster.RealFromSequenceData[text]; PushNum[self, [real[val]]]; }; }; DoRational: PROC [self: Ref, text: REF TEXT] ~ { len: NAT ~ text.length; half: NAT ~ len/2; IF half<=4 THEN { n: INT ~ IPMaster.IntFromSequenceData[text: text, start: 0, len: half]; d: INT ~ IPMaster.IntFromSequenceData[text: text, start: half, len: half]; IF n IN INTEGER AND d IN INTEGER THEN PushNum[self, [rational[n: n, d: d]]] ELSE PushNum[self, [real[REAL[n]/REAL[d]]]]; } ELSE { n: REAL ~ IPMaster.RealFromSequenceData[text: text, start: 0, len: half]; d: REAL ~ IPMaster.RealFromSequenceData[text: text, start: half, len: half]; PushNum[self, [real[n/d]]]; }; IF (half+half)#len THEN MasterWarning[$invalidEncoding, IO.PutFR1["Invalid sequenceRational (length=%g)", IO.int[len]]]; }; DoInsertFile: PROC [self: Ref, text: REF TEXT] ~ { MasterWarning[$unimplemented, "Not implemented: sequenceInsertFile"]; }; Fetch16: PROC [rope: ROPE, startByte: INT] RETURNS [CARDINAL] ~ { b0: CARDINAL ~ Rope.Fetch[rope, startByte]-'\000; b1: CARDINAL ~ Rope.Fetch[rope, startByte+1]-'\000; RETURN [b0*256+b1]; }; OpenFileFromStream: PROC [stream: IO.STREAM] RETURNS [FS.OpenFile] ~ { openFile: FS.OpenFile _ FS.nullOpenFile; name: ROPE _ NIL; ok: BOOL _ TRUE; openFile _ FS.OpenFileFromStream[stream ! FS.Error, IO.Error => {ok _ FALSE; CONTINUE}]; name _ FS.GetName[openFile ! FS.Error => {ok _ FALSE; CONTINUE}].fullFName; IF ok THEN openFile _ FS.Open[ name: name, wantedCreatedTime: FS.GetInfo[openFile].created, remoteCheck: FALSE ! FS.Error => {ok _ FALSE; CONTINUE} ]; RETURN [IF ok THEN openFile ELSE FS.nullOpenFile] }; smallish: INT _ 30000; maxChunkSize: INT ~ LAST[NAT]-SIZE[TEXT[0]]*2-4; maxRopeStreams: NAT ~ 4; nRopeStreams: NAT _ 3; ropeBuffers: NAT _ 1; pagesPerFileBuffer: NAT _ 10; numberOfFilebuffers: NAT _ 2; ropeFileStreamOptions: FS.StreamOptions ~ [ tiogaRead: FALSE, commitAndReopenTransOnFlush: FALSE, truncatePagesOnClose: FALSE, finishTransOnClose: FALSE, closeFSOpenFileOnClose: FALSE ]; RopeFromRuns: PROC [stream: IO.STREAM, runs: LIST OF Run, sequenceLength: INT] RETURNS [rope: ROPE _ NIL] ~ { size: INT _ 0; openFile: FS.OpenFile ~ IF sequenceLength > smallish THEN OpenFileFromStream[stream] ELSE FS.nullOpenFile; IF openFile # FS.nullOpenFile THEN { ropes: ARRAY [0..maxRopeStreams) OF ROPE _ ALL[NIL]; FOR i: NAT IN [0..nRopeStreams) DO ropeFile: ROPE ~ RopeFile.FromStream[stream: FS.StreamFromOpenFile[openFile: openFile, streamOptions: ropeFileStreamOptions, streamBufferParms: [vmPagesPerBuffer: pagesPerFileBuffer, nBuffers: numberOfFilebuffers]], buffers: ropeBuffers]; t: ROPE _ NIL; size _ 0; FOR r: LIST OF Run _ runs, r.rest UNTIL r = NIL DO run: Run ~ r.first; t _ Rope.Concat[t, Rope.Substr[ropeFile, run.start, run.len]]; size _ size + run.len; ENDLOOP; ropes[i] _ t; ENDLOOP; FOR i: NAT IN [0..nRopeStreams) DO start: INT ~ size*i/nRopeStreams; end: INT ~ size*(i+1)/nRopeStreams; rope _ Rope.Concat[rope, Rope.Substr[ropes[i], start, end-start]]; ENDLOOP; } ELSE { saveIndex: INT ~ IO.GetIndex[stream]; FOR r: LIST OF Run _ runs, r.rest UNTIL r = NIL DO run: Run _ r.first; UNTIL run.len = 0 DO chunkSize: NAT ~ MIN[run.len, maxChunkSize]; text: Rope.Text ~ Rope.NewText[chunkSize]; zero: [0..0]; IO.SetIndex[stream, run.start]; TRUSTED {zero _ IO.GetBlock[stream, LOOPHOLE[text], 0, chunkSize]-chunkSize}; rope _ Rope.Concat[rope, text]; size _ size + chunkSize; run.start _ run.start + chunkSize; run.len _ run.len - chunkSize; ENDLOOP; ENDLOOP; IO.SetIndex[stream, saveIndex]; }; IF Rope.Size[rope] # sequenceLength THEN ERROR; IF size # sequenceLength THEN ERROR; }; ExecuteToEndOfBody: PROC [self: Ref] ~ { stream: STREAM ~ self.stream; sequenceData: {nil, text, runs, skip} _ nil; sequenceType: SequenceType _ nil; sequenceLength: INT _ 0; sequenceRuns: INT _ 0; text: REF TEXT _ NIL; buffer: REF TEXT ~ self.buffer; runsHead, runsTail: LIST OF Run _ NIL; BeginSequence: PROC [seq: SequenceType] ~ { SELECT sequenceType _ seq FROM sequenceString, sequenceIdentifier, sequenceInsertFile, sequenceComment, sequenceInteger, sequenceRational, sequenceReal => sequenceData _ text; sequenceLargeVector, sequencePackedPixelVector, sequenceCompressedPixelVector, sequenceAdaptivePixelVector => sequenceData _ runs; ENDCASE => sequenceData _ skip; SELECT sequenceData FROM text => { text _ buffer; text.length _ 0 }; runs => { runsHead _ runsTail _ NIL }; ENDCASE; sequenceLength _ 0; }; ExtendSequence: PROC [length: INT] ~ { SELECT sequenceData FROM nil => { MasterWarning[$invalidEncoding, "Misplaced sequenceContinued"]; SkipBytes[stream, length]; }; text => { len: NAT ~ length; nBytesRead: NAT _ 0; IF (text.maxLength-text.length) { prevTail: LIST OF Run ~ runsTail; runsTail _ LIST[[start: IO.GetIndex[stream], len: length]]; IF prevTail=NIL THEN runsHead _ runsTail ELSE prevTail.rest _ runsTail; SkipBytes[stream, length]; }; skip => SkipBytes[stream, length]; ENDCASE => ERROR; sequenceRuns _ sequenceRuns+1; sequenceLength _ sequenceLength+length; }; FinishSequence: PROC ~ { SELECT sequenceType FROM sequenceString => DoString[self, text]; sequenceIdentifier => DoIdentifier[self, text]; sequenceInteger => DoInteger[self, text]; sequenceRational => DoRational[self, text]; sequenceInsertFile => DoInsertFile[self, text]; sequenceComment => NULL; sequenceLargeVector => { rope: ROPE ~ RopeFromRuns[self.stream, runsHead, sequenceLength]; b: NAT ~ Rope.Fetch[rope, 0]-'\000; vector: Vector ~ VectorFromBytes[bytes: Rope.Substr[rope, 1], bytesPerElement: b, signed: TRUE]; PushVector[self, vector]; }; sequencePackedPixelVector => { rope: ROPE ~ RopeFromRuns[self.stream, runsHead, sequenceLength]; bitsPerSample: [1..1] ~ Fetch16[rope, 0]; -- only one bit per sample supported here scanLength: NAT ~ Fetch16[rope, 2]; dataBitsPerLine: NAT ~ bitsPerSample*scanLength; padBitsPerLine: NAT ~ NAT[32 - (dataBitsPerLine MOD 32)] MOD 32; vector: Vector ~ VectorFromBits[bytes: Rope.Substr[rope, 4], dataBitsPerLine: dataBitsPerLine, padBitsPerLine: padBitsPerLine]; PushVector[self, vector]; }; sequenceCompressedPixelVector => MasterWarning[$unimplemented, "Not implemented: sequenceCompressedPixelVector"]; sequenceAdaptivePixelVector => MasterWarning[$unimplemented, "Not implemented: sequenceAdaptivePixelVector"]; sequenceContinued => MasterWarning[$invalidEncoding, "Misplaced sequenceContinued"]; ENDCASE => MasterWarning[$invalidEncoding, IO.PutFR1["Invalid sequence type (%g)", IO.int[ORD[sequenceType]]]]; sequenceData _ nil; sequenceType _ nil; }; DO -- for each Token token: Token ~ GetToken[stream: self.stream, flushComments: FALSE]; IF token.seq=sequenceContinued THEN { ExtendSequence[token.len]; LOOP }; self.context.token _ token; IF sequenceType=sequenceString AND self.showVec.font#NIL THEN { done: BOOL _ TRUE; SELECT token.op FROM show => Imager.ShowText[context: self.imager, text: text]; showandxrel => Imager.ShowText[context: self.imager, text: text, xrel: TRUE]; ENDCASE => done _ FALSE; IF done THEN { sequenceData _ nil; LOOP }; }; IF sequenceData#nil THEN FinishSequence[]; IF token.op=endBody THEN EXIT; SELECT token.type FROM op => Apply[self, token.op]; num => PushNum[self, [int[token.num]]]; seq => { BeginSequence[token.seq]; ExtendSequence[token.len] }; ENDCASE => ERROR; ENDLOOP; }; BeginBody: PROC [self: Ref] RETURNS [INT] ~ { token: Token ~ IPMaster.GetToken[self.stream]; self.context.token _ token; IF NOT token.op=beginBody THEN MasterError[$missingBody, "Missing body"]; RETURN[token.index]; }; SkipInlineBody: PUBLIC PROC [self: Ref] ~ { index: INT ~ BeginBody[self]; IPMaster.SkipToEndOfBody[self.stream]; }; GetInlineBody: PUBLIC PROC [self: Ref] RETURNS [Body] ~ { start, stop: INT _ 0; start _ BeginBody[self]; IPMaster.SkipToEndOfBody[self.stream]; stop _ IO.GetIndex[self.stream]; RETURN[NEW[IPMaster.BodyRep _ [index: start, length: stop-start]]]; }; ExecuteInlineBody: PROC [self: Ref] ~ { index: INT ~ BeginBody[self]; DO error: BOOL _ FALSE; ExecuteToEndOfBody[self ! MarkRecovery => { error _ TRUE; CONTINUE }]; IF error THEN { -- do mark recovery marker: Marker ~ PopToActiveMark[self]; IF marker=self.context.marker THEN { IO.SetIndex[self.stream, self.context.token.index]; DO token: Token ~ IPMaster.GetToken[self.stream]; SELECT token.op FROM endBody => ERROR MarkRecovery; -- end of body beginBody => IPMaster.SkipToEndOfBody[self.stream]; -- skip body literal unmark0 => { IO.SetIndex[self.stream, token.index]; EXIT }; -- found UNMARK0 ENDCASE; IF token.type=seq THEN IPMaster.SkipBytes[self.stream, token.len]; ENDLOOP; } ELSE ERROR MarkRecovery; -- not this context's marker } ELSE EXIT; -- normal completion ENDLOOP; }; CallInlineBody: PUBLIC PROC [self: Ref, frame: Vector, pool: Pool, env: Vector] ~ { action: PROC ~ { ExecuteInlineBody[self] }; Call[self: self, action: action, frame: frame, pool: pool, env: env]; }; CallBody: PROC [self: Ref, body: Body, frame: Vector, pool: Pool, env: Vector] ~ { stream: STREAM ~ self.stream; next: INT ~ IO.GetIndex[stream]; IO.SetIndex[stream, body.index]; CallInlineBody[self: self, frame: frame, pool: pool, env: env ! UNWIND => IO.SetIndex[stream, next]]; IO.SetIndex[stream, next]; }; DoWithMarkProtection: PUBLIC PROC [self: Ref, action: PROC] ~ { error: BOOL _ FALSE; inner: PROC ~ { Mark[self, 0]; action[]; Unmark[self, 0] }; inner[! MarkRecovery => { error _ TRUE; CONTINUE}]; IF error THEN { -- do mark recovery marker: Marker ~ PopToActiveMark[self]; IF marker=self.context.marker THEN Unmark[self, 0] ELSE ERROR MarkRecovery; }; }; Do: PUBLIC PROC [self: Ref, op: Operator] ~ { op.class.do[op, self] }; composedClass: OperatorClass ~ NEW[OperatorClassRep _ [ type: $Composed, do: ComposedDo]]; ComposedData: TYPE ~ REF ComposedDataRep; ComposedDataRep: TYPE ~ RECORD[ frame: Vector, -- initial frame pool: Pool, -- shared pool env: Vector, -- environment body: Body -- body of the operator ]; ComposedDo: PROC [op: Operator, state: Ref] ~ { data: ComposedData ~ NARROW[op.data]; CallBody[self: state, body: data.body, frame: data.frame, pool: data.pool, env: data.env]; }; MakeCO: PUBLIC PROC [frame: Vector, pool: Pool, env: Vector, body: Body] RETURNS [Operator] ~ { data: ComposedData ~ NEW[ComposedDataRep _ [ frame: frame, pool: pool, env: env, body: body]]; RETURN[NEW[OperatorRep _ [class: composedClass, data: data]]]; }; compiledImageClass: OperatorClass ~ NEW[OperatorClassRep _ [ type: $CompiledImage, do: CompiledImageDo]]; CompiledImageData: TYPE ~ REF CompiledImageDataRep; CompiledImageDataRep: TYPE ~ RECORD[frame: Vector, env: Vector, body: Body]; CompiledImageDo: PROC [op: Operator, state: Ref] ~ { data: CompiledImageData ~ NARROW[op.data]; CallBody[self: state, body: data.body, frame: data.frame, pool: NoPool[], env: data.env]; }; MakeCompiledImage: PUBLIC PROC [frame: Vector, env: Vector, body: Body] RETURNS [Operator] ~ { data: CompiledImageData ~ NEW[CompiledImageDataRep _ [ frame: frame, env: env, body: body]]; RETURN[NEW[OperatorRep _ [class: compiledImageClass, data: data]]]; }; CallPreamble: PROC [self: Ref, node: Node, frame: Vector, env: Vector] ~ { WITH node SELECT FROM node: REF NodeRep.body => { preamble: PROC ~ { Mark[self, 0]; ExecuteInlineBody[self]; IF Count[self]<1 THEN PushVector[self, Env[self]]; IF Count[self]<2 THEN PushVector[self, Frame[self]]; Unmark[self, 2]; }; IO.SetIndex[self.stream, node.body.index]; Call[self: self, action: preamble, frame: frame, pool: NoPool[], env: env]; }; ENDCASE => ERROR; }; CallNode: PROC [self: Ref, node: Node, frame: Vector, env: Vector] ~ { WITH node SELECT FROM node: REF NodeRep.body => { body: Body ~ node.body; IO.SetIndex[self.stream, body.index]; CallInlineBody[self: self, frame: frame, pool: NoPool[], env: env]; }; ENDCASE => ERROR; }; emptyVec: Vector ~ ZeroVec[0]; topFrame: Vector ~ ZeroVec[topFrameSize]; topEnv: Vector ~ emptyVec; -- empty vector, for now OpenMaster: TYPE ~ Interpress.OpenMaster; OpenMasterRep: TYPE ~ Interpress.OpenMasterRep; OpenMasterImplRep: PUBLIC TYPE ~ IPInterpreter.Rep; -- exported to Interpress LogProc: TYPE ~ Interpress.LogProc; DoTopAction: PROC [master: OpenMaster, action: PROC] ~ { self: Ref ~ master.impl; protect: PROC ~ { DoWithMarkProtection[self, action] }; call: PROC ~ { Call[self, protect, emptyVec, NoPool[], emptyVec] }; save: PROC ~ { IF self.imager=NIL THEN call ELSE DoSaveAll[self, call] }; Interpress.AddMaster[master, save]; }; DoPreamble: PROC [master: OpenMaster] ~ { self: Ref ~ master.impl; block: Block ~ master.skeleton.topBlock; action: PROC ~ { CallPreamble[self: self, node: block.preamble, frame: topFrame, env: topEnv]; self.topFrame _ PopVector[self]; self.topEnv _ PopVector[self]; }; DoTopAction[master, action]; }; defaultMaxStackLength: Integer ~ 1000; Open: PUBLIC PROC [fileName: ROPE, logProc: LogProc, logData: REF _ NIL] RETURNS [OpenMaster] ~ { stream: STREAM ~ FS.StreamOpen[fileName]; RETURN [FromStream[stream, logProc, logData]]; }; FromStream: PUBLIC PROC [stream: STREAM, logProc: LogProc, logData: REF _ NIL] RETURNS [OpenMaster] ~ { restOfHeader: ROPE ~ IPMaster.GetHeader[stream, "Interpress/Xerox/"]; skeleton: IPMaster.Skeleton ~ IPMaster.GetSkeleton[stream]; self: Ref ~ NEW[Rep _ [stream: stream]]; master: OpenMaster ~ NEW[OpenMasterRep _ [ pages: skeleton.topBlock.size, skeleton: skeleton, logProc: logProc, logData: logData, impl: self]]; self.buffer _ NEW[TEXT[200]]; self.stackArray _ NEW[StackArrayRep _ ALL[[zero[]]]]; self.stackCountMax _ defaultMaxStackLength; DoPreamble[master]; RETURN[master]; }; DoPage: PUBLIC PROC [master: OpenMaster, page: INT, context: Imager.Context] ~ { IF page IN[1..master.pages] THEN { block: Block ~ master.skeleton.topBlock; node: Node ~ block[page-1]; self: Ref ~ master.impl; action: PROC ~ { CallNode[self: self, node: node, frame: self.topFrame, env: self.topEnv] }; self.imager _ context; DoTopAction[master, action]; self.imager _ NIL; }; }; END. hIPExecImpl.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. Doug Wyatt, July 8, 1985 4:58:44 pm PDT Michael Plass, February 17, 1986 9:03:24 am PST Can't just return this openFile, because it can get closed unpredictably. This is a performance hack to make the rope out out several rope-files, each on a separate stream. This is so switching between several regions of the file can be done without excessive thrashing of the disk arm. Ideally, we would have more information about the typical access pattern to make a better decision here. node: REF NodeRep.block => { MasterError[$unimplemented, "Preamble cannot be a block."]; ERROR Error; }; node: REF NodeRep.block => { block: Block ~ node.block; pageFrame, pageEnv: Vector; CallPreamble[self, block.preamble, frame, env]; pageFrame _ PopVector[self]; pageEnv _ PopVector[self]; FOR i: NAT IN[0..block.size) DO CallNode[self, block[i], pageFrame, pageEnv]; ENDLOOP; }; self.imager _ imager; -- dummy imager context ObtainExternalInstructions: PROC [self: Ref] RETURNS [Vector] ~ { RETURN[VectorFromAny[GetP[Env[self], $externalInstructions]]]; }; AddInstructionDefaults: PROC [self: Ref, computedInstructions, externalInstructions: Vector] RETURNS [Vector] ~ { RETURN[computedInstructions] }; ExecuteInstructionsBody: PROC [self: Ref, externalInstructions: Vector] RETURNS [Vector] ~ { body: Index ~ self.skeleton.preamble.instructions; IF body=nullIndex THEN RETURN[externalInstructions] ELSE { reader: Reader ~ NARROW[self.reader]; PushVector[self, externalInstructions]; reader.SetIndex[body]; DoBody[self, NoPool[], initialTopFrame, $saveAll]; WHILE Count[self]>1 DO Apply[self, $mergeprop] ENDLOOP; RETURN[PopVector[self]]; }; }; ComputePrintingInstructions: PROC [self: Ref] ~ { externalInstructions: Vector ~ ObtainExternalInstructions[self]; instructions: Vector _ emptyVector; Mark[self, 0]; instructions _ ExecuteInstructionsBody[self, externalInstructions ! Error => CONTINUE]; Unmark0[self]; instructions _ AddInstructionDefaults[self, instructions, externalInstructions]; self.media _ GetP[instructions, $media]; self.copySelect _ GetP[instructions, $copySelect]; self.pageSelect _ GetP[instructions, $pageSelect]; self.onSimplex _ GetP[instructions, $onSimplex]; self.mediaSelect _ GetP[instructions, $mediaSelect]; self.copyName _ GetP[instructions, $copyName]; self.instructions _ instructions; }; Κ˜codešœ™Kšœ Οmœ7™BKšœ'™'K™/—K˜šΟk ˜ Kšœžœ˜!Kšžœ˜Kšœžœ˜!Kšœ žœ˜(Kšœ žœ1˜AKšžœ˜Kšœžœώ˜‘Kšœ žœžœ™˜ΓKšœžœ˜K˜ Kšœ˜—K˜KšΠbl œžœž˜KšžœžœžœR˜fKšžœ˜!Kšœžœžœ˜%K˜Kšžœžœžœ˜Kšžœžœžœžœ˜K˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœ žœ˜!Kšžœžœ žœ˜K˜Kšœžœžœžœ˜"Kšœžœžœžœ˜K˜Kšœžœžœ žœ˜$Kšœ žœžœžœ˜K˜šΟnœžœžœžœ˜.K˜\Kšœ+˜+K˜K˜—š  œžœžœžœ˜2Kšœžœ˜Kšœžœžœžœ˜=Kšœžœžœ˜Kšœ"Οc"˜Dšžœžœžœ ž˜Kšœžœ ˜šžœž˜Kšžœ žœ˜Kšžœ$‘˜9Kšžœžœžœžœ˜*Kšžœ žœ˜—Kšžœ˜—Kšžœžœžœ˜K˜)K˜Kšžœžœ7˜CK˜K˜—š  œžœžœžœ˜/Kšœžœ˜šžœžœ˜Kšœžœ&˜.Kšœ˜K˜—šžœ˜Kšœžœ'˜0Kšœ˜K˜—K˜K˜—š  œžœžœžœ˜0Kšœžœ˜Kšœžœ ˜šžœ žœ˜KšœžœA˜GKšœžœD˜JKšžœžœžœžœžœžœžœ&˜KKšžœžœžœ˜,K˜—šžœ˜KšœžœB˜IKšœžœE˜LKšœ˜K˜—Kšžœžœ"žœ0žœ ˜yK˜K˜—š  œžœžœžœ˜2KšœE˜EK˜K˜—š  œžœžœ žœžœžœ˜AKšœžœ%˜1Kšœžœ'˜3Kšžœ ˜K˜K˜—š  œžœ žœžœžœžœ˜FKšœ žœ žœ˜(Kšœžœžœ˜Kšœžœžœ˜Kš œ žœžœžœ žœ˜XK•StartOfExpansion†[name: ROPE, lock: FS.Lock _ read, wantedCreatedTime: GMT _ OPAQUE#17777777777B, remoteCheck: BOOL _ TRUE, wDir: ROPE _ NIL]šœI™IKš œžœžœžœžœ ˜Kšžœžœ žœ˜Kšœ ˜ Kšœžœ˜0Kšœ ž˜Kšœžœžœžœ˜$Kšœ˜—Kš žœžœžœ žœžœ˜1Kšœ˜K˜—Kšœ žœ ˜Kš œžœžœžœžœžœ ˜0Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜šœžœ˜+Kšœ žœ˜Kšœžœ˜#Kšœžœ˜Kšœžœ˜Kšœž˜Kšœ˜—š  œžœ žœžœžœžœžœžœžœžœ˜mKšœžœ˜Kš œ žœ žœžœžœ˜jšžœ žœžœ˜$K™ΏKš œžœžœžœžœžœ˜4šžœžœžœž˜"K–¨[openFile: FS.OpenFile, accessRights: FS.Lock _ read, initialPosition: FS.InitialPosition _ start, streamOptions: FS.StreamOptions _ (5)[TRUE, TRUE, TRUE, TRUE, TRUE], streamBufferParms: FS.StreamBufferParms _ [vmPagesPerBuffer: 8, nBuffers: 2], extendFileProc: FS.ExtendFileProc]šœ žœΰ˜ξKšœžœžœ˜Kšœ ˜ š žœžœžœžœžœž˜2Kšœ˜Kšœ>˜>Kšœ˜Kšžœ˜—Kšœ ˜ Kšžœ˜—šžœžœžœž˜"Kšœžœ˜!Kšœžœ˜#KšœB˜BKšžœ˜—Kšœ˜—šžœ˜Kšœ žœžœ˜%š žœžœžœžœžœž˜2Kšœ˜šžœ ž˜Kšœ žœžœ˜,Kšœ*˜*K˜ Kšžœ˜Jšžœ žœžœ!˜MKšœ˜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šœ?˜?K˜K˜—˜ Kšœžœ ˜Kšœ žœ˜Kšžœ"žœ(˜PKšœ žœJ˜YKšžœžœžœžœ˜4K˜—˜ Kšœ žœžœ˜!Kšœ žœ žœ!˜;Kšžœ žœžœžœ˜GKšœ˜K˜—K˜"Kšžœžœ˜—Kšœ˜Kšœ'˜'K˜—š œžœ˜šžœž˜Kšœ'˜'Kšœ/˜/Kšœ)˜)Kšœ+˜+Kšœ/˜/Kšœžœ˜šœ˜Kšœžœ7˜AKšœžœ˜#KšœZžœ˜`Kšœ˜K˜—šœ˜Kšœžœ7˜AKšœ*‘)˜SKšœ žœ˜#Kšœžœ˜0Kš œžœžœžœžœ˜@Kšœ˜Kšœ˜Kšœ˜—Kšœr˜rKšœn˜nKšœU˜UKšžœ%žœ&žœžœ˜p—Kšœ˜Kšœ˜K˜—šžœ‘˜Kšœ<žœ˜CKšžœžœžœ˜HK˜šžœžœžœžœ˜?Kšœžœžœ˜šžœ ž˜Kšœ:˜:KšœGžœ˜MKšžœ žœ˜—Kšžœžœžœ˜*K˜—Kšžœžœ˜*Kšžœžœžœ˜šžœ ž˜Kšœ˜Kšœ'˜'Kšœ?˜?Kšžœžœ˜—Kšžœ˜—K˜K˜—K˜š  œžœ žœžœ˜-K˜.K˜Kšžœžœžœ+˜IKšžœ˜K˜K˜—š œžœžœ˜+Kšœžœ˜K˜&K˜K˜—š  œžœžœ žœ ˜9Kšœ žœ˜Kšœ˜Kšœ&˜&Kšœžœ˜ Kšžœžœ9˜CK˜K˜—š œžœ˜'Kšœžœ˜šžœžœžœ˜Kšœ4žœžœ˜Fšžœžœ‘˜#Kšœ'˜'šžœžœ˜$Kšžœ1˜3šžœ/˜1šžœ ž˜Kšœ žœ‘˜-Kšœ4‘˜HKšœ žœ%žœ‘˜LKšžœ˜—Kšžœžœ,˜BKšžœ˜—K˜—Kšžœžœ‘˜5K˜—Kšžœžœ‘˜Kšžœ˜—K˜K˜—K˜š œžœžœ8˜SKšœžœ˜+KšœE˜EK˜K˜—š œžœD˜RKšœžœ˜Kšœžœžœ˜ Kšžœ˜ šœ=˜=Kšœžœžœ˜'—Kšžœ˜K˜K˜—K˜š œžœžœžœ˜?Kšœžœžœ˜Kšœžœ0˜;Kšœ"žœžœ˜3šžœžœ‘˜#Kšœ'˜'Kšžœžœ˜2Kšžœžœ˜K˜—K˜K˜—K˜Kš œžœžœ7˜FK˜šœžœ˜7Kšœ"˜"K˜—Kšœžœžœ˜)šœžœžœ˜Kšœ‘˜Kšœ ‘˜Kšœ ‘˜Kšœ ‘˜"K˜K˜—š  œžœ˜/Kšœžœ ˜%KšœZ˜ZK˜K˜—š œžœžœ6žœ˜`šœžœ˜,Kšœ1˜1—Kšžœžœ4˜>K˜K˜—K˜šœ$žœ˜K™K™—š œžœ@™\Kšžœ ™Kšžœ™K™K™—š œžœ+žœ ™\K™2Kšžœžœžœ™3šžœ™Kšœžœ™%Kšœ'™'Kšœ™K™2Kšžœžœžœ™7Kšžœ™K™—K™K™—š œžœ™1Kšœ@™@Kšœ#™#K™K™KšœMžœ™WK™K™KšœP™PK™K™(K™2K™2K™0K™4K™.Kšœ!™!K™K™—K˜—…—@V_Σ