DIRECTORY Basics, CountedVM, FS, IO, PDFileFormat, PDFileWriter, PrincOpsUtils, 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 = MACHINE DEPENDENT 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 _ [black: TRUE], 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; pdState.herald.imageSSize _ pdState.sMinPage _ imageSSize; 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 _ [black: TRUE]; pdState.feed _ pdState.strip _ TRUE; nBands _ (pdState.herald.imageSSize+pdState.herald.bandSSize-1)/pdState.herald.bandSSize; 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 _ [black: TRUE], 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, fSize: CARDINAL] = { 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; }; 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; TRUSTED {loadDescription.pointer _ CountedVM.Pointer[countedVM]}; loadDescription.words _ CountedVM.Words[countedVM]; 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, fSize: CARDINAL] = TRUSTED { 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]; }; 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; }; 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: IO.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 Michael Plass, April 30, 1984 4:54:01 pm PDT 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. Ê#/˜Jšœ™J™,šÏk ˜ J˜Jšœ ˜ J˜J˜Jšœ ˜ Jšœ ˜ Jšœ˜J˜J˜J˜—šœœ˜Jšœœœ˜0Jšœ ˜šœ˜J˜—šÏn œœœ œœ œœœ˜VJšœ œœA˜SJ˜—šžœœœ œœ œœœ œ˜cšœ œœ˜Jšœ%œœ˜AJšœœœ˜!Jšœœœ˜Jšœœœ˜Jšœ˜—Jšœ œ9˜JJšœ˜J˜—Jšœœ˜-Jšœ œ˜+Jšœœœ˜Jšœœœ˜Jšžœœ$˜=Jšžœœ˜3Jšžœœ'˜CJšžœœ$˜=Jšœœ˜!Jšœ œ˜'Jšœœ˜!J˜Jšœœœ ˜šœ œœ˜Jšœœ œœ˜%Jšœ˜J˜—šœœœ˜Jšœ œ˜ Jšœ˜Jšœ˜J˜—Jšœœ˜Jšœ œœ˜%šœœœ˜Jšœœ˜Jš œœœœœ˜#Jšœœœ˜'Jšœ˜J˜—š œœœ œœ˜2Jšœ œÏc%˜7Jšœ œœ˜Jšœœ˜Jšœ?˜?Jšœ'˜'Jšœ˜J˜—Jšœœ˜Jšœœœ˜/šœœœ˜#Jšœ œŸ(˜9Jšœ œœ˜JšœœŸ%˜2Jšœœ˜Jšœ œ œœ˜7Jšœ˜J˜—Jšœœ#˜6šœœœ˜%Jšœ˜Jšœ˜Jšœœ˜Jšœœ˜Jšœ˜Jšœ˜J˜—Jšœ œœœ ˜&šœ œœœ˜"Jšœ œ˜Jšœ˜Jšœœœ˜0Jšœœœ˜Jšœœ˜!Jšœ%˜%Jšœœœ˜Jšœœœ˜Jšœœœ˜Jšœœ˜Jšœœ˜Jšœ œ˜Jšœ œ˜Jšœ œ˜Jšœ œ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœ!˜!Jšœœœ˜Jšœ˜J˜—šžœœœ œYœ œ œœœœ˜õJšœœ˜ Jšœ œ˜Jšœ˜Jšœ'˜'Jšœ)˜)Jšœ)˜)Jšœ:˜:Jšœ:˜:Jšœ%˜%Jšœ˜Jšœ˜Jšœœ ˜'Jšœ$˜$Jšœœ˜"Jšœ(˜(Jšœœ˜Jšœœ˜$JšœY˜YJšœœ˜.Jšœ2˜2šœ˜J™=—Jšœ˜J˜—š žœœœ'œœœ˜uJšœ*˜*Jšœ.˜.Jšœ˜J˜—š ž œœœ/œœœ˜mJšœ˜Jšœ˜Jšœ˜Jšœœ˜ Jšœœ˜ š œ œœœ˜,šœ œ˜šœœœ˜ Jšœœ+˜AJšœ˜—Jšœœœ˜?Jšœ˜Jšœ˜—šœ˜Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜—Jš˜—Jšœ˜J˜—šž œœœ%˜=Jšœœœœ˜(JšœT˜TJšœ(œ˜CJšœ@˜@Jšœ)œ˜.Jšœ˜J˜—šž œœœ%˜?Jšœœœœ˜(JšœT˜TJšœ(œ˜CJšœB˜BJšœ)œ˜.Jšœ˜J˜—šž œœœ%˜=Jšœ)œ˜/Jšœ˜J˜—šž œœœJœ˜lJšœC˜CJšœk˜kJšœ œ.˜:Jšœœœœ˜`Jšœ œœ˜-Jšœœœœ˜(šœ"˜"Jšœ˜Jšœœœ˜EJšœ'˜'Jšœ#˜#Jšœ ˜ Jšœ˜—Jšœ˜J˜—šžœœœœ ˜Ešœœ)˜>Jšœœ ˜*Jšœ˜—Jšœ˜J˜—š ž œœœœœ˜LJšœ!˜!Jšœ!˜!Jšœ˜J˜—š ž œœœ œœœ˜gJš œœœœœ˜GJšœ œ˜/Jšœ<˜šœ(œ˜0Jšœœœ ˜DJšœ!˜!Jšœ!œ˜=Jšœ"œ˜Dšœœ œ˜>Jšœ˜Jšœ!œ˜=Jšœ"œ˜DJšœ˜—Jšœ˜—Jšœ˜—Jšœ˜J˜—šž œœœ!œœœœ˜†Jš œœœœœ˜GJšœ œ˜/Jšœ<˜šœ(œ˜0Jšœœœ ˜DJšœ!˜!Jšœ!œ˜=Jšœ"œ˜Dšœœ œ˜>Jšœ˜Jšœ!œ˜=Jšœ"œ˜DJšœ˜—Jšœ˜—Jšœ˜—Jšœ˜J˜—š žœœœ5œœœ˜uJšœF˜FJšœk˜kJšœT˜Tšœ%˜%Jšœ%˜%Jšœ ˜ Jšœ ˜ Jšœ˜—JšœœœœK˜jJš œœœœœ˜WJšœ œ˜/Jšœ#œœ˜0Jšœ˜JšœN˜Nšœœ)˜>šœ(œ˜0Jšœœœ ˜DJšœ!˜!Jšœ!œ˜=Jšœœ˜Ašœœ œ˜>Jšœ˜Jšœ!œ˜=Jšœœ˜AJšœ˜—Jšœ˜—Jšœ˜—Jšœ˜J˜—šž œœœœœ œ œ)œ˜žJšœ:˜:Jšœ œ˜/Jšœœ'˜8Jšœ˜Jšœ.˜.šœœ)˜>šœ(œ˜0Jšœœ˜Jšœœ˜Jšœœ˜š œœœœœ˜Bšœœ˜šœ"˜"Jšœ˜Jšœ ˜ Jšœ˜—Jšœœœœ˜Hšœ)˜)Jšœ-˜-Jšœ ˜ Jšœ˜—Jšœ˜Jšœ!œ˜=Jšœœ˜>Jšœ%œ˜EJšœ˜—Jšœ:˜:Jšœ(˜(J˜ Jšœ˜—Jšœ˜Jšœœœ˜#Jšœ œœ˜Jšœ˜—Jšœ˜—Jšœ˜J˜—š žœœœ6œœœ˜wJšœG˜GJšœk˜kJšœU˜Ušœ&˜&Jšœ%˜%Jšœ ˜ Jšœ ˜ Jšœ˜—Jš œ œœœœ6˜XJš œ œœœœ2˜TJš œœœœœ˜KJšœ œ˜/Jšœ$œœ˜1Jšœ˜Jšœ6˜6šœœ)˜>šœ(œ˜0Jšœœœ ˜DJšœ!˜!Jšœ!œ˜=Jšœœ ˜Bšœœ œ˜>Jšœ˜Jšœ!œ˜=Jšœœ ˜BJšœ˜—Jšœ˜—Jšœ˜—Jšœ˜J˜—šž œœœ9˜RJšœ œœ˜5Jšœ œ˜/šœœ œœ˜"Jšœ8˜8Jšœœ˜Jšœœ˜Jšœœœ œ˜+J˜—Jšœœ˜Jšœœ˜Jšœ œ˜Jšœ˜šž œœœ˜šœ œ˜šœœœ˜+Jšœ ˜ Jšœ œ˜%Jšœ˜—Jšœ/˜/Jš œ œœœœœ œ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜—Jšœ˜—šž œœœ˜%Jšœ$˜$Jšœ˜Jšœœ˜0Jšœ˜—šž œœœœ˜2Jšœœ ˜$Jšœ8œ˜?Jšœ˜Jšœ˜—šžœœœ˜Jšœ ˜ Jšœ œ˜%Jšœ$˜$Jšœ˜—šž œœœ˜2Jšœ œ˜"Jšœœœœœ%œœ!˜„Jšœœ ˜)Jšœœœ˜$Jšœœ œ œœœœ œœ ˜UJšœ˜šœ œœœ˜Jšœœœ˜Jš œœœœœ˜3Jšœ˜—Jšœ˜Jšœ*˜*Jšœ˜—šœœ)˜>šœ(œ˜0Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜—Jšœ˜—Jšœ˜J˜—šž œœœ&œœœ7œ˜§Jšœ.œœœ˜eJšœ œ˜/Jšœœ'˜8Jšœœ˜Jšœœ˜Jšœœ˜š žœœœœœ˜Ešœœ˜šœ"˜"Jšœ˜Jšœ ˜ Jšœ˜—Jšœœœœ ˜Fšœ)˜)Jšœ-˜-Jšœ ˜ Jšœ˜—Jšœ˜Jšœ&œ˜BJšœœ˜>Jšœ%œ˜EJšœ˜—Jšœ:˜:Jšœ(˜(J˜ Jšœ˜—šœ(œ˜0Jšœ˜Jšœ.˜.Jšœ˜Jšœœœ˜#Jšœ œœ˜J˜—Jšœ˜J˜—š žœœœœ œ˜JJšœ>˜>JšœœœBœ ˜uJšœ˜J˜—šžœœœ˜Išœœœ˜'Jšœ#œ#˜IJšœJ˜JJšœ'˜'Jšœ:˜AJšœ3˜3Jšœ˜Jšœ*˜*Jšœ˜—Jšœ˜ Jšœ˜J˜—Jšœœœœ˜!Jšœœ˜šž œœœ˜%šœ˜$J™5Jšœ$˜$—Jšœ˜J˜—š ž œœœ6œ"œ˜Jš œ œœœœ˜,Jšœ?˜?Jšœœ˜Jšœœ˜&Jšœœ˜'Jš œœœœœ˜9Jšœœ˜Jšœœœ˜šž œœœœ˜:JšœœœŸ.˜Qšœ˜Jšœœœ˜Jšœœ8˜MJšœ+˜/Jšœ"˜"Jšœœ˜Jšœ˜—Jšœœ˜Jšœœ œ œœœœ œœ ˜Ušœ œœœ˜Jšœœœ˜Jšœ$œœ˜;Jš œœœœœ˜3Jšœ˜—Jšœœœ˜Jšœ7˜7Jšœœ˜Jšœ˜—šœœ ˜Jšœ$™$—˜J™ —Jšœœœ˜Jšœ˜JšœœœN˜gšœ˜Jšœ ™ —šœ ˜ J™—Jšœ"˜"Jšœœ"˜BJšœ&˜&Jšœ2˜2šœ"˜"Jšœ˜Jšœ(˜(Jšœ&˜&Jšœ˜Jšœ˜Jšœ˜—Jšœ˜Jšœ˜J˜—šžœœœ"œ œœœ"œ˜›Jšœ?˜?Jš œœœœœ ˜'Jšœœ'˜8Jšœœ(˜2Jšœ œ˜/Jšœ œœ˜?Jšœ œ˜$Jšœ œœœB˜^Jš œ œœœœ(˜FJšœ%œœ˜2Jšœ˜Jšœ˜Jšœ@˜@Jšœ&˜&Jšœ2˜2šœ"˜"Jšœ˜Jšœ-˜-Jšœ+˜+Jšœ˜Jšœ˜Jšœ˜—Jšœ(˜(Jšœœ(˜HJšœ˜Jšœ˜J˜—šžœœœœœœ œœœ"œ˜ÀJšœ?˜?Jš œœœœœ ˜'Jšœœ'˜8Jšœœ(˜2Jšœ œ˜/Jšœ œœ˜8Jšœ œ˜$Jšœœœœ;˜PJš œ œœœœ(˜FJšœ%œœ˜2Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ@˜@Jšœ&˜&Jšœ2˜2šœ"˜"Jšœ˜Jšœ-˜-Jšœ+˜+Jšœ˜Jšœ˜Jšœ˜—Jšœ(˜(Jšœœ(˜HJšœ˜Jšœ˜J˜—šžœœœ˜+Jšœ œ-˜;Jšœ œJ˜VJšœœœœ˜1Jšœ œœœ(˜EJšœ œ˜!Jšœœ˜+Jšœ˜šœ œ)˜:Jšœ ˜ šœœ˜šœ˜Jšœ˜Jšœœ˜.Jšœœ˜/Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜—Jšœ.˜.Jšœ0˜0J˜—Jšœ˜—Jšœ-˜-Jšœ-˜-Jšœ(˜(Jšœœœ$˜HJšœ˜Jšœ˜J˜—šž œœœ˜-J™EJšœ œ-˜;Jšœ œJ˜VJšœœœœ˜1Jšœ œœœ(˜Ešœ œ)˜:Jšœ ˜ šœœœ˜.Jšœ˜Jšœ˜Jšœ&œ˜*Jš˜—Jšœ˜—šœœœ˜&J˜#Jšœ˜—Jšœ-˜-Jšœ-˜-Jšœ(˜(Jšœ˜J˜—šžœœœ˜)Jšœ*˜*Jšœ˜Jšœ˜Jšœ˜šœœœ˜&J˜#Jšœ$˜$Jšœ$œ˜*Jšœ˜—Jšœ˜J˜—šœ(œœ˜5J˜—šžœœœœ˜?Jšœœ˜,Jšœœ˜,Jšœœ˜,Jšœœ˜,Jšœ.œœ(˜bJšœ.œœ(˜bJšœ˜J˜—šžœœœœ˜TJšœ œ!˜-Jšœ$˜$Jšœœœœ˜WJšœ˜Jšœ"˜"Jšœ˜J˜—šž œœœœ˜MJšœ œ*˜6Jšœ0˜0Jšœ3˜3Jšœœ˜1JšœQ˜QJšœ œ!˜-Jšœ$˜$Jšœœœœ˜WJšœ˜Jšœ"˜"šœ!œ˜*Jšœ!˜!šœœ˜#Jšœ)œ˜EJšœ)œœ˜9J˜—Jšœi˜iJšœ˜—Jšœ˜J˜—šžœœ.œ˜NJšœ œœ˜/šœœœ˜&JšœT˜TJ™¡Jšœ˜—šœœ˜"Jšœ"˜$Jšœ˜Jšœ˜—Jšœn˜nJšœ˜Jšœ˜J˜—š ž œœœœ œœ˜ZJš œœœœœ ˜(JšœS˜Sšœ˜šœ1œ˜9Jšœ_˜_Jšœ ˜ Jšœ2˜2Jšœ˜Jšœ˜—šœ˜Jšœœ&˜0Jšœœœ˜*JšœN˜NJšœ˜Jšœ.˜.Jšœ˜Jšœ'˜'Jšœ˜—Jš˜—Jšœ˜J˜—šžœœœ˜7J™)šœ9˜@Jšœ?˜?Jšœœ9˜OJšœœœ˜4Jšœ œ{˜ŠJšœ(˜(Jšœ6˜6Jšœ&˜&Jšœ+˜+JšœF˜FJšœ˜—Jšœ˜J˜—š žœœœœœ˜IJšœœœ˜JšœAœœœ˜dJšœ˜J˜—šž œœœœ˜?Jšœœœ˜JšœAœœ˜_Jšœ˜J˜—šž œœœ˜0Jšœœœ˜%JšœAœ%˜jJšœ˜J˜—šžœœ;œ˜]Jšœ6˜6Jšœœœ ˜JšœAœ&˜kJšœ˜J˜—šžœœ˜Jšœ˜Jšœœ˜Jšœœ˜Jšœ ˜ Jšœ œ˜Jšœœ˜ Jšœ œ˜Jšœ ˜Jšœœ˜ š œœœ œœ˜0Jšœ˜Jšœ˜Jšœ˜—šœ ˜ Jšœ$˜$Jšœ¢˜¢Jšœ˜—Jšœœœ˜$JšœAœ˜dJšœ˜J˜—šž œœ5œœ˜UJ™3šœ œœ˜4Jšœ3˜3šœœœ˜Jš œœœœœ˜#J™%šœœ˜)Jšœœœœ˜,Jšœ=˜=Jšœ˜Jšœ˜Jšœ˜—šœœ˜Jšœ œœœ˜3Jšœœœ˜"Jšœ7˜7šœ˜ šœ'˜'Jšœ ˜ Jšœ˜Jšœ"˜"Jšœ˜——Jšœœ˜ Jšœ_˜_Jš œœœœ7œ˜KJšœ˜—Jšœ%œM˜zJšœ˜Jšœ˜—Jšœ&˜&Jšœ˜Jšœ˜—Jšœ˜J˜—Jšœ˜——…—zX