DIRECTORY Atom, CD, CDBasics, CDCommandOps, CDDefaultProcs, CDEnvironment, CDIO, CDVArrow, CDCurves, CDOps, CDOrient, CDPDPlot, CDProperties, CDPropertyTools, CDSequencer, CDValue, GraphicsBasic, CGArea, CGClipper, CGReducer, Commander, CStitching, IO, PeachPrint, PDFileFormat, PDFileWriter, Process, Real, Rope, RuntimeError USING [UNCAUGHT], TerminalIO, ViewerClasses, ViewerSpecs; CDPDPlotImpl: CEDAR MONITOR IMPORTS Atom, CD, CDBasics, CDCommandOps, CDDefaultProcs, CDEnvironment, CDIO, CDValue, CDVArrow, CDOps, CDOrient, CDCurves, CDProperties, CDPropertyTools, CDSequencer, CGArea, CGClipper, CGReducer, 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] = BEGIN ColorVersatec: PROC [dd: REF DeviceDesc] = BEGIN 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"; END; InkJetC150: PROC [dd: REF DeviceDesc] = BEGIN 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"; END; Color400: PROC [dd: REF DeviceDesc] = BEGIN 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"; END; Puffin: PROC [dd: REF DeviceDesc] = BEGIN 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"; END; PlateMaker: PROC [dd: REF DeviceDesc] = BEGIN 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]"; END; Raven384: PROC [dd: REF DeviceDesc] = BEGIN 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]"; END; 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; END; 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, bandClip: CD.Rect _ [0, 0, 0, 0], pdState: PDFileWriter.PDState, colorLoads: REF ColorDescription, anouncedLayer: INT _ -1, design: CD.Design, pdy: CARDINAL _ 0, -- top of band in pixel coords dd: REF DeviceDesc ]; Plot: PUBLIC PROC [task: REF TaskDesc] = BEGIN ps: PlotState; clipSize: CD.Position; dd: REF DeviceDesc _ task.dd; design: CD.Design _ task.design; 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.WriteRope[" ** 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 _ CDCommandOps.BoundingBox[design]; clipSize _ CDBasics.SizeOfRect[task.clip]; dr _ CD.CreateDrawRef[[ design: design, stopFlag: task.abort, drawRect: NoteRectangle, drawContext: DrawContext, 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.FixC[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, clipSize.y]; pageWidth _ [Real.Round[dd.imageFSize/ps.plotScale], clipSize.y]; dr.devicePrivate _ ps; TerminalIO.WriteRopes["start ploting\n"]; FOR strip: INT IN [0..task.strips) DO fileName: Rope.ROPE _ MakeName[task.fileName, strip, task.strips]; dd.stripClip _ [ --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: dd.imageSSize, imageFSize: dd.imageFSize, bandSSize: dd.bandSSize, leftOverMode: dd.leftOverMode, maxLoadWords: dd.maxLoadWords, copies: dd.copies ]; ps.colorLoads^ _ ALL[NIL]; PDFileWriter.StartImage[pdState: ps.pdState, toners: dd.toners]; FOR bandYtop: INT _ 0, bandYtop+dd.bandSSize WHILE bandYtop TerminalIO.WriteRopes["color stipples used: [", r, "]\n"]; ENDCASE => { TerminalIO.WriteRope["**color stipples are not defined\n"]; ERROR ABORTED }; IF technology.key#CDProperties.GetAtomProp[dd.stippleKey, lastTechPropKey] THEN { TerminalIO.WriteRope["**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]; END; SetColor: PROC [ps: PlotState, lev: CD.Layer] = BEGIN MakeLoadref: PROC [pattern: REF ANY] RETURNS [loadRef: PDFileWriter.LoadReference] = TRUSTED BEGIN ToTexture: PROC [pattern: REF ANY] RETURNS [texture: Stipple16] = CHECKED BEGIN 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] END; -- 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; }; END; -- MakeLoadref MakeLoad: PROC [ps: PlotState, lev: CD.Layer] = INLINE BEGIN 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; }; END; --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 END; PlotPolygon: PROC [ps: PlotState, ob: CD.Object, pos: CD.Position, orient: CD.Orientation] = BEGIN OutputTrapezoid: PROC [xbotL: REAL, xbotR: REAL, ybot: REAL, xtopL: REAL, xtopR: REAL, ytop: REAL] = BEGIN PDFileWriter.MaskTrapezoid[ pdState: ps.pdState, sMin: Real.RoundC[ybot], sSize: Real.RoundC[ytop-ybot], fMin: Real.RoundC[xbotL], fSize: Real.RoundC[xbotR-xbotL], fMinLast: Real.RoundC[xtopL], fSizeLast: Real.RoundC[xtopR-xtopL] ]; END; --OutputTrapezoid dd: REF DeviceDesc = ps.dd; pp: CDCurves.CurvePtr = NARROW[ob.specificRef]; polygon: CGReducer.Ref = CGReducer.New[size: 8]; tiling: CGArea.Ref = CGArea.New[size: 4]; clipRef: CGClipper.Ref = CGClipper.New[size: 4]; clip: GraphicsBasic.Box _ [ xmin: 0, ymin: ps.pdy, xmax: MIN[(ps.bandClip.x2-dd.stripClip.x1)*ps.plotScale, dd.imageFSize], ymax: MIN[ps.pdy+dd.bandSSize, dd.imageSSize] ]; CGClipper.SetBox[self: clipRef, box: clip]; CGClipper.Load[self: clipRef, reducer: polygon]; FOR p: LIST OF CD.Position _ pp.points, p.rest WHILE p#NIL DO at: CD.Position = CDOrient.MapPoint[ pointInCell: p.first, cellSize: ob.size, cellInstOrient: orient, cellInstPos: pos ]; CGReducer.Vertex[self: polygon, v: [ x: (at.x-dd.stripClip.x1)*ps.plotScale, y: (dd.stripClip.y2-at.y)*ps.plotScale ]] ENDLOOP; CGReducer.Close[polygon]; CGReducer.Generate[self: polygon, area: tiling]; UNTIL CGArea.Empty[tiling] DO t: GraphicsBasic.Trap = CGArea.Remove[tiling]; OutputTrapezoid[t.xbotL, t.xbotR, t.ybot, t.xtopL, t.xtopR, t.ytop]; ENDLOOP; END; --PlotPolygon DrawContext: PROC [pr: CD.DrawRef, proc: CD.DrawContextLayerProc, ob: CD.Object, pos: CD.Position, orient: CD.Orientation, layer: CD.Layer] = BEGIN IF CDCurves.IsPolygon[ob] THEN { ps: PlotState = NARROW[pr.devicePrivate]; SetColor[ps, layer]; PlotPolygon[ps, ob, pos, orient]; } ELSE CDDefaultProcs.DrawContext[pr, proc, ob, pos, orient, layer] END; AnalyzeTesselations: PROC [ps: PlotState] = BEGIN 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.bandClip, eachTile: ProcessTile, data: ps]; }; ENDLOOP; END; ProcessTile: PROC [tile: CStitching.Tile, data: REF ANY] = BEGIN IF tile.value = $covered THEN { rightBound, xStart, xStop, yStart, yStop: INT; cxStart, cxStop, cyStop, cyStart: CARDINAL; sSize, fSize: CARDINAL; ps: PlotState = NARROW[data]; dd: REF DeviceDesc = ps.dd; r: CD.Rect = tile.Area; xStart _ Real.Round[(r.x1-dd.stripClip.x1)*ps.plotScale]; yStop _ Real.Round[(dd.stripClip.y2-r.y1)*ps.plotScale]; xStop _ Real.Round[(r.x2-dd.stripClip.x1)*ps.plotScale]; yStart _ Real.Round[(dd.stripClip.y2-r.y2)*ps.plotScale]; rightBound _ Real.Round[(ps.bandClip.x2-dd.stripClip.x1)*ps.plotScale]; IF xStart>rightBound OR xStop<0 THEN RETURN; IF yStopMIN[dd.imageSSize, ps.pdy+dd.bandSSize] THEN RETURN; cxStart _ MAX[xStart, 0]; cxStop _ MIN[xStop, rightBound, dd.imageFSize]; cyStart _ MAX[yStart, ps.pdy]; cyStop _ MIN[yStop, ps.pdy+dd.bandSSize, dd.imageSSize]; fSize _ cxStop - cxStart; sSize _ cyStop - cyStart; IF sSize>0 AND fSize>0 THEN PDFileWriter.MaskRectangle[pdState: ps.pdState, sMin: cyStart, fMin: cxStart, sSize: sSize, fSize: fSize]; }; END; CheckSpecialScale: PROC [task: REF TaskDesc] = { micronsPerInch: REAL ~ 25400; dd: REF DeviceDesc _ task.dd; specialScale: REAL _ -1; --means microns on plotted device per lambda WITH CDProperties.GetAtomProp[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*dd.sResolution/micronsPerInch/task.design.technology.lambda; TerminalIO.WriteF["plotting at special scale %g microns/lambda [%g pixels/chipndaleUnit]\n", [real[specialScale]], [real[task.scale]]]; IF dd.pageMode=fixedPage THEN { IF task.scale > REAL[dd.pageSlowSize]/(size.y+1) THEN TerminalIO.WriteRope["doesn't fit on page; must change scale\n"]; }; }; }; cnt: INT _ 0; PDColorPlotComm: PROC [comm: CDSequencer.Command] = BEGIN 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.WriteRope["Color plot\n"]; task.dd _ MakeDevice[comm.key]; IF task.dd=NIL THEN { TerminalIO.WriteRope["no device specified\n"]; RETURN }; TerminalIO.WriteRopes[task.dd.name, "\n"]; SELECT TerminalIO.RequestSelection["PD Plot", LIST["plot complete design", "plot drawn rectangle", "specials, strips, servers..."]] FROM 1 => { clip _ CDCommandOps.BoundingBox[comm.design]; TerminalIO.WriteRope["plot all\n"]; }; 2 => { clip _ CDBasics.ToRect[comm.pos, comm.sPos]; TerminalIO.WriteRope["plot rectangle\n"]; }; 3 => { default: Rope.ROPE _ NIL; choice: LIST OF Rope.ROPE _ LIST["no", "type name of server"]; TerminalIO.WriteRope["special\n"]; SELECT TerminalIO.RequestSelection["Plot", LIST["plot complete design", "plot drawn rectangle"]] FROM 1 => { clip _ CDCommandOps.BoundingBox[comm.design]; TerminalIO.WriteRope["plot all\n"]; }; 2 => { clip _ CDBasics.ToRect[comm.pos, comm.sPos]; TerminalIO.WriteRope["plot rectangle\n"]; }; ENDCASE => ERROR ABORTED; IF task.dd.pageMode=anyStripe THEN { IF TerminalIO.Confirm[label: "plot multiple vertical strips", choice: "yes"] THEN task.strips _ TerminalIO.RequestInt["How many vertical strips? [1..10] "]; }; IF TerminalIO.Confirm[label: "ommit comments", choice: "yes"] THEN task.dd.contextFilter[CD.commentLayer] _ FALSE; 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[label: "multiple copies", choice: "yes"] THEN copies _ TerminalIO.RequestInt["copies>"]; IF copies<1 OR copies>10 THEN { TerminalIO.WriteRope["unreasonable number of copies\n"]; ERROR ABORTED }; }; }; ENDCASE => ERROR ABORTED; IF clip.x1>=clip.x2 OR clip.y1>=clip.y2 THEN { TerminalIO.WriteRope["**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 { 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.WriteRope["**Pup aborted plotting\n"]; CONTINUE}; RuntimeError.UNCAUGHT => {TerminalIO.WriteRope["**Peach aborted plotting\n"]; CONTINUE}; ]; ENDLOOP }; EXITS tobad => NULL END; 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 = BEGIN 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"] END; 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] = BEGIN 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]; END; Start: PUBLIC PROC[tech, device, b, c, m, y: ATOM, text: Rope.ROPE_NIL, invert: BOOL_FALSE] = BEGIN 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; End: PUBLIC PROC [] = { currTech _ NIL }; Layer: PUBLIC PROC [uniqueKey: ATOM] = BEGIN currLayer _ CD.FetchLayer[t: currTech, uniqueKey: uniqueKey]; Forgett[currLayer] END; LayerNumber: PUBLIC PROC [layer: NAT] = BEGIN currLayer _ layer; Forgett[currLayer] END; Color1: PUBLIC PROC [key: ATOM] = BEGIN CDProperties.PutLayerProp[onto: currLayer, prop: key, val: $ink] END; Color4: PUBLIC PROC [key: ATOM, i0, i1, i2, i3: [0..16)] = BEGIN 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]] ] END; Color8: PUBLIC PROC [key: ATOM, i0, i1, i2, i3, i4, i5, i6, i7: [0..256)] = BEGIN 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]] ] END; Init: PROC [] = BEGIN 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.WriteRope["ChipNDale PD color plot program loaded\n"]; END; Init[]; END. μCDPDPlotImpl.mesa Copyright c 1983, 1986 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, August 25, 1986 12:03:08 pm PDT --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 --rectangles in design space touching all geometry in the plot, or this band xoffset: INT _ -dd.stripClip.x1*scale; yoffset: INT _ dd.stripClip.y2*scale; --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 -- Determine coordinate transformations --Display current band under consideration to pacify user -- clear previous tessalations --tries to convert pattern to a texture stipple --makes the load if it does not already exist --SetColor --lower left x, lower right x, lower y, upper left x, upper right x, upper y --global variables ps, dd.stripClip, ps.plotScale, dd.imageFSize, dd.imageSSize, ps.pdy --x-Fast --y-Slow --PlotPolygon -- calculate device coords of rectangle -- clip device rectangle -- print device rectangle --command level --interpreter set up --initializations CD Menus.CreateEntry[$HardCopyMenu, "PD Color Versatec", $PDPlotVersatec]; CD Menus.CreateEntry[$HardCopyMenu, "PD C150", $PDPlotC150]; CD Menus.CreateEntry[$HardCopyMenu, "PD Color400", $PDPlotColor400]; CD Menus.CreateEntry[$HardCopyMenu, "PD using commandfile", $PDPlotUserDevice]; Κ Τ˜codešœ™Kšœ Οmœ7™B™KšœG™GKšœ2™2Kšœ>™>K™A——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šœ ˜ —K˜šΠbn œžœž˜Kšžœžœ7žœ‘žœ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šœžœ˜Kšœ’/˜FKšœ’-˜DKšœ˜Kšœ žœžœ˜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šž˜Kšœ2˜2Kšœ’/˜FKšœ’-˜DKšœ)˜)Kšœ žœžœ˜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šž˜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šœL™L—K˜Kšœ žœ˜!Kšœžœ˜Kšœžœ˜šœžœ’˜2Kšœ'™'Kšœ&™&—Kšœžœ ˜Kšœ˜—K˜K˜š‘œžœžœžœ ˜(Kšž˜Kšœ˜Kšœ žœ ˜Kšœžœ˜Kšœžœ˜ Kšœ žœ ˜Kšœ žœ ˜Kšœžœ ˜Kš žœžœžœžœžœžœ˜#šžœ˜šžœ’ ˜šžœ˜ Kšœ˜Kšœ.˜.K˜Kšœ˜—Kšœ˜—Kšœ˜Kšžœ3˜:Kšœžœžœ˜+Kš žœ žœžœžœžœžœ˜4Kšžœžœ.˜SKšœ*˜*šœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ#˜#Kšœ˜KšœΣ™ΣKšœS™Sšœžœ˜Kšœ˜Kšœ žœžœžœ˜-Kšœ˜Kšœ˜Kšœ˜Kšœ˜—šžœžœ˜šœžœ˜Kšžœ0˜4Kšžœ@˜DKšœ˜—K˜—Kšœ5˜5šžœžœ˜Kšœžœ!˜4Kšœžœžœ"˜GKšœ˜—Kšœ0˜0KšœA˜AK˜Kšœ)˜)šžœžœžœž˜%Kšœžœ/˜Bšœ’3˜DKšœ%˜%Kšœ˜Kšœ1˜1Kšœ˜Kšœ˜—šœ!˜!Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœžœžœ˜Kšœ@˜@K™šžœ žœžœž˜LKšœžœ’C˜PKšœ!˜!K™'Kšœ˜šœ˜Kšœ˜KšœF˜FKšœ<˜Kšœ-˜-Kšœ˜—Kšžœ˜—K˜š‘ œžœžœžœ˜CKšž˜K˜š‘œžœžœ˜1Kšž˜š žœžœžœžœžœ˜šžœžœ˜Jšœžœžœ˜šžœžœž˜šžœžœž˜ šžœ4žœžœ˜@Kšœžœž˜K˜——Kšžœ˜—Kšœ˜K˜—Kšžœ˜—Kšžœ˜—K˜šžœžœžœ˜Kšœ;˜;Kšžœž˜ Kšœ˜—šžœIžœ˜QKšœ3˜3Kšœnžœžœ˜xKšœS˜SK˜—šžœ*žœž˜9Kšœžœ>˜Jšžœ˜ Kšœ;˜;Kšžœž˜ K˜——šžœIž˜QKšœ†˜†K˜—Kšœžœ žœžœ˜*šžœžœž˜2KšœO˜Ošžœžœžœžœ˜0Kšœžœ˜Kšœžœžœ˜K˜—Kšžœ˜—Kšœ˜Kšžœ˜—K˜š‘œžœžœ ˜/Kšž˜K˜š ‘ œžœ žœžœžœ(˜TKšžœž˜ K˜š ‘ œžœ žœžœžœ˜AKšœ/™/Kšž ˜ šžœ žœž˜Kšœžœ˜%šœžœ ˜šžœ žœž˜Kšœ*˜*Kšžœ˜——šœžœ ˜šžœ žœž˜KšœG˜GKšžœ˜——Kšžœžœ4’˜U—Kšžœ ˜Kšžœ’ ˜K˜—Kšžœ žœžœ˜%Kšžœžœžœ˜-šžœ˜Kšœ(˜(Kšœ‰˜‰Kšžœžœžœ˜!Kšœ˜—Kšžœ’˜—K˜š‘œžœžœ ž˜6Kšœ-™-Kšž˜šžœžœžœ˜!Kšœžœ ˜%šžœžœž˜KšœžœG˜OKšžœžœžœ%˜4Kšžœ.˜2Kšžœ˜—K˜—Kšžœ’ ˜—K˜Kšœ ™ Kšžœžœžœ˜$Kšžœžœžœ˜2šžœžœž˜šžœ&žœ˜-Kšœ+˜+—šžœžœ'ž˜3Kšœ+˜+—šž˜KšœV˜V—Kšžœ˜—Kšœ˜Kšžœ˜—K˜š ‘ œžœžœžœžœ˜\Kšž˜K˜š‘œžœ žœ žœžœ žœ žœžœ˜dKšœL™LKšž˜KšœW™WKšœ™Kšœ™šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ!˜!Kšœ˜Kšœ#˜#K˜—Kšžœ’˜K˜—Kšœ ™ Kšœžœ˜Kšœžœ˜/Kšœ0˜0Kšœ)˜)Kšœ0˜0šœ˜Kšœ ˜ Kšœ˜Kšœžœ@˜IKšœžœ$˜-Kšœ˜—Kšœ+˜+Kšœ0˜0š žœžœžœžœžœžœž˜=šœžœ˜$Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—šœ$˜$Kšœ(˜(Kšœ&˜&Kšœ˜—Kšžœ˜—Kšœ˜Kšœ0˜0šžœž˜Kšœ.˜.KšœD˜DKšžœ˜—Kšžœ’ ˜—K˜š‘ œžœžœžœžœžœžœžœ ˜Kšž˜šžœžœ˜ Kšœžœ˜)Kšœ˜Kšœ!˜!K˜—Kšžœ=˜AKšžœ˜—K˜š‘œžœ˜+Kšž˜š žœžœžœžœž˜ šžœ žœžœ˜Kšœ˜Kšœa˜aKšœ˜—Kšžœ˜—Kšžœ˜K˜—š‘ œžœžœžœ˜:Kšžœ˜šžœžœ˜Kšœ*žœ˜.Kšœ"žœ˜+Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœ'™'Kšœ9˜9Kšœ9˜9Kšœ8˜8Kšœ;˜;Kšœ™KšœG˜GKšžœžœ žœžœ˜,Kš žœžœžœ%žœžœ˜NKšœ™Kšœ žœ ˜Kšœ žœ#˜/Kšœ žœ˜Kšœ žœ,˜8K˜Kšœ˜šžœ žœ žœ˜Kšœj˜j—Kšœ˜—Kšžœ˜K˜—Kš£™K˜K˜š‘œžœžœ˜0Kšœžœ ˜Kšœžœ˜Kšœžœ’,˜Ešžœ:žœž˜IKšœžœžœ˜"Kšœžœžœ˜#Kšžœ˜—šžœžœ˜Kšœžœ+˜3KšœW˜WKšœ‡˜‡šžœžœ˜šžœžœžœ˜6KšœA˜A—K˜—K˜—K˜—K˜Kšœžœ˜ K˜š‘œžœ˜3Kšž˜šžœ ˜šžœ&žœ1ž˜eKšœžœ˜Kšœžœžœ˜"Kšœžœ˜ Kšžœžœ˜—K˜—Kšœžœ˜Kšœžœžœ˜Kšœ žœ žœ˜#Kšœžœ žœ@˜XKšœ&˜&Kšœ˜šžœ žœžœ˜Kšœ.˜.Kšž˜K˜—Kšœ*˜*šžœ(žœRž˜ˆ˜Kšœ-˜-Kšœ#˜#K˜—˜Kšœ,˜,Kšœ)˜)K˜—˜Kšœžœžœ˜Kš œžœžœžœžœ˜>Kšœ"˜"šžœ%žœ2ž˜e˜Kšœ-˜-Kšœ#˜#K˜—˜Kšœ,˜,Kšœ)˜)K˜—Kšžœžœžœ˜—šžœžœ˜$šžœKž˜QKšœJ˜J—K˜—šžœ<ž˜BKšœžœž˜/—Kšžœžœ˜3Kšžœžœžœ˜9Kšžœ žœžœžœ ˜5šžœCž˜MKšœžœ˜ ˜Kšœžœ˜Kšœ0˜0K˜—˜Kšœžœ˜Kšœ˜K˜—Kšžœžœ˜—šžœžœ˜šžœ=ž˜CJšœ*˜*—šžœ žœ žœ˜Kšœ8˜8Kšžœž˜ K˜—Kšœ˜—K˜—Kšžœžœžœ˜—šžœžœžœ˜.Kšœ3˜3Jšžœž˜ K˜—Kšœ˜šžœžœ˜Kšœžœ/žœ˜V—Kšœ ˜ šžœžœ˜šžœžœžœž˜%šœ˜Kšœ˜Kšœ2˜2Kšœžœ˜Kšœ˜Kšœž˜ Kšœ˜KšœLžœ˜VKšœ žœ9žœ˜XKšœ˜—Kšž˜—K˜—Kšžœ ž˜Kšžœ˜—K˜š ‘œžœ žœžœžœžœ˜XKšœžœžœ žœžœ žœžœžœ˜PKšžœžœ˜+Kšœ žœG˜VK˜—K˜š£œ˜1Kšž˜Kšœ/˜/šžœžœ˜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šž˜Jšžœžœžœ7žœ˜NJšžœžœžœ6žœ˜LJšžœ žœžœ9žœ˜RJšžœ žœžœ8žœ˜PJšžœ˜J˜—š‘œž œžœ žœžœ žœžœ˜^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šž˜Jšœ@˜@Jšžœ˜—J˜š‘œž œžœ˜:Jšž˜šœ6˜6šœ˜Jš žœžœžœžœžœžœ˜,Jš žœžœžœžœžœžœ˜5Jšžœžœ˜%—Jšœ˜—Jšžœ˜—J˜š‘œž œžœ-˜KJšž˜šœ6˜6šœ˜Jšžœžœžœžœžœžœžœžœžœžœ˜PJšžœžœžœžœžœžœžœžœžœ˜_Jšžœžœ-˜5—Jšœ˜—Jšžœ˜—K˜Kš‘™K˜š‘œžœ˜Kšž˜Kšœ<˜