DIRECTORY Atom, CD, CDBasics, CDCells, CDDefaultProcs, CDEnvironment, CDImports, CDInstances, CDIO, CDVArrow, CDViewer, CDCurves, CDOps, CDPDPlot, CDProperties, CDPropertyTools, CDSequencer, CDValue, Commander, CStitching, IO, PeachPrint, PDFileFormat, PDFileWriter, Process, Real, Rope, RuntimeError USING [UNCAUGHT], TerminalIO, ViewerClasses, ViewerSpecs; CDPDPlotImpl: CEDAR MONITOR IMPORTS Atom, CD, CDBasics, CDCells, CDDefaultProcs, CDEnvironment, CDImports, CDInstances, CDIO, CDValue, CDVArrow, CDViewer, CDOps, CDProperties, CDPropertyTools, CDSequencer, Commander, CStitching, IO, PDFileWriter, PeachPrint, Process, Real, Rope, RuntimeError, TerminalIO EXPORTS CDPDPlot = BEGIN retry: CONDITION; plottingInProgress: BOOL _ FALSE; Enter: ENTRY PROC [d: CD.Design] = { ENABLE UNWIND => NULL; BROADCAST retry; --to make others call CheckAborted WHILE plottingInProgress DO WAIT retry; CDSequencer.CheckAborted[d]; --UNWIND IS CATCHED !!! ENDLOOP; plottingInProgress _ TRUE }; Leave: ENTRY PROC [] = { ENABLE UNWIND => NULL; plottingInProgress _ FALSE; BROADCAST retry }; lastTechPropKey: REF _ $CDxLastTechnology; --a property of the dd.stippleKey abortPlot: REF BOOL _ NEW[BOOL _ FALSE]; Toner: TYPE = PDFileFormat.Toner; -- {black, cyan, magenta, yellow, .. 15}; TonerKeys: TYPE = ARRAY Toner OF REF; LoadArray: TYPE = ARRAY Toner OF PDFileWriter.LoadReference; ColorDescription: TYPE = ARRAY CD.Layer OF REF LoadArray _ ALL[NIL]; noColor: PDFileWriter.LoadReference = LAST[PDFileWriter.LoadReference]; fullColor: PDFileWriter.LoadReference = noColor-1; tonerToKeyKeys: REF TonerKeys = NEW[TonerKeys _ ALL[NIL]]; DeviceDesc: TYPE = CDPDPlot.DeviceDesc; TaskDesc: TYPE = CDPDPlot.TaskDesc; PageMode: TYPE = {fixedPage, finiteStripe, anyStripe}; Stipple4: TYPE = ARRAY[0..4) OF [0..16); Stipple8: TYPE = ARRAY[0..8) OF [0..256); Stipple16: TYPE = ARRAY[0..16) OF CARDINAL; fiddleDevice: PUBLIC REF DeviceDesc _ NIL; error: ERROR = CODE; MakeDevice: PUBLIC PROC [key: ATOM] RETURNS [dd: REF DeviceDesc] = { ColorVersatec: PROC [dd: REF DeviceDesc] = { dd.deviceCode _ last; --does not yet has an assigned value, use "last" dd.sResolution _ 200; -- resolution (slow directition), pixels / inch dd.fResolution _ 200; -- resolution (fast direction), pixels / inch dd.imageFSize _ 8000; --for the wide-bed Versatec, length in the "fast" direction; dd.toners _ ALL[FALSE]; dd.toners[black] _ TRUE; dd.toners[cyan] _ TRUE; dd.toners[magenta] _ TRUE; dd.toners[yellow] _ TRUE; dd.bandSSize _ 64; -- number chosen because of buffer-size of versatec dd.overlap _ 300; -- number of pixels by which to overlap strips dd.maxPixPerLambda _ 20; -- maximum # of pixels to make lambda dd.pageMode _ anyStripe; dd.leftOverMode _ FALSE; dd.stippleKey _ $CDxVersatec; dd.name _ "color versatec"; }; InkJetC150: PROC [dd: REF DeviceDesc] = { dd.deviceCode _ VAL[10]; dd.sResolution _ 120; -- resolution (slow directition), pixels / inch dd.fResolution _ 120; -- resolution (fast direction), pixels / inch dd.imageFSize _ 1020; dd.toners _ ALL[FALSE]; dd.toners[black] _ TRUE; dd.toners[cyan] _ TRUE; dd.toners[magenta] _ TRUE; dd.toners[yellow] _ TRUE; dd.bandSSize _ 48; -- dd.overlap _ 30; -- number of pixels by which to overlap strips dd.maxPixPerLambda _ 20; -- maximum # of pixels to make lambda dd.pageMode _ finiteStripe; dd.pageSlowSize _ 1020; dd.leftOverMode _ FALSE; dd.stippleKey _ $CDxVersatec; dd.name _ "ink jet"; }; Color400: PROC [dd: REF DeviceDesc] = { dd.deviceCode _ VAL[9]; dd.sResolution _ 400; -- resolution (slow directition), pixels / inch dd.fResolution _ 400; -- resolution (fast direction), pixels / inch dd.imageFSize _ 4096; dd.toners _ ALL[FALSE]; dd.toners[black] _ TRUE; dd.toners[cyan] _ TRUE; dd.toners[magenta] _ TRUE; dd.toners[yellow] _ TRUE; dd.bandSSize _ 50; -- dd.overlap _ 30; -- number of pixels by which to overlap strips dd.maxPixPerLambda _ 240; -- maximum # of pixels to make lambda dd.pageMode _ fixedPage; dd.pageSlowSize _ 5500; dd.leftOverMode _ FALSE; dd.stippleKey _ $CDxC400; dd.name _ "Color400"; }; Puffin: PROC [dd: REF DeviceDesc] = { dd.deviceCode _ PDFileFormat.DeviceCode[puffin]; dd.sResolution _ 384; -- resolution (slow directition), pixels / inch dd.fResolution _ 384; -- resolution (fast direction), pixels / inch dd.imageFSize _ dd.fResolution * 17 / 2; dd.toners _ ALL[FALSE]; dd.toners[black] _ FALSE; dd.toners[cyan] _ TRUE; dd.toners[magenta] _ TRUE; dd.toners[yellow] _ TRUE; dd.bandSSize _ 16; -- dd.overlap _ 30; -- number of pixels by which to overlap strips dd.maxPixPerLambda _ 20; -- maximum # of pixels to make lambda dd.pageMode _ fixedPage; dd.pageSlowSize _ dd.sResolution*11; dd.leftOverMode _ TRUE; dd.stippleKey _ $CDxPuffin; dd.name _ "Puffin"; }; PlateMaker: PROC [dd: REF DeviceDesc] = { dd.deviceCode _ PDFileFormat.DeviceCode[last]; dd.sResolution _ 1200; -- resolution (slow directition), pixels / inch dd.fResolution _ 1200; -- resolution (fast direction), pixels / inch dd.imageFSize _ dd.fResolution * 17 / 2; dd.toners _ ALL[FALSE]; dd.toners[black] _ TRUE; dd.bandSSize _ 16; -- dd.overlap _ 30; -- number of pixels by which to overlap strips dd.maxPixPerLambda _ 20; -- maximum # of pixels to make lambda dd.pageMode _ fixedPage; dd.pageSlowSize _ dd.sResolution*11; dd.leftOverMode _ TRUE; dd.stippleKey _ $CDxPDPlotPlatemaker; dd.name _ "platemaker [color separation]"; }; Raven384: PROC [dd: REF DeviceDesc] = { dd.deviceCode _ PDFileFormat.DeviceCode[raven]; dd.sResolution _ 384; -- resolution (slow directition), pixels / inch dd.fResolution _ 384; -- resolution (fast direction), pixels / inch dd.imageFSize _ dd.fResolution * 17 / 2; dd.toners _ ALL[FALSE]; dd.toners[black] _ TRUE; dd.bandSSize _ 16; -- dd.overlap _ 30; -- number of pixels by which to overlap strips dd.maxPixPerLambda _ 20; -- maximum # of pixels to make lambda dd.pageMode _ fixedPage; dd.pageSlowSize _ dd.sResolution*11; dd.leftOverMode _ TRUE; dd.stippleKey _ $CDxPDPlotRaven384; dd.name _ "Raven384 [color separation]"; }; dd _ NEW[DeviceDesc]; dd.contextFilter _ NEW[CD.ContextFilter_ALL[TRUE]]; SELECT key FROM $Versatec, $PDPlotVersatec => ColorVersatec[dd]; $C150, $PDPlotC150 => InkJetC150[dd]; $Puffin, $PDPlotPuffin => Puffin[dd]; $Platemaker, $PDPlotPlatemaker => PlateMaker[dd]; $Raven384, $PDPlotRaven384 => Raven384[dd]; $Color400, $PDPlotColor400 => Color400[dd]; $UserDevice, $PDPlotUserDevice => dd _ fiddleDevice; ENDCASE => ERROR error; }; PlotState: TYPE = REF PlotStateRec; PlotStateRec: TYPE = RECORD [ tes: ARRAY CD.Layer OF CStitching.Tesselation _ ALL[NIL], plotScale: REAL _ 1.0, -- pixels per CD.Number plotClip: CD.Rect _ [0, 0, 0, 0], --in design space touching all geometry in plot stripeClip: CD.Rect _ [0, 0, 0, 0],--in design space touching all geometry in stripe bandClip: CD.Rect _ [0, 0, 0, 0],--in design space touching all geometry in band pdState: PDFileWriter.PDState, colorLoads: REF ColorDescription, anouncedLayer: INT _ -1, design: CD.Design, band: CD.Rect _ [0, 0, 0, 0], -- in device pixel coordinates but y-sign inversion not yet done dd: REF DeviceDesc ]; ToDeviceX: PROC[ps: PlotState, cdX: CD.Number] RETURNS [REAL] = INLINE { RETURN [(cdX-ps.stripeClip.x1)*ps.plotScale] }; ToDeviceY: PROC[ps: PlotState, cdY: CD.Number] RETURNS [REAL] = INLINE { RETURN [(cdY-ps.stripeClip.y1)*ps.plotScale] }; ToDeviceR: PROC[ps: PlotState, r: CD.Rect] RETURNS [CD.Rect] = INLINE { RETURN [[ x1: Real.Round[ToDeviceX[ps, r.x1]], y1: Real.Round[ToDeviceY[ps, r.y1]], x2: Real.Round[ToDeviceX[ps, r.x2]], y2: Real.Round[ToDeviceY[ps, r.y2]] ]] }; ConvertY2: PROC[ps: PlotState, y2: CD.Number] RETURNS [INT] = INLINE { RETURN [ps.dd.imageSSize-1-y2] }; Plot: PUBLIC PROC [task: REF TaskDesc] = { ps: PlotState; clipSize: CD.Position; dd: REF DeviceDesc _ task.dd; design: CD.Design _ task.design; instance: CD.Instance _ task.instance; pageStep: CD.Position; pageWidth: CD.Position; dr: CD.DrawRef; IF design=NIL OR dd=NIL THEN ERROR; BEGIN ENABLE { -- for ERRORs UNWIND => { CDVArrow.RemoveArrow[design]; TerminalIO.PutRope[" ** plot aborted **\n"]; Leave[]; }; }; Enter[design]; TRUSTED {Process.SetPriority[Process.priorityBackground]}; task.strips _ MAX[1, MIN[10, task.strips]]; IF task.abort=NIL THEN task.abort _ NEW[BOOL_FALSE]; IF ~CDBasics.NonEmpty[task.clip] THEN task.clip _ CDOps.BoundingBox[design]; clipSize _ CDBasics.SizeOfRect[task.clip]; dr _ CD.CreateDrawRef[[ design: design, selections: FALSE, borders: TRUE, fontSubstitution: task.substituteFonts, stopFlag: task.abort, drawRect: NoteRectangle, drawChildSel: CDDefaultProcs.IgnoreChild, drawOutLine: DrawOutline, contextFilter: dd.contextFilter ]]; SetStipples[dd, design.technology]; CheckSpecialScale[task]; ps _ NEW[PlotStateRec _ [ plotClip: task.clip, colorLoads: NEW[ColorDescription _ ALL[NIL]], design: design, plotScale: task.scale, dd: dd ]]; IF ps.plotScale<=0 THEN { ps.plotScale _ MIN[ REAL[dd.maxPixPerLambda] / design.technology.lambda, REAL[(dd.imageFSize-dd.overlap)*task.strips+dd.overlap] / clipSize.x ] }; dd.imageSSize _ Real.InlineRoundC[clipSize.y*ps.plotScale]+1; IF dd.pageMode=fixedPage THEN { dd.imageSSize _ MIN[dd.imageSSize, dd.pageSlowSize]; ps.plotScale _ MIN[ps.plotScale, REAL[dd.pageSlowSize]/(clipSize.y+1)]; }; pageStep _ [(clipSize.x+task.strips-1)/task.strips, clipSize.y]; pageWidth _ [Real.Round[dd.imageFSize/ps.plotScale]+1, clipSize.y]; --larger to prevent rounding errors dr.devicePrivate _ ps; TerminalIO.PutRopes["start ploting\n"]; FOR strip: INT IN [0..task.strips) DO fileName: Rope.ROPE _ MakeName[task.fileName, strip, task.strips]; ps.stripeClip _ [ --but not yet intersected with complete design clip x1: ps.plotClip.x1+strip*pageStep.x, y1: ps.plotClip.y1, x2: ps.plotClip.x1+strip*pageStep.x+pageWidth.x, y2: ps.plotClip.y2 ]; ps.pdState _ PDFileWriter.Create[ fileName: fileName, deviceCode: dd.deviceCode, sResolution: dd.sResolution, fResolution: dd.fResolution, imageSSize: (IF dd.pageMode=fixedPage THEN dd.pageSlowSize ELSE dd.imageSSize), imageFSize: dd.imageFSize, bandSSize: dd.bandSSize, leftOverMode: dd.leftOverMode, maxLoadWords: dd.maxLoadWords, copies: dd.copies ]; CDDefaultProcs.ConvertContextsToDeviceRects[ pr: dr, dDrawRect: NoteDeviceRectangle, dOrigin: [ps.stripeClip.x1, ps.stripeClip.y1], scale: ps.plotScale ]; ps.colorLoads^ _ ALL[NIL]; PDFileWriter.StartImage[pdState: ps.pdState, toners: dd.toners]; FOR bandYtop: INT _ dd.imageSSize, bandYtop-dd.bandSSize WHILE bandYtop>0 DO dc: CD.Rect; --task.clip for band in design coordinates; little larger than band CDSequencer.CheckAborted[design]; dc _ [ x1: ps.stripeClip.x1-1, y1: ps.stripeClip.y1+Real.Round[(bandYtop-dd.bandSSize)/ps.plotScale]-2, x2: ps.stripeClip.x1+pageWidth.x+1, y2: ps.stripeClip.y1+Real.Round[bandYtop/ps.plotScale]+2 ]; dr.interestClip _ ps.bandClip _ CDBasics.Intersection[ps.plotClip, dc]; ps.band _ [ x1: 0, y1: MAX[0, bandYtop-dd.bandSSize], x2: MIN[Real.Round[ToDeviceX[ps, ps.bandClip.x2]+1], ps.dd.imageFSize], y2: bandYtop ]; IF instance=NIL THEN CDVArrow.ShowArrow[design, CDBasics.Center[dr.interestClip]]; ps.anouncedLayer _ -1; FOR l: CD.Layer IN CD.Layer DO IF ps.tes[l]#NIL THEN CStitching.ChangeRect[plane: ps.tes[l], rect: CDBasics.universe, new: NIL]; ENDLOOP; -- build tesselations of design rectangles IF instance=NIL THEN CDOps.DrawDesign[design, dr] ELSE CD.DrawOb[dr, instance.ob, instance.trans, instance.properties]; AnalyzeTesselations[ps]; -- actually draw tesselations TerminalIO.PutRope["."]; ENDLOOP; -- each band in the strip PDFileWriter.EndPage[ps.pdState]; PDFileWriter.Close[ps.pdState]; TerminalIO.PutRopes["*\nrecorded strip on file ", fileName, "\n"]; ENDLOOP; -- each strip TerminalIO.PutRope[" finished plot\n"]; CDVArrow.RemoveArrow[design: design]; Leave[]; END; }; MaskRect: PROC [ps: PlotState, r: CD.Rect] = --INLINE-- { debugBand: CD.Rect _ ps.band; debugR: CD.Rect _ r; IF CDBasics.Intersect[r, ps.band] THEN { r _ CDBasics.Intersection[r, ps.band]; IF r.x2>r.x1 AND r.y2>r.y1 THEN PDFileWriter.MaskRectangle[pdState: ps.pdState, sMin: ConvertY2[ps, r.y2-1], fMin: r.x1, sSize: r.y2-r.y1, fSize: r.x2-r.x1]; } }; ProcessTile: PROC [tile: CStitching.Tile, data: REF ANY] = { IF tile.value=$covered THEN { ps: PlotState = NARROW[data]; MaskRect[ps, CStitching.Area[tile]] }; }; AnalyzeTesselations: PROC [ps: PlotState] = { FOR lev: CD.Layer IN CD.Layer DO IF ps.tes[lev]#NIL THEN { SetColor[ps, lev]; CStitching.EnumerateArea[plane: ps.tes[lev], rect: ps.band, eachTile: ProcessTile, data: ps, skip: NIL]; }; ENDLOOP; }; NoteRectangle: PROC [pr: CD.DrawRef, r: CD.Rect, l: CD.Layer] = { ps: PlotState = NARROW[pr.devicePrivate]; IF ps.dd.contextFilter[l] THEN { r _ CDBasics.Intersection[r, pr.interestClip]; IF CDBasics.NonEmpty[r] THEN { r _ ToDeviceR[ps, r]; IF ps.tes[l]=NIL THEN ps.tes[l] _ CStitching.NewTesselation[]; CStitching.ChangeRect[plane: ps.tes[l], rect: r, new: $covered]; }; }; }; NoteDeviceRectangle: PROC [pr: CD.DrawRef, r: CD.Rect, l: CD.Layer] = { ps: PlotState = NARROW[pr.devicePrivate]; IF ps.dd.contextFilter[l] THEN { r _ CDBasics.Intersection[r, ps.band]; IF CDBasics.NonEmpty[r] THEN { IF ps.tes[l]=NIL THEN ps.tes[l] _ CStitching.NewTesselation[]; CStitching.ChangeRect[plane: ps.tes[l], rect: r, new: $covered]; }; }; }; DrawOutline: CD.DrawRectProc = { --PROC [r: Rect, l: Layer, pr: DrawRef] delta: INT = 8;--doesn't cause overflow, plot scale is limited ps: PlotState = NARROW[pr.devicePrivate]; r.x1 _ MAX[pr.interestClip.x1-delta, r.x1]; --r in cd Coordinates r.y1 _ MAX[pr.interestClip.y1-delta, r.y1]; r.x2 _ MIN[pr.interestClip.x2+delta, r.x2]; r.y2 _ MIN[pr.interestClip.y2+delta, r.y2]; r _ ToDeviceR[ps, r]; NoteDeviceRectangle[pr, [r.x1, r.y1, r.x2+1, r.y1+1], l]; --bottom NoteDeviceRectangle[pr, [r.x1, r.y2-1, r.x2+1, r.y2], l]; --top NoteDeviceRectangle[pr, [r.x1, r.y1, r.x1+1, r.y2+1], l]; --left NoteDeviceRectangle[pr, [r.x2-1, r.y1, r.x2, r.y2+1], l]; --right }; CheckSpecialScale: PROC [task: REF TaskDesc] = { micronsPerInch: REAL ~ 25400; specialScale: REAL _ -1; --means microns on plotted device per lambda WITH CDProperties.GetAtomProp[task.dd.stippleKey, $CDxPDPlotScale] SELECT FROM ri: REF INT => specialScale _ ri^; rr: REF REAL => specialScale _ rr^; ENDCASE => specialScale _ -1; IF specialScale>0 THEN { size: CD.Position _ CDBasics.SizeOfRect[task.clip]; task.scale _ specialScale*task.dd.sResolution/micronsPerInch/task.design.technology.lambda; TerminalIO.PutF["plotting at special scale %g microns/lambda [%g pixels/chipndaleUnit]\n", [real[specialScale]], [real[task.scale]]]; IF task.dd.pageMode=fixedPage THEN { IF task.scale > REAL[task.dd.pageSlowSize]/(size.y+1) THEN TerminalIO.PutRope["doesn't fit on page; must change scale\n"]; }; }; }; RequestClipRect: PROC [comm: CDSequencer.Command] RETURNS [clip: CD.Rect, inst: CD.Instance _ NIL] = { n: INT; n _ TerminalIO.RequestSelection[header: "plot area", choice: LIST["plot complete design", "plot drawn rectangle", "plot like viewer", "plot area of selection", "plot selection only"] ]; SELECT n FROM 1 => { clip _ CDBasics.Extend[CDOps.BoundingBox[comm.design], 2]; TerminalIO.PutRope["plot complete design\n"]; }; 2 => { clip _ CDBasics.ToRect[comm.pos, comm.sPos]; TerminalIO.PutRope["plot rectangle of command\n"]; }; 3 => { clip _ CDViewer.VisibleRect[CDViewer.GetViewer[comm]]; TerminalIO.PutRope["plot as viewed\n"]; }; 4 => { clip _ CDBasics.Extend[CDOps.BoundingBox[comm.design, TRUE], 2]; TerminalIO.PutRope["plot area of selection\n"]; }; 5 => { sel: CD.InstanceList _ NIL; design: CD.Design _ comm.design; TerminalIO.PutRope["plot selection only\n"]; FOR l: CD.InstanceList _ CDOps.InstList[design], l.rest WHILE l#NIL DO IF l.first.selected THEN sel _ CONS[l.first, sel] ENDLOOP; IF sel=NIL THEN { TerminalIO.PutRope["no selection\n"]; ERROR ABORTED }; inst _ CDInstances.NewInst[CDCells.CreateCellXTransformed[il: sel]]; clip _ CDBasics.Extend[CDInstances.InstRectO[inst], 2]; }; ENDCASE => ERROR ABORTED; IF ~CDBasics.NonEmpty[clip] THEN { TerminalIO.PutRope["clip rectangle is empty\n"]; ERROR ABORTED }; }; SubstituteFonts: PROC [] RETURNS [substituteFonts: BOOL] = { n: INT; n _ TerminalIO.RequestSelection[header: "substitute tioga fonts", headerDoc: "do for schematics; don't for layout", choice: LIST["yes", "no"] ]; substituteFonts _ n#2 }; IgnoreCommentLayer: PROC [] RETURNS [ignoreComment: BOOL] = { n: INT; n _ TerminalIO.RequestSelection[header: "suppress comment layer", headerDoc: "do for large layouts; don't for anything else", choice: LIST["yes", "no"] ]; ignoreComment _ n=1 }; Stripes: PROC [allowStripes: BOOL] RETURNS [n: INT_1] = { IF allowStripes THEN { choice: INT; choice _ TerminalIO.RequestSelection[header: "plot multiple vertical strips", headerDoc: "it's ok not to...", choice: LIST["yes", "no"] ]; IF choice=1 THEN { n _ TerminalIO.RequestInt["How many vertical strips? [1..10] "]; IF n<1 OR n>10 THEN { TerminalIO.PutRope["unreasonable number of stripes\n"]; ERROR ABORTED }; }; }; }; cnt: INT _ 0; PDColorPlotComm: PROC [comm: CDSequencer.Command] = { ENABLE error => { SELECT TerminalIO.RequestSelection["ERROR", LIST["abort plot", "reset and abort plot", "debug"]] FROM 1 => GOTO tobad; 2 => {currTech _ NIL; GOTO tobad}; 3 => REJECT; ENDCASE => GOTO tobad; }; clip: CD.Rect; mustSendToDevice: BOOL _ FALSE; server: Rope.ROPE; copies: INT _ 1; task: REF TaskDesc _ NEW[TaskDesc _ [design: comm.design, abort: abortPlot, strips: 1]]; TerminalIO.PutRope["Color plot\n"]; task.dd _ MakeDevice[comm.key]; IF task.dd=NIL THEN { TerminalIO.PutRope["no device specified\n"]; RETURN }; TerminalIO.PutRopes[task.dd.name, "\n"]; IF CDImports.HasUnloadedImports[comm.design].yes THEN { TerminalIO.PutRope["design has unloaded imports\n"]; IF ~TerminalIO.Confirm["unloaded imports, continue anyway", "you would better load imports first", 20] THEN ERROR ABORTED; }; [clip, task.instance] _ RequestClipRect[comm]; task.substituteFonts _ SubstituteFonts[]; IF IgnoreCommentLayer[] THEN task.dd.contextFilter[CD.commentLayer] _ FALSE; task.strips _ Stripes[task.dd.pageMode=anyStripe]; BEGIN default: Rope.ROPE _ NIL; choice: LIST OF Rope.ROPE _ LIST["no", "type name of server"]; IF comm.key=$PDPlotVersatec THEN default _ "Sleepy" ELSE IF comm.key=$PDPlotColor400 THEN default _ "MtFuji"; IF default#NIL THEN choice.rest.rest _ LIST[default]; SELECT TerminalIO.RequestSelection["send immediately to server", choice] FROM 0, 1 => NULL; 2 => { mustSendToDevice _ TRUE; server _ TerminalIO.RequestRope["server name>"]; }; 3 => { mustSendToDevice _ TRUE; server _ default; }; ENDCASE => NULL; IF mustSendToDevice THEN { IF TerminalIO.Confirm["multiple copies"] THEN copies _ TerminalIO.RequestInt["copies>"]; IF copies<1 OR copies>10 THEN { TerminalIO.PutRope["unreasonable number of copies\n"]; ERROR ABORTED }; }; END; IF clip.x1>=clip.x2 OR clip.y1>=clip.y2 THEN { TerminalIO.PutRope["**cannot plot empty area\n"]; ERROR ABORTED }; task.clip _ clip; IF mustSendToDevice THEN task.fileName _ IO.PutFR["///temp/chipndale/pdplots/Plot%gX.pd", IO.int[cnt _ cnt+1]]; Plot[task]; IF mustSendToDevice THEN { CDEnvironment.ExecFileEntry[key: "PeachPrint"]; --should load file; PeachPrint loaded only on demand FOR strip: INT IN [0..task.strips) DO PeachPrint.DoPeachPrintCommand[ server: server, file: MakeName[task.fileName, strip, task.strips], log: TerminalIO.TOS[], copies: copies, fork: TRUE ! PeachPrint.PupAborted => {TerminalIO.PutRope["**Pup aborted plotting\n"]; CONTINUE}; RuntimeError.UNCAUGHT => {TerminalIO.PutRope["**Peach aborted plotting\n"]; CONTINUE}; ]; ENDLOOP }; EXITS tobad => NULL }; MakeName: PROC [base: Rope.ROPE, strip, strips: INT_1] RETURNS [fileName: Rope.ROPE] = { modifier: Rope.ROPE _ IF strips>1 THEN IO.PutFR["%d", IO.int[strip+1]] ELSE NIL; IF Rope.IsEmpty[base] THEN base _ "PDPlot"; fileName _ CDIO.MakeName[wDir: "///temp/", base: base, modifier: modifier, ext: "pd"]; }; WaitPlotFinishedCommand: Commander.CommandProc = { prio: Process.Priority = Process.GetPriority[]; IF ~plottingInProgress THEN { IO.PutRope[cmd.out, " waiting for plot to start"]; WHILE ~plottingInProgress DO Process.Pause[Process.SecondsToTicks[1]]; ENDLOOP; IO.PutRope[cmd.out, ". plot started...\n"] }; Process.SetPriority[Process.priorityBackground]; WHILE plottingInProgress DO Process.Pause[Process.SecondsToTicks[2]]; ENDLOOP; Process.SetPriority[prio]; IO.PutRope[cmd.out, " finished\n"] }; blackX: REF _ NIL; cyanX: REF _ NIL; yellowX: REF _ NIL; magentaX: REF _ NIL; currTech: CD.Technology _ NIL; currLayer: CD.Layer _ CD.undefLayer; Forgett: PROC [l: CD.Layer] = { IF blackX#NIL THEN CDProperties.PutLayerProp[onto: l, prop: blackX, val: NIL]; IF cyanX#NIL THEN CDProperties.PutLayerProp[onto: l, prop: cyanX, val: NIL]; IF magentaX#NIL THEN CDProperties.PutLayerProp[onto: l, prop: magentaX, val: NIL]; IF yellowX#NIL THEN CDProperties.PutLayerProp[onto: l, prop: yellowX, val: NIL]; }; Start: PUBLIC PROC[tech, device, b, c, m, y: ATOM, text: Rope.ROPE_NIL, invert: BOOL_FALSE] = { IF currTech#NIL THEN ERROR error; CDPropertyTools.RemoveProperties[$CDxPDPlotScale]; CDPropertyTools.RemoveProperties[device]; CDProperties.PutAtomProp[device, $CDxPDPlotScale, NIL]; --might be not associated IF b#NIL THEN CDPropertyTools.RemoveProperties[b]; IF c#NIL THEN CDPropertyTools.RemoveProperties[c]; IF m#NIL THEN CDPropertyTools.RemoveProperties[m]; IF y#NIL THEN CDPropertyTools.RemoveProperties[y]; currTech _ CD.FetchTechnology[tech]; blackX _ b; cyanX _ c; yellowX _ y; magentaX _ m; CDValue.Store[currTech, device, text]; IF invert THEN { CDProperties.PutAtomProp[device, tonerToKeyKeys[black], yellowX]; CDProperties.PutAtomProp[device, tonerToKeyKeys[cyan], magentaX]; CDProperties.PutAtomProp[device, tonerToKeyKeys[yellow], blackX]; CDProperties.PutAtomProp[device, tonerToKeyKeys[magenta], cyanX]; } ELSE { CDProperties.PutAtomProp[device, tonerToKeyKeys[black], blackX]; CDProperties.PutAtomProp[device, tonerToKeyKeys[cyan], cyanX]; CDProperties.PutAtomProp[device, tonerToKeyKeys[yellow], yellowX]; CDProperties.PutAtomProp[device, tonerToKeyKeys[magenta], magentaX]; }; CDProperties.PutAtomProp[device, $CDxLastTechnology, currTech.key]; FOR l: CD.Layer IN CD.Layer DO Forgett[l] ENDLOOP; }; End: PUBLIC PROC [] = { currTech _ NIL }; Layer: PUBLIC PROC [uniqueKey: ATOM] = { currLayer _ CD.FetchLayer[t: currTech, uniqueKey: uniqueKey]; Forgett[currLayer] }; LayerNumber: PUBLIC PROC [layer: NAT] = { currLayer _ layer; Forgett[currLayer] }; Color1: PUBLIC PROC [key: ATOM] = { CDProperties.PutLayerProp[onto: currLayer, prop: key, val: $ink] }; Color4: PUBLIC PROC [key: ATOM, i0, i1, i2, i3: [0..16)] = { CDProperties.PutLayerProp[onto: currLayer, prop: key, val: IF i0=0 AND i1=0 AND i2=0 AND i3=0 THEN NIL ELSE IF i0=15 AND i1=15 AND i2=15 AND i3=15 THEN $ink ELSE NEW[Stipple4 _ [i0, i1, i2, i3]] ] }; Color8: PUBLIC PROC [key: ATOM, i0, i1, i2, i3, i4, i5, i6, i7: [0..256)] = { CDProperties.PutLayerProp[onto: currLayer, prop: key, val: IF i0=0 AND i1=0 AND i2=0 AND i3=0 AND i4=0 AND i5=0 AND i6=0 AND i7=0 THEN NIL ELSE IF i0=255 AND i1=i0 AND i2=i0 AND i3=i0 AND i4=i0 AND i5=i0 AND i6=i0 AND i7=i0 THEN $ink ELSE NEW[Stipple8 _ [i0, i1, i2, i3, i4, i5, i6, i7]] ] }; Init: PROC [] = { CDPropertyTools.Associate[$CDxPDPlotScale, $CDxPDPlotScale]; tonerToKeyKeys[black] _ $CDxPDPlotBlack; tonerToKeyKeys[cyan] _ $CDxPDPlotCyan; tonerToKeyKeys[magenta] _ $CDxPDPlotMagenta; tonerToKeyKeys[yellow] _ $CDxPDPlotYellow; CDSequencer.ImplementCommand[key: $PDPlotVersatec, proc: PDColorPlotComm, queue: doQueue]; CDSequencer.ImplementCommand[key: $PDPlotC150, proc: PDColorPlotComm, queue: doQueue]; CDSequencer.ImplementCommand[key: $PDPlotColor400, proc: PDColorPlotComm, queue: doQueue]; CDSequencer.ImplementCommand[key: $PDPlotUserDevice, proc: PDColorPlotComm, queue: doQueue]; Commander.Register[ key: "///Commands/CDWaitPlotFinished", proc: WaitPlotFinishedCommand, doc: "waits until ChipNDale pd plotting is finished once" ]; TerminalIO.PutRope["ChipNDale PD color plot program loaded\n"]; }; SetStipples: PROC [dd: REF DeviceDesc, technology: CD.Technology] = { PrepareContextFilter: PROC [dd: REF DeviceDesc] = { FOR l: CD.Layer IN CD.Layer DO IF dd.contextFilter^[l] THEN { color: BOOL _ FALSE; FOR toner: Toner IN Toner DO IF dd.tonerToKey[toner]#NIL THEN IF CDProperties.GetLayerProp[l, dd.tonerToKey[toner]]#NIL THEN { color _ TRUE; EXIT }; ENDLOOP; dd.contextFilter^[l] _ color } ENDLOOP; }; IF dd.stippleKey=NIL THEN { TerminalIO.PutRope["device has undefined stipple key\n"]; ERROR ABORTED }; IF technology.key#CDProperties.GetAtomProp[dd.stippleKey, lastTechPropKey] THEN { TerminalIO.PutRope["try to load the stipples\n"]; CDEnvironment.ExecFileEntry[Rope.Cat["PDPlot-stipples-", Atom.GetPName[dd.stippleKey], "-", technology.name], NIL, NIL]; TerminalIO.PutRope["stipples loaded; please check whether any errors occured\n"]; }; WITH CDValue.Fetch[technology, dd.stippleKey] SELECT FROM r: Rope.ROPE => TerminalIO.PutRopes["color stipples used: [", r, "]\n"]; ENDCASE => { TerminalIO.PutRope["**color stipples are not defined\n"]; ERROR ABORTED }; IF technology.key#CDProperties.GetAtomProp[dd.stippleKey, lastTechPropKey] THEN { TerminalIO.PutRope["**Warning: another technology registered in the meantime; the technology independent stipples are redefined\n"]; }; dd.tonerToKey _ NEW[TonerKeys _ ALL[NIL]]; FOR t: PDFileWriter.Toner IN PDFileWriter.Toner DO dd.tonerToKey^[t] _ CDProperties.GetAtomProp[dd.stippleKey, tonerToKeyKeys[t]]; IF ~dd.toners[t] OR dd.tonerToKey^[t]=NIL THEN { dd.toners[t] _ FALSE; dd.tonerToKey^[t] _ NEW[INT]; } ENDLOOP; PrepareContextFilter[dd]; }; SetColor: PROC [ps: PlotState, lev: CD.Layer] = { MakeLoadref: PROC [pattern: REF ANY] RETURNS [loadRef: PDFileWriter.LoadReference] = TRUSTED { ToTexture: PROC [pattern: REF ANY] RETURNS [texture: Stipple16] = CHECKED { WITH pattern SELECT FROM s16: REF Stipple16 => texture _ s16^; s8: REF Stipple8 => FOR i: [0..8) IN [0..8) DO texture[i] _ texture[i+8] _ (256+1)*s8[i]; ENDLOOP; s4: REF Stipple4 => FOR i: [0..4) IN [0..4) DO texture[i] _ texture[i+4] _ texture[i+8] _ texture[i+12] _ s4[i]*1111H; ENDLOOP; ENDCASE => RETURN[Stipple16[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0FFFFH]]; -- error texture RETURN [texture] }; -- ToTexture IF pattern=NIL THEN loadRef _ noColor ELSE IF pattern=$ink THEN loadRef _ fullColor ELSE { texture: Stipple16 _ ToTexture[pattern]; loadRef _ PDFileWriter.LoadContiguousColorTile[pdState: ps.pdState, phase: 0, sMin: 0, fMin: 0, sSize: 16, fSize: 16, bitsPtr: @texture]; IF loadRef>=fullColor THEN ERROR; }; }; -- MakeLoadref MakeLoad: PROC [ps: PlotState, lev: CD.Layer] = INLINE { IF ps.colorLoads^[lev]=NIL THEN { ps.colorLoads^[lev] _ NEW[LoadArray]; FOR toner: Toner IN Toner DO tex: REF _ CDProperties.GetLayerProp[from: lev, prop: ps.dd.tonerToKey[toner]]; IF tex=NIL THEN ps.colorLoads^[lev][toner] _ noColor ELSE ps.colorLoads^[lev][toner] _ MakeLoadref[tex] ENDLOOP; }; }; --MakeLoad IF ps.anouncedLayer=lev THEN RETURN; IF ps.colorLoads^[lev]=NIL THEN MakeLoad[ps, lev]; FOR toner: Toner IN Toner DO IF ps.colorLoads^[lev][toner] = noColor THEN PDFileWriter.SetColorOff[ps.pdState, toner] ELSE IF ps.colorLoads^[lev][toner] = fullColor THEN PDFileWriter.SetColorInk[ps.pdState, toner] ELSE PDFileWriter.SetColorTile[ps.pdState, toner, ps.colorLoads^[lev][toner], transparent]; ENDLOOP; ps.anouncedLayer _ lev }; Init[]; END. >CDPDPlotImpl.mesa Copyright c 1985, 1986, 1987 by Xerox Corporation. All rights reserved. History Black and white versatec plot written by: E. McCreight, August 1, 1983 Changed for color Versatec by: Kim Rachmeler, 1983 Rewritten by: Christian Jacobi, April 11, 1985 3:21:48 pm PST Last Edited by: Christian Jacobi, November 9, 1987 10:17:19 am PST --MONITOR: to protect the stipples --handling colors -- used to identify tiles without toner so that you can avoid recording them -- used to identify tiles with full toner so that you can avoid recording them --gives a key to get the keys to get the color stipple as property of the layers --device description --state of plot --plot and stripe areas are defined in integral cd units --the band is defined in pixel units; -- bandClip contains at least all area contributing to the real band -- low border points are legal pixels of band, high border points are not --but not clipped! --but not clipped! --but not clipped! y2 in (non negated y) pixel coordinates; does the conversion of the y --Center the x range of the selected area of the design on the plotter bed, with at most dd.maxPixPerLambda pixels per lambda. If multiple task.strips are called for, overlap adjacent ones by "dd.toners" pixels. -- total number of pixels across plot = imageFSize+[imageFSize-overlap]*(strips-1)) -- For each band in the strip --bandYtop is top pixel not plotted ! -- Determine coordinate transformations --Display current band under consideration to pacify user -- clear previous tessalations --coordinates in devices pixel coordinates, but y not yet negated; --plots inclusive low, exclusive high border pixels --r in cd coords --r in device pixel coords; before changing y sign --restrict outline to be only slightly larger than device, to prevent arithmetic overflow --convert to device pixel coordinates --draw [doesn't draw 2 border pixels] --command level --plot parameters --direct sending to servers --interpreter set up --initializations --tries to convert pattern to a texture stipple --makes the load if it does not already exist --SetColor Κ"_˜codešœ™Kšœ Οmœ=™H™KšœG™GKšœ2™2Kšœ>™>K™B——K˜šΟk ˜ Kšœž˜Kšžœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ ˜ Kšžœ˜Kšœ ˜ Kšœ ˜ K˜ Kšœ˜Kšœ˜Kšœ˜Kšœ žœžœ˜Kšœ ˜ Kšœ˜Kšœ ˜ —K˜šΠbn œžœž˜Kš žœžœ2žœ žœ žœižœI˜”Kšžœ ˜—Kšž˜K˜KšŸΠbkŸ™"K˜Kšœž œ˜Kšœžœžœ˜!K˜šΟnœžœžœžœ ˜$Jšžœžœžœ˜Kšž œΟc"˜3šžœžœ˜Kšžœ˜ Kšœ’˜4Kšžœ˜—Kšœž˜Kšœ˜—K˜š‘œžœžœ˜Jšžœžœžœ˜Kšœžœ˜Kšž œ˜Kšœ˜—K˜Kšœžœ’!˜LKš œ žœžœžœžœžœ˜(K˜K˜KšΟb™K˜Kšœžœ’)˜LKš œ žœžœžœžœ˜%Kšœ žœžœžœ˜Kšœ˜Kšœžœ˜Kšœ˜Kšœ˜Kšœ˜—K˜š‘ œžœžœ˜)Kšœžœ˜Kšœ’/˜FKšœ’-˜DKšœ˜Kšœ žœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœ’˜Kšœ’.˜@Kšœ’%˜>Kšœ˜Kšœ˜Kšœžœ˜Kšœ˜Kšœ˜Kšœ˜—K˜š‘œžœžœ˜'Kšœžœ˜Kšœ’/˜FKšœ’-˜DKšœ˜Kšœ žœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœ’˜Kšœ’.˜@Kšœ’%˜?Kšœ˜Kšœ˜Kšœžœ˜Kšœ˜Kšœ˜Kšœ˜—K˜š‘œžœžœ˜%Kšœ2˜2Kšœ’/˜FKšœ’-˜DKšœ)˜)Kšœ žœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœ’˜Kšœ’.˜@Kšœ’%˜>Kšœ˜Kšœ$˜$Kšœžœ˜Kšœ˜Kšœ˜Kšœ˜—K˜š‘ œžœžœ˜)Kšœ0˜0Kšœ’/˜GKšœ’-˜EKšœ)˜)Kšœ žœžœ˜Kšœžœ˜Kšœ’˜Kšœ’.˜@Kšœ’%˜>Kšœ˜Kšœ$˜$Kšœžœ˜Kšœ%˜%Kšœ*˜*Kšœ˜—K˜š‘œžœžœ˜'Kšœ1˜1Kšœ’/˜FKšœ’-˜DKšœ)˜)Kšœ žœžœ˜Kšœžœ˜Kšœ’˜Kšœ’.˜@Kšœ’%˜>Kšœ˜Kšœ$˜$Kšœžœ˜Kšœ#˜#Kšœ(˜(Kšœ˜—K˜Kšœžœ ˜Kš œžœžœžœžœ˜3šžœž˜Kšœ0˜0Kšœ%˜%Kšœ%˜%Kšœ1˜1Kšœ+˜+Kšœ+˜+Kšœ4˜4Kšžœžœ˜—Kšœ˜—K˜K˜K˜Kš£™K˜Kšœ žœžœ˜#šœžœžœ˜Kš œžœžœžœžœžœ˜:Kšœ žœ’˜.Kšœ žœ’/˜QKšœ žœ’1˜Tšœ žœ’0˜QKš’8™8Kš’&™&Kšœ ’9™D—K˜Kšœ žœ˜!Kšœžœ˜Kšœžœ˜šœžœ’@˜^Kš’œF™I—Kšœžœ ˜Kšœ˜—K˜š ‘ œžœžœ žœžœžœ˜HKš’™Kšžœ'˜-K˜—K˜š ‘ œžœžœ žœžœžœ˜HKš’™Kšžœ'˜-K˜—K˜š ‘ œžœžœžœžœ žœ˜GKš’™šžœ˜ Kšœ$˜$Kšœ$˜$Kšœ%˜%Kšœ$˜$Kšœ˜—K˜—K˜š ‘ œžœžœ žœžœžœ˜FKšœE™EKšžœ˜K˜—K˜š‘œžœžœžœ˜*Kšœ˜Kšœ žœ ˜Kšœžœ˜Kšœžœ˜ Kšœ&˜&Kšœ žœ ˜Kšœ žœ ˜Kšœžœ ˜Kš žœžœžœžœžœžœ˜#šžœ˜šžœ’ ˜šžœ˜ Kšœ˜Kšœ,˜,K˜Kšœ˜—Kšœ˜—Kšœ˜Kšžœ3˜:Kšœžœžœ˜+Kš žœ žœžœžœžœžœ˜4Kšžœžœ'˜LKšœ*˜*šœžœ˜Kšœ˜Kšœ žœ˜Kšœ žœ˜Kšœ'˜'Kšœ˜Kšœ˜Kšœ)˜)Kšœ˜Kšœ˜Kšœ˜—Kšœ#˜#Kšœ˜KšœΣ™ΣKšœS™Sšœžœ˜Kšœ˜Kšœ žœžœžœ˜-Kšœ˜Kšœ˜Kšœ˜Kšœ˜—šžœžœ˜šœžœ˜Kšžœ0˜4Kšžœ@˜DKšœ˜—K˜—Kšœ=˜=šžœžœ˜Kšœžœ!˜4Kšœžœžœ"˜GKšœ˜—Kšœ@˜@KšœD’#˜gK˜Kšœ'˜'šžœžœžœž˜%Kšœžœ/˜Bšœ’3˜EKšœ%˜%Kšœ˜Kšœ1˜1Kšœ˜Kšœ˜—šœ!˜!Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ žœžœžœ˜PKšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—šœ,˜,Kšœ˜Kšœ ˜ Kšœ/˜/Kšœ˜Kšœ˜—Kšœžœžœ˜Kšœ@˜@K™šžœ žœ(žœ ž˜LKšœ£œ ™%Kšœžœ’C˜PKšœ!˜!Kš’'™'šœ˜Kšœ˜KšœI˜IKšœ$˜$Kšœ8˜8Kšœ˜—KšœG˜G˜ Kšœ˜Kšœžœ˜#Kšœžœ@˜GKšœ ˜ K˜—Kš’9™9Kšžœ žœžœ>˜RKš’™Kšœ˜š žœžœžœžœž˜šžœ žœž˜KšœFžœ˜K—Kšžœ˜—Kš’*œ˜+šžœ žœ˜Kšžœ˜!Kšžœžœ>˜E—Kšœ’˜6Kšœ˜Kšžœ’˜#—K˜!K˜KšœB˜BKšžœ’ ˜—Kšœ'˜'Kšœ%˜%K˜Kšžœ˜—Kšœ˜—K˜š‘œžœžœ’˜9Kš’C™CKš’3™3Kšœ žœ˜Kšœžœ ˜šžœ žœ˜(Kšœ&˜&šžœ žœ žœ˜ Kšœ}˜}—K˜—K˜K˜—š‘ œžœžœžœ˜<šžœžœ˜Kšœžœ˜Kšœ#˜#Kšœ˜—Kšœ˜K˜—š‘œžœ˜-š žœžœžœžœž˜ šžœ žœžœ˜Kšœ˜Kšœcžœ˜hKšœ˜—Kšžœ˜—Kšœ˜K˜—š ‘ œžœžœ žœ žœ ˜AKšœ™Kšœžœ˜)šžœžœ˜ Kšœ.˜.šžœžœ˜Kšœ˜Kšžœ žœžœ)˜>Kšœ@˜@Kšœ˜—K˜—Kšœ˜—K˜š ‘œžœžœ žœ žœ ˜GKšœ2™2Kšœžœ˜)šžœžœ˜ Kšœ&˜&šžœžœ˜Kšžœ žœžœ)˜>Kšœ@˜@Kšœ˜—K˜—Kšœ˜—K˜š‘ œžœ’'˜HKšœžœ’/˜>Kšœžœ˜)š’Y™YKšœžœ"’˜AKšœžœ!˜+Kšœžœ!˜+Kšœžœ!˜+—š’%™%Kšœ˜—š’%™%Kšœ:’˜BKšœ:’˜?Kšœ:’˜@Kšœ:’˜A—K˜—K˜Kš£™K˜K˜š‘œžœžœ˜0Kšœžœ ˜Kšœžœ’,˜Ešžœ?žœž˜NKšœžœžœ˜"Kšœžœžœ˜#Kšžœ˜—šžœžœ˜Kšœžœ+˜3Kšœ\˜\Kšœ…˜…šžœžœ˜$šžœžœ"žœ˜;Kšœ?˜?—K˜—K˜—K˜—K˜š ‘œžœžœžœ žœ žœ˜fKšœžœ˜šœ5˜5Kšœžœu˜Kšœ˜—šžœž˜ ˜Kšœ:˜:Kšœ-˜-K˜—˜Kšœ,˜,Kšœ2˜2K˜—˜Kšœ6˜6Kšœ'˜'K˜—˜Kšœ6žœ˜@Kšœ/˜/K˜—˜Kšœžœžœ˜Kšœžœ˜ Kšœ,˜,š žœžœ/žœžœž˜FKšžœžœžœ˜1Kšžœ˜—šžœžœžœ˜Kšœ%˜%Kšžœž˜ K˜—KšœD˜DKšœ7˜7K˜—Kšžœžœžœ˜—šžœžœ˜"Kšœ0˜0Kšžœž˜ Kšœ˜—Kšœ˜—K˜š‘œžœžœžœ˜Kšžœžœ˜3Kšžœžœžœ˜9Kšžœ žœžœžœ ˜5šžœCž˜MKšœžœ˜ ˜Kšœžœ˜Kšœ0˜0K˜—˜Kšœžœ˜Kšœ˜K˜—Kšžœžœ˜—šžœžœ˜šžœ'ž˜-Jšœ*˜*—šžœ žœ žœ˜Kšœ6˜6Kšžœž˜ K˜—Kšœ˜—Kšžœ˜—K˜šžœžœžœ˜.Kšœ1˜1Jšžœž˜ K˜—Kšœ˜šžœžœ˜Kšœžœ/žœ˜V—Kšœ ˜ šžœžœ˜Kšœ0’4˜dšžœžœžœž˜%šœ˜Kšœ˜Kšœ2˜2Kšœ˜Kšœ˜Kšœž˜ Kšœ˜KšœJžœ˜TKšœ žœ7žœ˜VKšœ˜—Kšž˜—K˜—Kšžœ ž˜Kšœ˜—K˜š ‘œžœ žœžœžœžœ˜XKšœžœžœ žœžœ žœžœžœ˜PKšžœžœ˜+Kšœ žœG˜VK˜—K˜š£œ˜2Kšœ/˜/šžœžœ˜Kšžœ1˜3šžœž˜Kšœ)˜)Kšž˜—Kšžœ(˜*K˜—Kšœ0˜0šžœž˜Kšœ)˜)Kšžœ˜—Kšœ˜Kšžœ!˜#Kšœ˜—K˜Kš£™J˜Jšœžœžœ˜Jšœžœžœ˜Jšœ žœžœ˜Jšœ žœžœ˜Jšœ žœžœ˜Jšœ žœ žœ ˜$J˜š‘œžœžœ ˜Jšžœžœžœ7žœ˜NJšžœžœžœ6žœ˜LJšžœ žœžœ9žœ˜RJšžœ žœžœ8žœ˜PJšœ˜J˜—š‘œž œžœ žœžœ žœžœ˜_Jšžœ žœžœžœ˜!Jšœ2˜2Jšœ)˜)Jšœ2žœ’˜QJšžœžœžœ%˜2Jšžœžœžœ%˜2Jšžœžœžœ%˜2Jšžœžœžœ%˜2Jšœ žœ˜$Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ&˜&šžœžœ˜JšœA˜AJšœA˜AJšœA˜AJšœA˜AJšœ˜—šžœ˜Jšœ@˜@Jšœ>˜>JšœB˜BJšœD˜DJ˜—JšœC˜CJš žœžœžœžœžœ žœ˜2Jšœ˜—J˜š‘œž œ˜Jšœ ž˜Jšœ˜—J˜š‘œž œ žœ˜(Jšœ žœ/˜=Jšœ˜Jšœ˜—J˜š‘ œž œ žœ˜)Jšœ˜Jšœ˜Jšœ˜—š‘œžœžœžœ˜#Jšœ@˜@Jšœ˜—J˜š‘œž œžœ˜<šœ6˜6šœ˜Jš žœžœžœžœžœžœ˜,Jš žœžœžœžœžœžœ˜5Jšžœžœ˜%—Jšœ˜—Jšœ˜—J˜š‘œž œžœ/˜Mšœ6˜6šœ˜Jšžœžœžœžœžœžœžœžœžœžœ˜PJšžœžœžœžœžœžœžœžœžœ˜_Jšžœžœ-˜5—Jšœ˜—Jšœ˜—K˜Kš‘™K˜š‘œžœ˜Kšœ<˜