DIRECTORY Basics USING [bitsPerWord, bytesPerWord, HighHalf, LongMult, LongNumber, LowHalf, UnsafeBlock], CountedVM USING [Allocate, Handle], FS USING [StreamOpen], IO USING [Close, GetIndex, SetIndex, SetLength, STREAM, UnsafeGetBlock, UnsafePutBlock], PDFileFormat USING [Command, ControlCom, DeviceCode, Herald, MaskRectangle, MaskRunGroupRef, MaskSamples, MaskSamplesRef, MaskTrapezoid, opaqueFlag, Run, SampleArray, SetColorTile, StartImage, Tile, Toner, transparentFlag], PDFileWriter USING [CaptureRunProc, CaptureScanLineProc, DeliverRunGroupProc, DeliverSampleArrayProc, TFlag, TonerSet], PrincOpsUtils USING [LongCopy], Rope USING [ROPE]; PDFileWriterImpl: CEDAR PROGRAM IMPORTS Basics, CountedVM, FS, IO, PrincOpsUtils EXPORTS PDFileWriter = BEGIN BlockTransfer: UNSAFE PROC [source: LONG POINTER, count: CARDINAL, dest: LONG POINTER] ~ UNCHECKED INLINE {PrincOpsUtils.LongCopy[from: source, nwords: count, to: dest]}; LongBlockTransfer: UNSAFE PROC [source: LONG POINTER, count: INT, dest: LONG POINTER] ~ UNCHECKED { WHILE count > LAST[CARDINAL] DO BlockTransfer[source: source, count: LAST[CARDINAL], dest: dest]; source _ source + LAST[CARDINAL]; dest _ dest + LAST[CARDINAL]; count _ count - LAST[CARDINAL]; ENDLOOP; IF count > 0 THEN BlockTransfer[source: source, count: count, dest: dest]; }; bytesPerWord: CARDINAL = Basics.bytesPerWord; bitsPerWord: CARDINAL = Basics.bitsPerWord; ROPE: TYPE = Rope.ROPE; LoadReference: TYPE = NAT; DeliverRunGroupProc: TYPE = PDFileWriter.DeliverRunGroupProc; CaptureRunProc: TYPE = PDFileWriter.CaptureRunProc; DeliverSampleArrayProc: TYPE = PDFileWriter.DeliverSampleArrayProc; CaptureScanLineProc: TYPE = PDFileWriter.CaptureScanLineProc; TFlag: TYPE = PDFileWriter.TFlag; TonerSet: TYPE = PDFileWriter.TonerSet; Toner: TYPE = PDFileFormat.Toner; Bands: TYPE = REF BandsRec; BandsRec: TYPE = RECORD [ bands: SEQUENCE maxBands: NAT OF Band ]; Band: TYPE = RECORD [ colorId: INT, bandBuffer: BandBuffer ]; bandBufferSize: NAT = 200; BandBuffer: TYPE = REF BandBufferRec; BandBufferRec: TYPE = RECORD [ length: NAT _ 0, overflowIndices: LIST OF INT _ NIL, word: ARRAY [0..bandBufferSize) OF WORD ]; ColorDescriptor: TYPE = RECORD [ colorId: INT _ 0, -- bumped whenever the color changes. enabled: BOOLEAN _ TRUE, length: NAT _ 1, command: PDFileFormat.Command.control _ [control[setColorInk]], setColorTile: PDFileFormat.SetColorTile ]; maxLoadItems: CARDINAL _ 2000; LoadDescription: TYPE = REF LoadDescriptionRep; LoadDescriptionRep: TYPE = RECORD [ storageRef: REF, -- to protect against garbage collection pointer: LONG POINTER, words: INT, -- at least as big as loadSizeInWords count: NAT _ 0, entries: SEQUENCE maxCount: NAT OF LoadEntryDescription ]; LoadEntryType: TYPE = {none, samples, runGroup, tile}; LoadEntryDescription: TYPE = RECORD [ loadEntryType: LoadEntryType, offsetHighBits: [0..256), offsetLowBits: CARDINAL, pageOfMostRecentUse: CARDINAL, numberOfPagesUsedIn: CARDINAL ]; PDState: PUBLIC TYPE = REF PDStateRec; PDStateRec: PUBLIC TYPE = RECORD [ fileName: ROPE, herald: PDFileFormat.Herald, colorDescriptor: ARRAY Toner OF ColorDescriptor, stream: IO.STREAM, toners: TonerSet _ ALL[FALSE], firstToner, lastToner: Toner _ black, feed: BOOLEAN _ TRUE, strip: BOOLEAN _ TRUE, bands: ARRAY Toner OF Bands, selectedBands: Bands _ NIL, selectedBandNum: NAT _ 0, sMinPage: CARDINAL, sMaxPage: CARDINAL, fMinPage: CARDINAL, fMaxPage: CARDINAL, currentImage: CARDINAL _ 1, currentLoadLocation: INT _ 0, loadWrittenLength: INT _ 0, loadSizeInWords: INT, leftOverMode: BOOLEAN, priorityImportant: BOOLEAN, loadDescription: LoadDescription, overflowStream: IO.STREAM _ NIL ]; Create: PUBLIC PROC [fileName: ROPE, deviceCode: PDFileFormat.DeviceCode, sResolution, fResolution, imageSSize, imageFSize: CARDINAL, bandSSize: CARDINAL, copies: CARDINAL, leftOverMode: BOOLEAN, maxLoadWords: INT] RETURNS [pdState: PDState] = { nBands: NAT; pdState _ NEW [PDStateRec]; pdState.fileName _ fileName; pdState.herald.deviceCode _ deviceCode; pdState.herald.sResolution _ sResolution; pdState.herald.fResolution _ fResolution; nBands _ (imageSSize+bandSSize-1)/bandSSize; pdState.herald.imageSSize _ pdState.sMinPage _ nBands*bandSSize; pdState.herald.imageFSize _ pdState.fMinPage _ imageFSize; pdState.herald.bandSSize _ bandSSize; pdState.herald.maxLoadWord _ 0; pdState.herald.copies _ copies; pdState.loadSizeInWords _ maxLoadWords; pdState.leftOverMode _ leftOverMode; pdState.priorityImportant _ FALSE; pdState.sMaxPage _ pdState.fMaxPage _ 0; pdState.toners _ ALL[FALSE]; pdState.toners[black] _ TRUE; pdState.feed _ pdState.strip _ TRUE; pdState.bands[black] _ NEW [BandsRec[nBands]]; pdState.stream _ FS.StreamOpen[fileName, $create]; WriteHerald[pdState]; }; SetPriorityImportant: PUBLIC PROC [pdState: PDState, priorityImportant: BOOLEAN] RETURNS [previousValue: BOOLEAN] = { previousValue _ pdState.priorityImportant; pdState.priorityImportant _ priorityImportant; }; StartImage: PUBLIC PROC [pdState: PDState, toners: TonerSet, feed, strip: BOOLEAN _ TRUE] ~ { pdState.feed _ feed; pdState.strip _ strip; pdState.toners _ toners; pdState.firstToner _ Toner.LAST; pdState.lastToner _ Toner.FIRST; FOR t: Toner IN [Toner.FIRST..Toner.LAST] DO IF toners[t] THEN { IF pdState.bands[t] = NIL THEN { pdState.bands[t] _ NEW [BandsRec[pdState.bands[black].maxBands]]; }; IF pdState.firstToner = Toner.LAST THEN pdState.firstToner _ t; pdState.lastToner _ t; }; pdState.colorDescriptor[t] _ [ colorId: 0, length: 1, command: [control[setColorInk]], setColorTile: [addr: 0], enabled: toners[t] ]; ENDLOOP; }; SetColorInk: PUBLIC PROC [pdState: PDState, toner: Toner] = { IF NOT pdState.toners[toner] THEN ERROR; pdState.colorDescriptor[toner].colorId _ pdState.colorDescriptor[toner].colorId + 1; pdState.colorDescriptor[toner].length _ SIZE[PDFileFormat.Command]; pdState.colorDescriptor[toner].command _ [control[setColorInk]]; pdState.colorDescriptor[toner].enabled _ TRUE; }; SetColorClear: PUBLIC PROC [pdState: PDState, toner: Toner] = { IF NOT pdState.toners[toner] THEN ERROR; pdState.colorDescriptor[toner].colorId _ pdState.colorDescriptor[toner].colorId + 1; pdState.colorDescriptor[toner].length _ SIZE[PDFileFormat.Command]; pdState.colorDescriptor[toner].command _ [control[setColorClear]]; pdState.colorDescriptor[toner].enabled _ TRUE; }; SetColorOff: PUBLIC PROC [pdState: PDState, toner: Toner] = { pdState.colorDescriptor[toner].enabled _ FALSE; }; SetColorTile: PUBLIC PROC [pdState: PDState, toner: Toner, tileRef: LoadReference, tFlag: TFlag] = TRUSTED { loadEntry: LoadEntryDescription _ pdState.loadDescription[tileRef]; reference: Basics.LongNumber _ [num[lowbits: loadEntry.offsetLowBits, highbits: loadEntry.offsetHighBits]]; colorId: INT _ pdState.colorDescriptor[toner].colorId + 1; tBit: [0..1] = IF tFlag = opaque THEN PDFileFormat.opaqueFlag ELSE PDFileFormat.transparentFlag; IF loadEntry.loadEntryType # tile THEN ERROR; IF NOT pdState.toners[toner] THEN ERROR; pdState.colorDescriptor[toner] _ [ colorId: colorId, length: SIZE[PDFileFormat.Command] + SIZE[PDFileFormat.SetColorTile], command: [control[setColorTile, tBit]], setColorTile: [addr: reference.lc], enabled: TRUE ]; }; DoForEachToner: PUBLIC PROC [pdState: PDState, proc: PROC[Toner]] = { FOR toner: Toner IN [pdState.firstToner..pdState.lastToner] DO IF pdState.toners[toner] THEN proc[toner]; ENDLOOP; }; GetBounds: PUBLIC PROC [pdState: PDState] RETURNS [sMax, fMax: CARDINAL] = { sMax _ pdState.herald.imageSSize; fMax _ pdState.herald.imageFSize; }; MaskRectangle: PUBLIC PROC [pdState: PDState, sMin, fMin: CARDINAL, sSize, fSize: CARDINAL] = TRUSTED { sEnd: CARDINAL _ IF pdState.leftOverMode THEN sMin+1 ELSE sMin + sSize; bandSSize: CARDINAL _ pdState.herald.bandSSize; command: PDFileFormat.Command _ [imaging[maskRectangle, 0]]; maskArgs: PDFileFormat.MaskRectangle _ [sMin:sMin, sSize:sSize, fMin:fMin, fSize:fSize]; ExtendBB[pdState, sMin, fMin]; ExtendBB[pdState, sMin + sSize, fMin + fSize]; FOR toner: Toner IN [pdState.firstToner..pdState.lastToner] DO IF pdState.colorDescriptor[toner].enabled THEN { nextBandStart: CARDINAL _ sMin + (bandSSize - (sMin MOD bandSSize)); SelectBand[pdState, sMin, toner]; EnterBandData[pdState, @command, SIZE[PDFileFormat.Command]]; EnterBandData[pdState, @maskArgs, SIZE[PDFileFormat.MaskRectangle]]; FOR s: CARDINAL _ nextBandStart, s + bandSSize WHILE s 0 THEN { IF NOT buffer.run[nRuns - 1].lastRun THEN { buffer.sSize _ buffer.sSize + 1; buffer.run[nRuns - 1].lastRun _ TRUE; }; SelectBand[pdState, buffer.sMin, currentToner]; EnterBandData[pdState, @buffer, SIZE[PDFileFormat.Command] + SIZE[CARDINAL] + SIZE[CARDINAL] + nRuns * SIZE[PDFileFormat.Run]]; nRuns _ 0; buffer.sMin _ scanLineNumber; buffer.sSize _ 0; }; }; InitBuffer: PROC [sMin: CARDINAL] = { buffer.sMin _ scanLineNumber _ sMin; buffer.sSize _ 0; bandEnd _ sMin - sMin MOD bandSSize + bandSSize; }; BufferRun: PROC [fMin, fSize: CARDINAL] = INLINE { IF nRuns = maxRuns THEN PutBuffer[]; buffer.run[nRuns] _ [fMin: fMin, fSize: fSize, lastRun: FALSE]; nRuns _ nRuns + 1; }; NextLine: PROC = INLINE { buffer.sSize _ buffer.sSize + 1; buffer.run[nRuns - 1].lastRun _ TRUE; scanLineNumber _ scanLineNumber + 1; }; CaptureRun: PROC [sMin, fMin: INTEGER, fSize: NAT] = { CaptureCardinalRun[sMin, fMin, fSize]; }; CaptureCardinalRun: PROC [sMin, fMin, fSize: CARDINAL] = INLINE { IF nRuns = 0 THEN InitBuffer[sMin] ELSE IF sMin >= bandEnd OR NOT (sMin IN [scanLineNumber..scanLineNumber+1]) OR nRuns = maxRuns THEN {PutBuffer[]; InitBuffer[sMin]}; IF sMin > scanLineNumber THEN NextLine[]; IF sMin # scanLineNumber THEN ERROR; IF INT[fMin] + INT[fSize] > INT[LAST[CARDINAL]] THEN {fSize _ LAST[CARDINAL] - fMin}; ExtendBB[pdState, sMin, fMin]; IF fSize > LAST[NAT] THEN { BufferRun[fMin, LAST[NAT]]; fMin _ fMin + LAST[NAT]; fSize _ fSize - LAST[NAT]; }; BufferRun[fMin, fSize]; ExtendBB[pdState, sMin + 1, fMin + fSize]; }; FOR toner: Toner IN [pdState.firstToner..pdState.lastToner] DO IF pdState.colorDescriptor[toner].enabled THEN { currentToner _ toner; deliverProc[CaptureRun]; PutBuffer[]; }; ENDLOOP; }; NewPriorityLevel: PUBLIC PROC [pdState: PDState, toner: Toner] = { IF NOT pdState.toners[toner] THEN ERROR; pdState.colorDescriptor[toner].colorId _ pdState.colorDescriptor[toner].colorId + 1; pdState.colorDescriptor[toner].length _ 0; pdState.colorDescriptor[toner].enabled _ TRUE; }; ColorSamples: PUBLIC PROC [pdState: PDState, toner: Toner, sMin, fMin: CARDINAL, sSize, fSize: CARDINAL, deliverProc: DeliverSampleArrayProc, tFlag: TFlag] = TRUSTED { colorCommand: PDFileFormat.Command _ [imaging[IF tFlag = opaque THEN colorSamples ELSE maskSamples]]; bandSSize: CARDINAL = pdState.herald.bandSSize; wordsPerLine: NAT _ (fSize+(bitsPerWord-1))/bitsPerWord; s: CARDINAL _ sMin; sEnd: CARDINAL _ sMin + sSize; residualThisBand: NAT _ 0; CaptureScanLine: PROC [scanLineDataPointer: LONG POINTER] = TRUSTED { IF residualThisBand = 0 THEN { args: PDFileFormat.MaskSamples _ [ sMin: s, fMin: fMin ]; truncatedEnd: CARDINAL _ MIN[sEnd, s + bandSSize - (s MOD bandSSize)]; sampleArray: PDFileFormat.SampleArray _ [ sSize: (residualThisBand _ truncatedEnd - s), fSize: fSize ]; SelectBand[pdState, s, toner]; EnterBandData[pdState, @colorCommand, SIZE[PDFileFormat.Command]]; EnterBandData[pdState, @args, SIZE[PDFileFormat.MaskSamples]]; EnterBandData[pdState, @sampleArray, SIZE[PDFileFormat.SampleArray]]; }; EnterBandData[pdState, scanLineDataPointer, wordsPerLine]; residualThisBand _ residualThisBand - 1; s _ s + 1; }; IF pdState.colorDescriptor[toner].enabled THEN { ExtendBB[pdState, sMin, fMin]; ExtendBB[pdState, sMin + sSize, fMin + fSize]; deliverProc[CaptureScanLine]; IF residualThisBand # 0 THEN ERROR; IF s # sEnd THEN ERROR; }; }; RemainingLoadSize: PUBLIC PROC [pdState: PDState] RETURNS [words: INT] = { words _ pdState.loadSizeInWords - pdState.currentLoadLocation; IF pdState.loadDescription # NIL AND pdState.loadDescription.count = pdState.loadDescription.maxCount THEN words _ 0; }; GetLoadDescription: PROC [pdState: PDState] RETURNS [LoadDescription] = { IF pdState.loadDescription = NIL THEN { loadDescription: LoadDescription _ NEW[LoadDescriptionRep[maxLoadItems]]; countedVM: CountedVM.Handle _ CountedVM.Allocate[pdState.loadSizeInWords]; loadDescription.storageRef _ countedVM; loadDescription.pointer _ countedVM.pointer; loadDescription.words _ countedVM.words; loadDescription.count _ 0; pdState.loadDescription _ loadDescription; }; RETURN [pdState.loadDescription] }; loadBreakOffset: INT _ LAST[INT]; loadBreakCount: INT _ 0; DebugLoad: PROC [loadOffset: INT] ~ { IF loadOffset = loadBreakOffset THEN loadBreakCount _ loadBreakCount + 1; }; LoadRunGroup: PUBLIC PROC [pdState: PDState, deliverProc: DeliverRunGroupProc] RETURNS [loadReference: LoadReference] = TRUSTED { highBit: CARDINAL = CARDINAL[LAST[NAT]] + 1; loadDescription: LoadDescription _ GetLoadDescription[pdState]; scanLineNumber: CARDINAL _ 0; maxLoc: INT _ pdState.loadSizeInWords; loc: INT _ pdState.currentLoadLocation; base: LONG POINTER TO CARDINAL _ loadDescription.pointer; fMax: CARDINAL _ 0; scanLineEmpty: BOOLEAN _ TRUE; CaptureRun: PROC [sMin, fMin: INTEGER, fSize: NAT] = CHECKED { CaptureCardinalRun[sMin, fMin, fSize]; }; CaptureCardinalRun: PROC [sMin, fMin, fSize: CARDINAL] = TRUSTED INLINE { IF sMin maxLoc THEN ERROR; IF scanLineEmpty THEN {(base+loc)^ _ 0; (base+loc+1)^ _ highBit; loc _ loc+2} ELSE {(base+loc-1)^ _ (base+loc-1)^ + highBit}; scanLineNumber _ scanLineNumber+1; scanLineEmpty _ TRUE; ENDLOOP; scanLineEmpty _ FALSE; IF INT[fMin] + INT[fSize] > INT[LAST[CARDINAL]] THEN {fSize _ LAST[CARDINAL] - fMin}; IF fSize > LAST[NAT] THEN { IF loc+2 > maxLoc THEN ERROR; (base+loc)^ _ fMin; (base+loc+1)^ _ LAST[NAT]; loc _ loc+2; fMin _ fMin + LAST[NAT]; fSize _ fSize - LAST[NAT]; }; IF loc+2 > maxLoc THEN ERROR; (base+loc)^ _ fMin; (base+loc+1)^ _ fSize; loc _ loc+2; fMax _ MAX[fMax, fMin+fSize]; }; origin: INT _ loc+1; loc _ loc + 2; IF loc > maxLoc THEN ERROR; deliverProc[CaptureRun]; IF NOT scanLineEmpty THEN {(base+loc-1)^ _ (base+loc-1)^ + highBit; scanLineNumber _ scanLineNumber+1}; (base+origin-1)^ _ fMax; (base+origin)^ _ scanLineNumber; pdState.currentLoadLocation _ loc; pdState.herald.maxLoadWord _ MAX[pdState.herald.maxLoadWord, loc]; loadReference _ loadDescription.count; loadDescription.count _ loadDescription.count + 1; loadDescription[loadReference] _ [ loadEntryType: runGroup, offsetHighBits: Basics.HighHalf[origin], offsetLowBits: Basics.LowHalf[origin], pageOfMostRecentUse: 0, numberOfPagesUsedIn: 0 ]; DebugLoad[origin]; }; LoadContiguousSampleArray: PUBLIC PROC [pdState: PDState, sSize, fSize: CARDINAL, bitsPtr: LONG POINTER] RETURNS [loadReference: LoadReference] = TRUSTED { loadDescription: LoadDescription _ GetLoadDescription[pdState]; source: LONG POINTER TO WORD _ bitsPtr; wordsPerLine: NAT _ (fSize+(bitsPerWord-1))/bitsPerWord; words: INT _ Basics.LongMult[sSize, wordsPerLine]; startOffset: INT _ pdState.currentLoadLocation; destOffset: INT _ startOffset + SIZE[PDFileFormat.SampleArray]; endOffset: INT _ destOffset + words; sampleArray: LONG POINTER TO PDFileFormat.SampleArray _ loadDescription.pointer + startOffset; destBase: LONG POINTER TO WORD _ loadDescription.pointer + destOffset; IF endOffset > pdState.loadSizeInWords THEN ERROR; sampleArray.sSize _ sSize; sampleArray.fSize _ fSize; LongBlockTransfer[source: source, count: words, dest: destBase]; loadReference _ loadDescription.count; loadDescription.count _ loadDescription.count + 1; loadDescription[loadReference] _ [ loadEntryType: samples, offsetHighBits: Basics.HighHalf[startOffset], offsetLowBits: Basics.LowHalf[startOffset], pageOfMostRecentUse: 0, numberOfPagesUsedIn: 0 ]; pdState.currentLoadLocation _ endOffset; pdState.herald.maxLoadWord _ MAX[pdState.herald.maxLoadWord, endOffset]; DebugLoad[startOffset]; }; LoadContiguousColorTile: PUBLIC PROC [pdState: PDState, phase: CARDINAL, sMin, fMin: CARDINAL, sSize, fSize: CARDINAL, bitsPtr: LONG POINTER] RETURNS [loadReference: LoadReference] = TRUSTED { loadDescription: LoadDescription _ GetLoadDescription[pdState]; source: LONG POINTER TO WORD _ bitsPtr; wordsPerLine: NAT _ (fSize+(bitsPerWord-1))/bitsPerWord; words: INT _ Basics.LongMult[sSize, wordsPerLine]; startOffset: INT _ pdState.currentLoadLocation; destOffset: INT _ startOffset + SIZE[PDFileFormat.Tile]; endOffset: INT _ destOffset + words; tile: LONG POINTER TO PDFileFormat.Tile _ loadDescription.pointer + startOffset; destBase: LONG POINTER TO WORD _ loadDescription.pointer + destOffset; IF endOffset > pdState.loadSizeInWords THEN ERROR; tile.phase _ phase; tile.sMin _ sMin; tile.fMin _ fMin; tile.sSize _ sSize; tile.fSize _ fSize; LongBlockTransfer[source: source, count: words, dest: destBase]; loadReference _ loadDescription.count; loadDescription.count _ loadDescription.count + 1; loadDescription[loadReference] _ [ loadEntryType: tile, offsetHighBits: Basics.HighHalf[startOffset], offsetLowBits: Basics.LowHalf[startOffset], pageOfMostRecentUse: 0, numberOfPagesUsedIn: 0 ]; pdState.currentLoadLocation _ endOffset; pdState.herald.maxLoadWord _ MAX[pdState.herald.maxLoadWord, endOffset]; DebugLoad[startOffset]; }; EndPage: PUBLIC PROC [pdState: PDState] = { startBand: NAT _ pdState.sMinPage/pdState.herald.bandSSize; endBand: NAT _ (pdState.sMaxPage+pdState.herald.bandSSize-1)/pdState.herald.bandSSize; nBands: NAT _ MAX[0, INTEGER[endBand]-startBand]; fSizePage: CARDINAL _ MAX[INT[pdState.fMaxPage]-pdState.fMinPage, 0]; IF nBands = 0 THEN startBand _ 0; IF fSizePage = 0 THEN pdState.fMinPage _ 0; WriteLoadAdditions[pdState]; FOR t: Toner IN [pdState.firstToner..pdState.lastToner] DO bands: Bands _ pdState.bands[t]; IF pdState.toners[t] THEN { WriteStartImage[ pdState: pdState, feed: t = pdState.firstToner AND pdState.feed, strip: t = pdState.lastToner AND pdState.strip, toner: t, passBands: startBand, nBands: nBands, fMinPage: pdState.fMinPage, fSizePage: fSizePage ]; WriteBands[pdState, bands, startBand, nBands]; pdState.currentImage _ pdState.currentImage + 1; }; ENDLOOP; pdState.sMinPage _ pdState.herald.imageSSize; pdState.fMinPage _ pdState.herald.imageFSize; pdState.sMaxPage _ pdState.fMaxPage _ 0; IF pdState.overflowStream # NIL THEN pdState.overflowStream.SetIndex[0]; StartImage[pdState, defaultToners]; }; defaultToners: TonerSet ~ DefaultToners[]; DefaultToners: PROC RETURNS [t: TonerSet] ~ {t[black] _ TRUE}; FlushPage: PUBLIC PROC [pdState: PDState] = { startBand: NAT _ pdState.sMinPage/pdState.herald.bandSSize; endBand: NAT _ (pdState.sMaxPage+pdState.herald.bandSSize-1)/pdState.herald.bandSSize; nBands: NAT _ MAX[0, INTEGER[endBand]-startBand]; fSizePage: CARDINAL _ MAX[INT[pdState.fMaxPage]-pdState.fMinPage, 0]; FOR t: Toner IN [pdState.firstToner..pdState.lastToner] DO bands: Bands _ pdState.bands[t]; FOR i: NAT IN [startBand..startBand+nBands) DO bands[i].colorId _ 0; bands[i].bandBuffer.length _ 0; bands[i].bandBuffer.overflowIndices _ NIL; ENDLOOP ENDLOOP; IF pdState.overflowStream # NIL THEN { pdState.overflowStream.SetIndex[0]; }; pdState.sMinPage _ pdState.herald.imageSSize; pdState.fMinPage _ pdState.herald.imageFSize; pdState.sMaxPage _ pdState.fMaxPage _ 0; StartImage[pdState, defaultToners]; }; Close: PUBLIC PROC [pdState: PDState] = { WriteControlCommand[pdState, endDocument]; pdState.stream.SetIndex[0]; WriteHerald[pdState]; IO.Close[pdState.stream]; IF pdState.overflowStream # NIL THEN { pdState.overflowStream.SetIndex[0]; pdState.overflowStream.SetLength[0]; pdState.overflowStream.Close[abort: TRUE]; }; }; ObjectFallsOutsideOfDeclaredPageBounds: ERROR ~ CODE; ExtendBB: PROC [pdState: PDState, s: CARDINAL, f: CARDINAL] = { pdState.sMinPage _ MIN[s, pdState.sMinPage]; pdState.sMaxPage _ MAX[s, pdState.sMaxPage]; pdState.fMinPage _ MIN[f, pdState.fMinPage]; pdState.fMaxPage _ MAX[f, pdState.fMaxPage]; IF pdState.sMaxPage > pdState.herald.imageSSize THEN ERROR ObjectFallsOutsideOfDeclaredPageBounds; IF pdState.fMaxPage > pdState.herald.imageFSize THEN ERROR ObjectFallsOutsideOfDeclaredPageBounds; }; SelectBandNoColor: PROC [pdState: PDState, sMin: CARDINAL, toner: Toner] = TRUSTED { bandNum: NAT _ sMin/pdState.herald.bandSSize; bands: Bands _ pdState.bands[toner]; IF bands[bandNum].bandBuffer = NIL THEN bands[bandNum].bandBuffer _ NEW[BandBufferRec]; pdState.selectedBands _ bands; pdState.selectedBandNum _ bandNum; }; SelectBand: PROC [pdState: PDState, sMin: CARDINAL, toner: Toner] = TRUSTED { colorId: INT _ pdState.colorDescriptor[toner].colorId; longPriority: Basics.LongNumber _ [lc[colorId]]; priorityHighbits: [0..256) _ longPriority.highbits; priorityLowbits: CARDINAL _ longPriority.lowbits; priorityCommand: PDFileFormat.Command _ [control[setPriority, priorityHighbits]]; bandNum: NAT _ sMin/pdState.herald.bandSSize; bands: Bands _ pdState.bands[toner]; IF bands[bandNum].bandBuffer = NIL THEN bands[bandNum].bandBuffer _ NEW[BandBufferRec]; pdState.selectedBands _ bands; pdState.selectedBandNum _ bandNum; IF colorId # bands[bandNum].colorId THEN { bands[bandNum].colorId _ colorId; IF pdState.priorityImportant THEN { EnterBandData[pdState, @priorityCommand, SIZE[PDFileFormat.Command]]; EnterBandData[pdState, @priorityLowbits, SIZE[CARDINAL]]; }; EnterBandData[pdState, @(pdState.colorDescriptor[toner].command), pdState.colorDescriptor[toner].length]; }; }; WriteOverflowBand: PROC [pdState: PDState, bandBuffer: BandBuffer] = TRUSTED { bandDataPtr: LONG POINTER _ @(bandBuffer.word); IF pdState.overflowStream = NIL THEN { pdState.overflowStream _ FS.StreamOpen[fileName: "PDTemp$", accessOptions: $create]; }; bandBuffer.overflowIndices _ CONS[ IO.GetIndex[pdState.overflowStream], bandBuffer.overflowIndices ]; pdState.overflowStream.UnsafePutBlock[[base: bandDataPtr, startIndex: 0, count: bandBufferSize*bytesPerWord]]; bandBuffer.length _ 0; }; EnterBandData: PROC [pdState: PDState, startPtr: LONG POINTER, wordCount: NAT] = TRUSTED { source: LONG POINTER TO WORD _ startPtr; bandBuffer: BandBuffer _ pdState.selectedBands[pdState.selectedBandNum].bandBuffer; WHILE wordCount > 0 DO IF wordCount <= bandBufferSize - bandBuffer.length THEN { BlockTransfer[source: startPtr, count: wordCount, dest: @(bandBuffer.word[bandBuffer.length])]; startPtr _ startPtr + wordCount; bandBuffer.length _ bandBuffer.length + wordCount; wordCount _ 0; } ELSE { count: NAT _ bandBufferSize - bandBuffer.length; bufPtr: LONG POINTER _ @(bandBuffer.word); BlockTransfer[source: startPtr, count: count, dest: bufPtr+bandBuffer.length]; startPtr _ startPtr + count; bandBuffer.length _ bandBuffer.length + count; wordCount _ wordCount - count; WriteOverflowBand[pdState, bandBuffer]; }; ENDLOOP; }; WriteLoadAdditions: PROC [pdState: PDState] = TRUSTED { WHILE pdState.loadWrittenLength < pdState.currentLoadLocation DO loadDescription: LoadDescription _ GetLoadDescription[pdState]; lengthOfAdditions: INT _ pdState.currentLoadLocation-pdState.loadWrittenLength; lengthOfChunk: INT _ MIN[lengthOfAdditions, 8*1024]; unsafeBlock: Basics.UnsafeBlock = [base: loadDescription.pointer+pdState.loadWrittenLength, startIndex: 0, count: lengthOfChunk*bytesPerWord]; WriteControlCommand[pdState, storeLoad]; WriteLongCardinal[pdState, pdState.loadWrittenLength]; WriteCardinal[pdState, lengthOfChunk]; pdState.stream.UnsafePutBlock[unsafeBlock]; pdState.loadWrittenLength _ pdState.loadWrittenLength + lengthOfChunk; ENDLOOP; }; WriteLongCardinal: PROC [pdState: PDState, lc: LONG CARDINAL] = TRUSTED { base: LONG POINTER ~ @lc; pdState.stream.UnsafePutBlock[[base: base, startIndex: 0, count: SIZE[LONG CARDINAL]*bytesPerWord]]; }; WriteCardinal: PROC [pdState: PDState, c: CARDINAL] = TRUSTED { base: LONG POINTER ~ @c; pdState.stream.UnsafePutBlock[[base: base, startIndex: 0, count: SIZE[CARDINAL]*bytesPerWord]]; }; WriteHerald: PROC [pdState: PDState] = TRUSTED { base: LONG POINTER ~ @pdState.herald; pdState.stream.UnsafePutBlock[[base: base, startIndex: 0, count: SIZE[PDFileFormat.Herald]*bytesPerWord]]; }; WriteControlCommand: PROC [pdState: PDState, controlCom: PDFileFormat.ControlCom] = TRUSTED { command: PDFileFormat.Command _ [control[controlCom]]; base: LONG POINTER ~ @command; pdState.stream.UnsafePutBlock[[base: base, startIndex: 0, count: SIZE[PDFileFormat.Command]*bytesPerWord]]; }; WriteStartImage: PROC [ pdState: PDState, feed: BOOLEAN, strip: BOOLEAN, toner: Toner, passBands: NAT, nBands: NAT, fMinPage: CARDINAL, fSizePage: CARDINAL ] = TRUSTED { StartImageBuf: TYPE = MACHINE DEPENDENT RECORD [ command: PDFileFormat.Command, args: PDFileFormat.StartImage ]; startImageBuf: StartImageBuf _ [ command: [control[com: startImage]], args: [leftOverMode: pdState.leftOverMode, feed: feed, strip: strip, toner: toner, passBands: passBands, nBands: nBands, fMinPage: fMinPage, fSizePage: fSizePage] ]; base: LONG POINTER ~ @startImageBuf; pdState.stream.UnsafePutBlock[[base: base, startIndex: 0, count: SIZE[StartImageBuf]*bytesPerWord]]; }; WriteBands: PROC [pdState: PDState, bands: Bands, startBand, nBands: NAT] = TRUSTED { FOR bandNum: NAT IN [startBand..startBand+nBands) DO bandBuffer: BandBuffer _ bands[bandNum].bandBuffer; IF bandBuffer # NIL THEN { overflowIndices: LIST OF INT _ NIL; WHILE bandBuffer.overflowIndices # NIL DO t: LIST OF INT _ bandBuffer.overflowIndices; bandBuffer.overflowIndices _ bandBuffer.overflowIndices.rest; t.rest _ overflowIndices; overflowIndices _ t; ENDLOOP; WHILE overflowIndices # NIL DO overflowBuf: ARRAY [0..bandBufferSize) OF CARDINAL; base: LONG POINTER ~ @overflowBuf; pdState.overflowStream.SetIndex[overflowIndices.first]; IF bandBufferSize*bytesPerWord # pdState.overflowStream.UnsafeGetBlock[[ base: base, startIndex: 0, count: bandBufferSize*bytesPerWord ]] THEN ERROR; pdState.stream.UnsafePutBlock[[base: base, startIndex: 0, count: bandBufferSize*bytesPerWord]]; {t: LIST OF INT _ overflowIndices; overflowIndices _ t.rest; t.rest _ NIL}; ENDLOOP; pdState.stream.UnsafePutBlock[[base: LOOPHOLE[@(bandBuffer.word)], startIndex: 0, count: bandBuffer.length*bytesPerWord]]; bandBuffer.length _ 0; }; WriteControlCommand[pdState, endBand]; bands[bandNum].colorId _ 0; ENDLOOP; }; END. τPDFileWriterImpl.mesa Copyright c 1984, 1985 Xerox Corporation. All rights reserved. Michael Plass, July 8, 1985 9:28:49 am PDT Doug Wyatt, March 7, 1985 6:27:30 pm PST We will come back and overwrite this when the file is closed. set a breakpoint here to debug strange load contents. Reserve a word in the load for fMax. Will come back to fill in sSize. Fill in fMax. Fill in sSize. In case the client decides it didn't really want this page after all. Note - this relys on FS to do the right thing when multiple instances of the file writer are around. The version number mechanism should keep us out of trouble. Writes out any additions to the font load Writes out the bands, resetting them along the way. Reverse the list of overflow indices. Κ$I˜codešœ™Kšœ Οmœ4™?K™*K™(—K˜šΟk ˜ KšœžœS˜_Kšœ žœ˜#Kšžœžœ˜Kšžœžœ(žœ"˜XKšœ žœΝ˜ίKšœ žœe˜wKšœžœ ˜Kšœžœžœ˜K˜—šœžœž˜Kšžœžœžœ˜0Kšžœ ˜šœž˜K˜—šΟn œžœžœ žœžœ žœžœžœ˜VKšœž œžœA˜SK˜—šŸœžœžœ žœžœ žœžœžœž œ˜cšžœ žœžœž˜Kšœ%žœžœ˜AKšœžœžœ˜!Kšœžœžœ˜Kšœžœžœ˜Kšžœ˜—Kšžœ žœ9˜JKšœ˜K˜—Kšœžœ˜-Kšœ žœ˜+Kšžœžœžœ˜Kšœžœžœ˜KšŸœžœ$˜=KšŸœžœ˜3KšŸœžœ'˜CKšŸœžœ$˜=Kšœžœ˜!Kšœ žœ˜'Kšœžœ˜!K˜Kšœžœžœ ˜šœ žœžœ˜Kšœžœ žœžœ˜%Kšœ˜K˜—šœžœžœ˜Kšœ žœ˜ Kšœ˜Kšœ˜K˜—Kšœžœ˜Kšœ žœžœ˜%šœžœžœ˜Kšœžœ˜Kš œžœžœžœžœ˜#Kšœžœžœž˜'Kšœ˜K˜—šœžœžœ˜ Kšœ žœΟc%˜7Kšœ žœžœ˜Kšœžœ˜Kšœ?˜?Kšœ'˜'Kšœ˜K˜—Kšœžœ˜Kšœžœžœ˜/šœžœžœ˜#Kšœ žœ (˜9Kšœ žœžœ˜Kšœžœ %˜2Kšœžœ˜Kšœ žœ žœžœ˜7Kšœ˜K˜—Kšœžœ#˜6šœžœžœ˜%Kšœ˜Kšœ˜Kšœžœ˜Kšœžœ˜Kšœž˜Kšœ˜K˜—Kšœ žœžœžœ ˜&šœ žœžœžœ˜"Kšœ žœ˜Kšœ˜Kšœžœžœ˜0Kšœžœžœ˜Kšœžœžœ˜Kšœ%˜%Kšœžœžœ˜Kšœžœžœ˜Kšœžœžœ˜Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœ!˜!Kšœžœžœž˜Kšœ˜K˜—šŸœžœžœ žœYžœ žœ žœžœžœžœ˜υKšœžœ˜ Kšœ žœ˜Kšœ˜Kšœ'˜'Kšœ)˜)Kšœ)˜)Kšœ,˜,Kšœ@˜@Kšœ:˜:Kšœ%˜%Kšœ˜Kšœ˜Kšœžœ ˜'Kšœ$˜$Kšœžœ˜"Kšœ(˜(Kšœžœžœ˜Kšœžœ˜Kšœžœ˜$Kšœžœ˜.Kšœ2˜2šœ˜K™=—Kšœ˜K˜—š Ÿœžœžœ'žœžœžœ˜uKšœ*˜*Kšœ.˜.Kšœ˜K˜—š Ÿ œžœžœ3žœžœ˜]Kšœ˜Kšœ˜Kšœ˜Kšœžœ˜ Kšœžœ˜ š žœ žœžœžœž˜,šžœ žœ˜šžœžœžœ˜ Kšœžœ+˜AKšœ˜—Kšžœžœžœ˜?Kšœ˜Kšœ˜—šœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜—Kšž˜—Kšœ˜K˜—šŸ œžœžœ%˜=Kšžœžœžœžœ˜(KšœT˜TKšœ(žœ˜CKšœ@˜@Kšœ)žœ˜.Kšœ˜K˜—šŸ œžœžœ%˜?Kšžœžœžœžœ˜(KšœT˜TKšœ(žœ˜CKšœB˜BKšœ)žœ˜.Kšœ˜K˜—šŸ œžœžœ%˜=Kšœ)žœ˜/Kšœ˜K˜—šŸ œžœžœJžœ˜lKšœC˜CKšœk˜kKšœ žœ.˜:Kšœžœžœžœ˜`Kšžœ žœžœ˜-Kšžœžœžœžœ˜(šœ"˜"Kšœ˜Kšœžœžœ˜EKšœ'˜'Kšœ#˜#Kšœ ž˜ Kšœ˜—Kšœ˜K˜—šŸœžœžœžœ ˜Ešžœžœ)ž˜>Kšžœžœ ˜*Kšžœ˜—Kšœ˜K˜—š Ÿ œžœžœžœžœ˜LKšœ!˜!Kšœ!˜!Kšœ˜K˜—š Ÿ œžœžœ žœžœžœ˜gKš œžœžœžœžœ˜GKšœ žœ˜/Kšœ<˜šžœ(žœ˜0Kšœžœžœ ˜DKšœ!˜!Kšœ!žœ˜=Kšœ"žœ˜Dšžœžœ žœž˜>Kšœ˜Kšœ!žœ˜=Kšœ"žœ˜DKšžœ˜—Kšœ˜—Kšžœ˜—Kšœ˜K˜—šŸ œžœžœ!žœžœžœžœ˜†Kš œžœžœžœžœ˜GKšœ žœ˜/Kšœ<˜šžœ(žœ˜0Kšœžœžœ ˜DKšœ!˜!Kšœ!žœ˜=Kšœ"žœ˜Dšžœžœ žœž˜>Kšœ˜Kšœ!žœ˜=Kšœ"žœ˜DKšžœ˜—Kšœ˜—Kšžœ˜—Kšœ˜K˜—š Ÿœžœžœ5žœžœžœ˜uKšœF˜FKšœk˜kKšœT˜Tšœ%˜%Kšœ%˜%Kšœ ˜ Kšœ ˜ Kšœ˜—KšœžœžœžœK˜jKš œžœžœžœžœ˜WKšœ žœ˜/Kšžœ#žœžœ˜0Kšœ˜KšœN˜Nšžœžœ)ž˜>šžœ(žœ˜0Kšœžœžœ ˜DKšœ!˜!Kšœ!žœ˜=Kšœžœ˜Ašžœžœ žœž˜>Kšœ˜Kšœ!žœ˜=Kšœžœ˜AKšžœ˜—Kšœ˜—Kšžœ˜—Kšœ˜K˜—šŸ œžœžœžœžœ žœ žœ)žœ˜žKšœ:˜:Kšœ žœ˜/Kšœžœ'˜8Kšœ˜Kšœ.˜.šžœžœ)ž˜>šžœ(žœ˜0Kšœžœ˜Kšœžœ˜Kšœžœ˜š œžœžœžœžœ˜Bšžœžœ˜šœ"˜"Kšœ˜Kšœ ˜ Kšœ˜—Kšœžœžœžœ˜Hšœ)˜)Kšœ-˜-Kšœ ˜ Kšœ˜—Kšœ˜Kšœ!žœ˜=Kšœžœ˜>Kšœ%žœ˜EKšœ˜—Kšœ:˜:Kšœ(˜(K˜ Kšœ˜—Kšœ˜Kšžœžœžœ˜#Kšžœ žœžœ˜Kšœ˜—Kšžœ˜—Kšœ˜K˜—š Ÿœžœžœ6žœžœžœ˜wKšœG˜GKšœk˜kKšœU˜Ušœ&˜&Kšœ%˜%Kšœ ˜ Kšœ ˜ Kšœ˜—Kš œ žœžœžœžœ6˜XKš œ žœžœžœžœ2˜TKš œžœžœžœžœ˜KKšœ žœ˜/Kšžœ$žœžœ˜1Kšœ˜Kšœ6˜6šžœžœ)ž˜>šžœ(žœ˜0Kšœžœžœ ˜DKšœ!˜!Kšœ!žœ˜=Kšœžœ ˜Bšžœžœ žœž˜>Kšœ˜Kšœ!žœ˜=Kšœžœ ˜BKšžœ˜—Kšœ˜—Kšžœ˜—Kšœ˜K˜—šŸ œžœžœ9˜RKšœ žœžœ˜5Kšœ žœ˜/šœžœž œžœ˜"Kšœ8˜8Kšœžœ˜Kšœžœ˜Kšœžœžœ žœ˜+K˜—Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kšœ˜šŸ œžœžœ˜šžœ žœ˜šžœžœžœ˜+Kšœ ˜ Kšœ žœ˜%Kšœ˜—Kšœ/˜/Kš œ žœžœžœžœžœ žœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜—Kšœ˜—šŸ œžœžœ˜%Kšœ$˜$Kšœ˜Kšœžœ˜0Kšœ˜—šŸ œžœžœžœ˜2Kšžœžœ ˜$Kšœ8žœ˜?Kšœ˜Kšœ˜—šŸœžœžœ˜Kšœ ˜ Kšœ žœ˜%Kšœ$˜$Kšœ˜—šŸ œžœžœ žœ˜6Kšœ&˜&Kšœ˜—šŸœžœžœžœ˜AKšžœ žœ˜"Kšžœžœžœžœžœ%žœžœ!˜„Kšžœžœ ˜)Kšžœžœžœ˜$Kšžœžœ žœ žœžœžœžœ žœžœ ˜UKšœ˜šžœ žœžœžœ˜Kšœžœžœ˜Kš œžœžœžœžœ˜3Kšœ˜—Kšœ˜Kšœ*˜*Kšœ˜—šžœžœ)ž˜>šžœ(žœ˜0Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜—Kšžœ˜—Kšœ˜K˜—šŸœžœžœ%˜BKšžœžœžœžœ˜(KšœT˜TKšœ*˜*Kšœ)žœ˜.Kšœ˜K˜—šŸ œžœžœ&žœžœžœ7žœ˜§Kšœ.žœžœžœ˜eKšœ žœ˜/Kšœžœ'˜8Kšœžœ˜Kšœžœ˜Kšœžœ˜š Ÿœžœžœžœžœ˜Ešžœžœ˜šœ"˜"Kšœ˜Kšœ ˜ Kšœ˜—Kšœžœžœžœ ˜Fšœ)˜)Kšœ-˜-Kšœ ˜ Kšœ˜—Kšœ˜Kšœ&žœ˜BKšœžœ˜>Kšœ%žœ˜EKšœ˜—Kšœ:˜:Kšœ(˜(K˜ Kšœ˜—šžœ(žœ˜0Kšœ˜Kšœ.˜.Kšœ˜Kšžœžœžœ˜#Kšžœ žœžœ˜K˜—Kšœ˜K˜—š Ÿœžœžœžœ žœ˜JKšœ>˜>KšžœžœžœBžœ ˜uKšœ˜K˜—šŸœžœžœ˜Išžœžœžœ˜'Kšœ#žœ#˜IKšœJ˜JKšœ'˜'Kšœ,˜,Kšœ(˜(Kšœ˜Kšœ*˜*Kšœ˜—Kšžœ˜ Kšœ˜K˜—Kšœžœžœžœ˜!Kšœžœ˜šŸ œžœžœ˜%šžœž˜$K™5Kšœ$˜$—Kšœ˜K˜—š Ÿ œžœžœ6žœ"žœ˜Kš œ žœžœžœžœ˜,Kšœ?˜?Kšœžœ˜Kšœžœ˜&Kšœžœ˜'Kš œžœžœžœžœ˜9Kšœžœ˜Kšœžœžœ˜š Ÿ œžœžœ žœžœ˜>Kšœ&˜&Kšœ˜—š Ÿœžœžœžœžœ˜IKšžœžœžœ .˜Qšžœž˜Kšžœžœžœ˜Kšžœžœ8˜MKšžœ+˜/Kšœ"˜"Kšœžœ˜Kšžœ˜—Kšœžœ˜Kšžœžœ žœ žœžœžœžœ žœžœ ˜Ušžœ žœžœžœ˜Kšžœžœžœ˜Kšœ$žœžœ˜;Kš œžœžœžœžœ˜3Kšœ˜—Kšžœžœžœ˜Kšœ7˜7Kšœžœ˜Kšœ˜—šœžœ ˜Kšœ$™$—˜K™ —Kšžœžœžœ˜Kšœ˜KšžœžœžœN˜gšœ˜Kšœ ™ —šœ ˜ K™—Kšœ"˜"Kšœžœ"˜BKšœ&˜&Kšœ2˜2šœ"˜"Kšœ˜Kšœ(˜(Kšœ&˜&Kšœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ˜K˜—šŸœžœžœ"žœ žœžœžœ"žœ˜›Kšœ?˜?Kš œžœžœžœžœ ˜'Kšœžœ'˜8Kšœžœ(˜2Kšœ žœ˜/Kšœ žœžœ˜?Kšœ žœ˜$Kšœ žœžœžœB˜^Kš œ žœžœžœžœ(˜FKšžœ%žœžœ˜2Kšœ˜Kšœ˜Kšœ@˜@Kšœ&˜&Kšœ2˜2šœ"˜"Kšœ˜Kšœ-˜-Kšœ+˜+Kšœ˜Kšœ˜Kšœ˜—Kšœ(˜(Kšœžœ(˜HKšœ˜Kšœ˜K˜—šŸœžœžœžœžœžœ žœžœžœ"žœ˜ΐKšœ?˜?Kš œžœžœžœžœ ˜'Kšœžœ'˜8Kšœžœ(˜2Kšœ žœ˜/Kšœ žœžœ˜8Kšœ žœ˜$Kšœžœžœžœ;˜PKš œ žœžœžœžœ(˜FKšžœ%žœžœ˜2Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ@˜@Kšœ&˜&Kšœ2˜2šœ"˜"Kšœ˜Kšœ-˜-Kšœ+˜+Kšœ˜Kšœ˜Kšœ˜—Kšœ(˜(Kšœžœ(˜HKšœ˜Kšœ˜K˜—šŸœžœžœ˜+Kšœ žœ-˜;Kšœ žœJ˜VKšœžœžœžœ˜1Kšœ žœžœžœ(˜EKšžœ žœ˜!Kšžœžœ˜+Kšœ˜šžœ žœ)ž˜:Kšœ ˜ šžœžœ˜šœ˜Kšœ˜Kšœžœ˜.Kšœžœ˜/Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ.˜.Kšœ0˜0K˜—Kšžœ˜—Kšœ-˜-Kšœ-˜-Kšœ(˜(Kšžœžœžœ$˜HKšœ#˜#Kšœ˜K˜—šœ*˜*KšŸ œžœžœžœ˜>K˜—šŸ œžœžœ˜-K™EKšœ žœ-˜;Kšœ žœJ˜VKšœžœžœžœ˜1Kšœ žœžœžœ(˜Ešžœ žœ)ž˜:Kšœ ˜ šžœžœžœž˜.Kšœ˜Kšœ˜Kšœ&žœ˜*Kšž˜—Kšžœ˜—šžœžœžœ˜&K˜#Kšœ˜—Kšœ-˜-Kšœ-˜-Kšœ(˜(Kšœ#˜#Kšœ˜K˜—šŸœžœžœ˜)Kšœ*˜*Kšœ˜Kšœ˜Kšžœ˜šžœžœžœ˜&K˜#Kšœ$˜$Kšœ$žœ˜*Kšœ˜—Kšœ˜K˜—šœ(žœžœ˜5K˜—šŸœžœžœžœ˜?Kšœžœ˜,Kšœžœ˜,Kšœžœ˜,Kšœžœ˜,Kšžœ.žœžœ(˜bKšžœ.žœžœ(˜bKšœ˜K˜—šŸœžœžœžœ˜TKšœ žœ!˜-Kšœ$˜$Kšžœžœžœžœ˜WKšœ˜Kšœ"˜"Kšœ˜K˜—šŸ œžœžœžœ˜MKšœ žœ*˜6Kšœ0˜0Kšœ3˜3Kšœžœ˜1KšœQ˜QKšœ žœ!˜-Kšœ$˜$Kšžœžœžœžœ˜WKšœ˜Kšœ"˜"šžœ!žœ˜*Kšœ!˜!šžœžœ˜#Kšœ)žœ˜EKšœ)žœžœ˜9K˜—Kšœi˜iKšœ˜—Kšœ˜K˜—šŸœžœ.žœ˜NKšœ žœžœ˜/šžœžœžœ˜&KšœT˜TK™‘Kšœ˜—šœžœ˜"Kšžœ"˜$Kšœ˜Kšœ˜—Kšœn˜nKšœ˜Kšœ˜K˜—š Ÿ œžœžœžœ žœžœ˜ZKš œžœžœžœžœ ˜(KšœS˜Sšžœž˜šžœ1žœ˜9Kšœ_˜_Kšœ ˜ Kšœ2˜2Kšœ˜Kšœ˜—šžœ˜Kšœžœ&˜0Kšœžœžœ˜*KšœN˜NKšœ˜Kšœ.˜.Kšœ˜Kšœ'˜'Kšœ˜—Kšž˜—Kšœ˜K˜—šŸœžœžœ˜7K™)šžœ9ž˜@Kšœ?˜?Kšœžœ9˜OKšœžœžœ˜4KšœŽ˜ŽKšœ(˜(Kšœ6˜6Kšœ&˜&Kšœ+˜+KšœF˜FKšžœ˜—Kšœ˜K˜—š Ÿœžœžœžœžœ˜IKšœžœžœ˜KšœAžœžœžœ˜dKšœ˜K˜—šŸ œžœžœžœ˜?Kšœžœžœ˜KšœAžœžœ˜_Kšœ˜K˜—šŸ œžœžœ˜0Kšœžœžœ˜%KšœAžœ%˜jKšœ˜K˜—šŸœžœ;žœ˜]Kšœ6˜6Kšœžœžœ ˜KšœAžœ&˜kKšœ˜K˜—šŸœžœ˜Kšœ˜Kšœžœ˜Kšœžœ˜Kšœ ˜ Kšœ žœ˜Kšœžœ˜ Kšœ žœ˜Kšœ ž˜Kšœžœ˜ š œžœžœž œžœ˜0Kšœ˜Kšœ˜Kšœ˜—šœ ˜ Kšœ$˜$Kšœ’˜’Kšœ˜—Kšœžœžœ˜$KšœAžœ˜dKšœ˜K˜—šŸ œžœ5žœžœ˜UK™3šžœ žœžœž˜4Kšœ3˜3šžœžœžœ˜Kš œžœžœžœžœ˜#K™%šžœžœž˜)Kšœžœžœžœ˜,Kšœ=˜=Kšœ˜Kšœ˜Kšžœ˜—šžœžœž˜Kšœ žœžœžœ˜3Kšœžœžœ˜"Kšœ7˜7šžœ˜ šœ'˜'Kšœ ˜ Kšœ˜Kšœ"˜"Kšœ˜——Kšžœžœ˜ Kšœ_˜_Kš œžœžœžœ7žœ˜KKšžœ˜—Kšœ%žœM˜zKšœ˜Kšœ˜—Kšœ&˜&Kšœ˜Kšžœ˜—Kšœ˜K˜—Kšžœ˜——…—~δ¦!