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, 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; }; UpdateMaxLoadWord: PROC [pdState: PDState, endOffset: CARD] ~ { maxLoadWord: Basics.LongNumber _ [pair[lo: pdState.herald.maxLoadWord.lo, hi: pdState.herald.maxLoadWord.hi]]; maxLoadWord.lc _ MAX[maxLoadWord.lc, endOffset]; pdState.herald.maxLoadWord _ [lo: maxLoadWord.lo, hi: maxLoadWord.hi]; }; 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, 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 _ [pair[lo: loadEntry.offsetLowBits, hi: 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: [lo: reference.lo, hi: reference.hi]], 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; UpdateMaxLoadWord[pdState, 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; UpdateMaxLoadWord[pdState, 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; UpdateMaxLoadWord[pdState, 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.hi; priorityLowbits: CARDINAL _ longPriority.lo; 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 AND pdState.leftOverMode 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 Σ 1984, 1985, 1987 Xerox Corporation. All rights reserved. Michael Plass, February 6, 1987 7:00:48 pm PST 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. Κ$q˜codešœ™KšœE™EK™.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˜—šžœœœ˜?Kšœn˜nKšœœ˜0KšœF˜FKšœ˜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šœa˜aKšœ œ.˜: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šœa˜aKšœ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šœa˜aKšœ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šœ ˜ Kšœ&˜&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šœ&˜&Kšœ˜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šœ&˜&Kšœ˜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šœ-˜-Kšœœ˜,KšœQ˜QKšœ œ!˜-Kšœ$˜$Kšœœœœ˜WKšœ˜Kšœ"˜"šœ!œ˜*Kšœ!˜!šœœœ˜