DIRECTORY Atom, CD, CDInstances, CDBasics, CDCallSpecific, CDViewer, CDEvents, CDExtras, CDIO, CDMenus, CDOps, CDProperties, CDSequencer, CornerStitching, FS, Imager, ImagerBackdoor, Menus, IO, Process, Real, Rope, STPStreams, TerminalIO, VFonts, ViewerClasses, ViewerOps, ViewerSpecs; CDBWVersatecImpl: CEDAR MONITOR IMPORTS Atom, CD, CDInstances, CDBasics, CDCallSpecific, CDEvents, CDExtras, CDIO, CDMenus, CDViewer, CDOps, CDProperties, CDSequencer, CornerStitching, FS, Imager, ImagerBackdoor, IO, Menus, Process, Real, STPStreams, TerminalIO, VFonts, ViewerOps EXPORTS = BEGIN maxScanLineWidth: CARDINAL = 7040; -- the wide-bed Versatec scanLineWidth: CARDINAL _ maxScanLineWidth; maxPatchHeight: CARDINAL = 144; -- fits in 64k stippleRepeat: CARDINAL = 16; Nibble: TYPE = [0..16); ScanLine: TYPE = PACKED ARRAY [0..0) OF WORD; ScanLineInNibbles: TYPE = PACKED ARRAY [0..0) OF Nibble; CodedScanLine: TYPE = RECORD [ codeWordCount: CARDINAL _ 0, codeWords: REF CodeWords ]; CodeWords: TYPE = PACKED ARRAY [0..maxScanLineWidth) OF CodeWord; CodeWord: TYPE = MACHINE DEPENDENT RECORD [ repeats (0: 0..3): [1..16], pattern (0: 4..7): Nibble]; textures: ARRAY CD.Layer OF REF ImagerBackdoor.Texture _ ALL[NIL]; outLine: BOOL _ TRUE; skipLayers: BOOL _ FALSE; allBlack: BOOL _ FALSE; handleSignalNames: BOOL _ TRUE; PlotStateRef: TYPE = REF PlotState; PlotState: TYPE = RECORD [ text: REF CornerStitching.Tesselation _ NIL, tes: ARRAY CD.Layer OF REF CornerStitching.Tesselation _ ALL[NIL], bitmap: ImagerBackdoor.Bitmap _ NIL, vPatch, context: Imager.Context _ NIL, scale: REAL _ 1.0, -- pixels per CD.Number totalPlotClip, bandClip: CD.Rect _ [0, 0, 0, 0], texture: ImagerBackdoor.Texture _ ALL[0] ]; currentFlavor: ViewerClasses.ViewerFlavor = $ChipndaleVersatecPlot; Init: ENTRY PROC ~ { menu: Menus.Menu = Menus.CreateMenu[]; Menus.AppendMenuEntry[menu: menu, entry: Menus.CreateEntry[name: "AbortPlot", proc: AbortProc, guarded: TRUE]]; CDEvents.RegisterEventProc[$Abort, AbortEvent]; ViewerOps.RegisterViewerClass[flavor: currentFlavor, class: NEW[ViewerClasses.ViewerClassRec _ [paint: PaintVersatecStripe, menu: menu]]]; CDSequencer.ImplementCommand[a: $VPlotLocal, p: PlotDesignToLocalFile, queue: doQueue]; CDSequencer.ImplementCommand[a: $VPlotPlotter, p: PlotDesignToPlotter, queue: doQueue]; CDSequencer.ImplementCommand[a: $VPlot, p: PlotDesignToAny, queue: doQueue]; CDSequencer.ImplementCommand[a: $VersatecBWPlot, p: PlotDesignToAny, queue: doQueue]; CDMenus.CreateEntry[menu: $HardCopyMenu, entry: "BW Versatec Plot", key: $VersatecBWPlot]; signalFont _ VFonts.EstablishFont[family: "Helvetica", size: 18, bold: TRUE]; TerminalIO.WriteRope["ChipNDale BW Versatec plotter loaded\n"]; TerminalIO.WriteRope[" ..use the hardcopy command for plotting..\n"]; }; PlotDesignToAny: ENTRY PROC [ c: CDSequencer.Command ] = BEGIN ENABLE UNWIND => NULL; n: CARDINAL _ TerminalIO.RequestSelection[ label: "Versatec Plot", choice: LIST[" plotter", " local", " read name"] ]; SELECT n FROM 1 => PlotDesign[c: c, to: plotter]; 2 => PlotDesign[c: c, to: localFile]; 3 => PlotDesign[c: c, to: requestFilename]; ENDCASE => TerminalIO.WriteRope["skipped\n"]; END; PlotDesignToLocalFile: ENTRY PROC [ c: CDSequencer.Command ] = BEGIN ENABLE UNWIND => NULL; PlotDesign[c: c, to: localFile]; END; PlotDesignToPlotter: ENTRY PROC [ c: CDSequencer.Command ] = BEGIN ENABLE UNWIND => NULL; PlotDesign[c: c, to: plotter]; END; signalFont: Imager.Font _ NIL; viewer: ViewerClasses.Viewer _ NIL; plotter: Rope.ROPE _ "vice"; plotFileToSpool: Rope.ROPE _ "[vice]plot.bits"; plotFileOnPlotter: Rope.ROPE _ "plot.bits"; plotFileOnLocalMachine: Rope.ROPE _ "///chipndale/tem/plot.bits"; latestPlotFile: Rope.ROPE _ NIL; spoolToPlotter: BOOL _ TRUE; abortPlot: BOOL _ FALSE; designIfAbort: CD.Design _ NIL; AssignTextures: PROC [usedLayers: REF PACKED ARRAY CD.Layer OF BOOL] = BEGIN IF allBlack THEN { black: REF ImagerBackdoor.Texture _ NEW[ImagerBackdoor.Texture_ALL[0FFH]]; FOR l: CD.Layer IN CD.Layer DO -- assign textures to used layers textures[l] _ black; ENDLOOP; } ELSE { textureNo: CARDINAL _ 0; FOR l: CD.Layer IN CD.Layer DO -- assign textures to used layers IF usedLayers[l] THEN { textures[l] _ Texture[textureNo]; textureNo _ textureNo+1 } ELSE textures[l] _ NIL; ENDLOOP; } END; PlotDesign: INTERNAL PROC [ c: CDSequencer.Command, to: {localFile, plotter, requestFilename}] = BEGIN s: IO.STREAM _ NIL; plotClip: CD.Rect; strips: [1..100]; IF ~outLine OR skipLayers OR allBlack OR ~handleSignalNames THEN TerminalIO.WriteRope["**WARNING, colors set up different from default\n"]; SELECT TerminalIO.RequestSelection["Plot", LIST["complete design", "rectangle"]] FROM 2 => { plotClip _ CDBasics.ToRect[c.pos, c.sPos]; TerminalIO.WriteRope["plot rectangle\n"]; }; ENDCASE => { plotClip _ CDExtras.BoundingBox[c.design]; TerminalIO.WriteRope["plot all\n"]; }; strips _ TerminalIO.RequestInt["How many vertical strips in the plot? "]; BEGIN ENABLE { -- for ERRORs UNWIND => {s _ AbortFile[s]; TerminalIO.WriteRope[" ** plot aborted ** "]}; }; design: CD.Design = c.design; dr: CD.DrawRef = CD.CreateDrawRef[design]; scale: REAL = MIN[32.0/CD.lambda, (REAL[scanLineWidth]+REAL[scanLineWidth-100]*(strips-1))/(plotClip.x2-plotClip.x1)]; patchHeight: CARDINAL = stippleRepeat*((MIN[maxPatchHeight, CARDINAL[Real.Fix[50*CD.lambda*scale]]]+stippleRepeat-1)/stippleRepeat); bitmap: ImagerBackdoor.Bitmap = ImagerBackdoor.NewBitmap[width: scanLineWidth, height: patchHeight]; ps: PlotStateRef = NEW[ PlotState _ [ text: CornerStitching.NewTesselation[], scale: scale, totalPlotClip: plotClip, bitmap: bitmap, vPatch: ImagerBackdoor.NewContextFromBitmap[bitmap]] ]; usedLayers: REF PACKED ARRAY CD.Layer OF BOOL _ NIL; abortPlot _ FALSE; designIfAbort _ design; TerminalIO.WriteRope["Starting Versatec plot "]; TRUSTED {Process.SetPriority[Process.priorityBackground]}; viewer _ ViewerOps.FindViewer["Versatec Stripe"]; IF viewer # NIL AND viewer.class.flavor # currentFlavor THEN {ViewerOps.DestroyViewer[viewer]; viewer _ NIL}; IF viewer=NIL THEN BEGIN viewer _ ViewerOps.CreateViewer[flavor: currentFlavor, info: [name: "Versatec Stripe", iconic: FALSE, openHeight: patchHeight+ViewerSpecs.menuHeight]]; END; viewer.data _ ps; dr.minimalSize _ 0; dr.drawRect _ dr.saveRect _ NoteLayer; dr.contextFilter _ NEW[CD.ContextFilter_ALL[[doit: TRUE]]]; dr.drawContext _ CheckDrawContext; dr.devicePrivate _ usedLayers; dr.interestClip _ CDBasics.universe; dr.devicePrivate _ usedLayers _ NEW[PACKED ARRAY CD.Layer OF BOOL _ ALL[FALSE]]; CDOps.DrawDesign[design, dr]; -- mark used layers AssignTextures[usedLayers]; dr.drawRect _ dr.saveRect _ NoteRectangle; dr.contextFilter _ NIL; dr.devicePrivate _ ps; SELECT to FROM localFile => BEGIN TerminalIO.WriteRope["onto """]; s _ FS.StreamOpen[plotFileOnLocalMachine, create]; TerminalIO.WriteRope[plotFileOnLocalMachine]; TerminalIO.WriteRope[""""]; s.SetLength[0]; latestPlotFile _ plotFileOnLocalMachine; END; requestFilename => BEGIN r: Rope.ROPE _ CDIO.MakeName[TerminalIO.RequestRope["to file ? > "], "bits"]; TerminalIO.WriteRope["onto """]; s _ FS.StreamOpen[r, create]; TerminalIO.WriteRope[r]; TerminalIO.WriteRope[""""]; s.SetLength[0]; latestPlotFile _ r; END; plotter => BEGIN TerminalIO.WriteRope["onto plotter "]; [self: s] _ STPStreams.OpenSTP[host: plotter, fileName: plotFileOnPlotter, accessOptions: create]; latestPlotFile _ NIL; END; ENDCASE => ERROR; TRUSTED { s.PutChar[LOOPHOLE[scanLineWidth/256, CHARACTER]]; s.PutChar[LOOPHOLE[scanLineWidth MOD 256]]; }; IF handleSignalNames THEN { TerminalIO.WriteRope["\n.. found "]; TerminalIO.WriteInt[CDCallSpecific.CallForAll[design: design, whatElse: LookForSignalName, x: ps]]; TerminalIO.WriteRope[" top-layer signal names "]; }; SendWhiteBar[s: s]; SendBlackBar[s: s]; FOR strip: INT IN [0..strips) DO clip: CD.Rect = [ x1: plotClip.x1+strip*((plotClip.x2-plotClip.x1)/strips), y1: plotClip.y1, x2: plotClip.x1+(strip+1)*((plotClip.x2-plotClip.x1)/strips)+Real.Fix[100./scale]+1, y2: plotClip.y2]; FOR topLine: INT _ 0, topLine+patchHeight WHILE topLine {s _ AbortFile[s]; TerminalIO.WriteRope[" ** plot aborted ** "]; abortPlot _ FALSE}; END; END; CheckDrawContext: PROC [pr: CD.DrawRef, proc: CD.DrawContextLayerProc, ob: CD.Object, pos: CD.Position, orient: CD.Orientation, layer: CD.Layer] = BEGIN IF pr.contextFilter#NIL AND pr.contextFilter[layer].doit THEN { pr.contextFilter[layer].doit _ FALSE; TerminalIO.WriteRope[" "]; TerminalIO.WriteRope[CDOps.Info[ob]]; TerminalIO.WriteRope[" (and maybe others) is not rectilinear and will not appear on plot.\n"]; } END; NoteLayer: PROC [ r: CD.Rect, l: CD.Layer, pr: CD.DrawRef ] = BEGIN ps: REF PACKED ARRAY CD.Layer OF BOOL = NARROW[pr.devicePrivate]; ps[l] _ TRUE; END; NoteRectangle: PROC [ r: CD.Rect, l: CD.Layer, pr: CD.DrawRef ] = BEGIN ps: PlotStateRef = NARROW[pr.devicePrivate]; IF CDBasics.NonEmpty[r] THEN { IF ps.tes[l]=NIL THEN { IF skipLayers AND CDProperties.GetPropFromLayer[l, $DrawMeOnBWVersatec]#$DrawMeOnBWVersatec THEN RETURN; ps.tes[l] _ CornerStitching.NewTesselation[]; }; ps.tes[l].ChangeRect[rect: r, newValue: $covered]; }; END; AnalyzeTesselations: PROC [ ps: PlotStateRef ] = BEGIN FOR l: CD.Layer IN CD.Layer DO IF ps.tes[l]#NIL THEN { ps.texture _ textures[l]^; [] _ ps.tes[l].EnumerateArea[rect: ps.bandClip, perTile: ProcessTile, data: ps, backgroundValue: $none]; }; ENDLOOP; END; ProcessTile: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] = -- CornerStitching.PerTileProc -- BEGIN -- only called on covered tiles t: CornerStitching.TilePtr; ps: PlotStateRef = NARROW[data]; tileValue: REF = tile.Value; IF tileValue = $covered THEN { r: CD.Rect = tile.Area; ImagerBackdoor.DrawTexturedBox[self: ps.context, box: [xmin: r.x1, ymin: r.y1, xmax: r.x2, ymax: r.y2], texture: ps.texture]; }; IF outLine THEN { FOR t _ tile.NEastNeighbour, t.WSouthNeighbour WHILE tile.SouthEdge s _ Atom.GetPName[atom]; rope: Rope.ROPE => s _ rope; ENDCASE => s _ "?"; END; ps: PlotStateRef = NARROW[x]; r: CD.Rect = CDBasics.Intersection[ps.totalPlotClip, CDInstances.ARectO[inst]]; signal: REF = CDProperties.GetProp[from: inst, prop: $SignalName]; IF signal # NIL AND CDBasics.NonEmpty[r] THEN BEGIN signalValue: SignalValueRef = NEW[SignalValue _ [s: GetSignalName[signal]]]; others: LIST OF REF CornerStitching.Region = NARROW[ps.text.EnumerateArea[rect: r]]; ps.text.ChangeRect[rect: r, newValue: signalValue]; FOR other: LIST OF REF CornerStitching.Region _ others, other.rest WHILE other#NIL DO ps.text.ChangeRect[rect: other.first.rect, newValue: other.first.value]; ENDLOOP; END ELSE done _ FALSE; END; PaintASignalName: PROC [tile: CornerStitching.TilePtr, data: REF ANY] = BEGIN ps: PlotStateRef = NARROW[data]; textContext: Imager.Context = ps.vPatch.CopyContext[]; signalValue: SignalValueRef = NARROW[tile.Value[]]; dx, dy, xmin, xmax, ymin, ymax: REAL; r: CD.Rect = CDBasics.Intersection[tile.Area, ps.totalPlotClip]; ctr: CD.Position = Center[r]; [dx: dx, dy: dy] _ Imager.Map[sc: ps.context, dc: ps.vPatch, sx: ctr.x, sy: ctr.y]; [xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax] _ Imager.RopeBox[font: signalFont, rope: signalValue.s]; textContext.Translate[tx: dx-(xmax+xmin)/2, ty: dy-(ymax+ymin)/2]; -- centers the text in r IF ((xmax-xmin)>(ymax-ymin)) # ((r.x2-r.x1)>(r.y2-r.y1)) THEN textContext.Rotate[270]; textContext.SetColor[Imager.white]; textContext.DrawBox[[xmin: -2, ymin: -2, xmax: xmax-xmin+2, ymax: ymax-ymin+2]]; textContext.SetColor[Imager.black]; textContext.SetCP[x: 0, y: 0]; textContext.DrawRope[rope: signalValue.s, font: signalFont]; END; Center: PROC [ r: CD.Rect ] RETURNS [ CD.Position ] = {RETURN[[x: (r.x1+r.x2)/2, y: (r.y1+r.y2)/2]]}; SendWhiteBar: PROC [ s: IO.STREAM, lines: CARDINAL _ 40 ] = {SendBar[s, 0, lines]}; SendBlackBar: PROC [ s: IO.STREAM, lines: CARDINAL _ 20 ] = {SendBar[s, 15, lines]}; SendBar: PROC [ s: IO.STREAM, pattern: Nibble, lines: CARDINAL ] = BEGIN scanLineNibbles: CARDINAL = scanLineWidth/4; FOR j: CARDINAL IN [0..lines) DO FOR i: CARDINAL IN [0..(scanLineNibbles+15)/16) DO TRUSTED {s.PutChar[LOOPHOLE[CodeWord[repeats: MIN[16, scanLineNibbles-16*i], pattern: pattern]]]}; ENDLOOP; ENDLOOP; END; SendBitmap: PROC [ s: IO.STREAM, bitmap: ImagerBackdoor.Bitmap ] = BEGIN csl: REF CodedScanLine = NEW[CodedScanLine _ [codeWords: NEW[CodeWords]]]; FOR i: CARDINAL IN [0..bitmap.height) DO -- send to the Versatec TRUSTED { EncodeScanLine[sl: LOOPHOLE[LOOPHOLE[bitmap.base, INT]+INT[bitmap.raster]*i, LONG POINTER TO ScanLine], bitWidth: bitmap.width, csl: csl]; s.UnsafePutBlock[[base: LOOPHOLE[csl.codeWords], startIndex: 0, count: csl.codeWordCount]]; } ENDLOOP; END; EncodeScanLine: PROC [ sl: LONG POINTER TO ScanLine, bitWidth: CARDINAL, csl: REF CodedScanLine ] = TRUSTED BEGIN size: CARDINAL _ 0; scanLineInNibbles: LONG POINTER TO ScanLineInNibbles = LOOPHOLE[sl]; scanLineNibbles: CARDINAL = (bitWidth+3)/4; i: CARDINAL _ 0; WHILE i Stipple[01H, 02H, 04H, 08H], 1 => Stipple[04H, 02H, 01H, 08H], 2 => Stipple[00H, 0AH, 00H, 0AH], 3 => Stipple[08H, 00H, 08H, 00H], 4 => Stipple[0AH, 00H, 00H, 00H], 5 => Stipple[08H, 00H, 02H, 00H], 6 => Stipple[00H, 01H, 00H, 04H], 7 => Stipple[04H, 04H, 00H, 00H], 8 => Stipple[00H, 00H, 00H, 03H], ENDCASE => Stipple[0FH, 0FH, 0FH, 0FH])[row]; ENDLOOP; RETURN[t]; END; PaintVersatecStripe: PROC [ self: ViewerClasses.Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL ] -- ViewerClasses.PaintProc -- = BEGIN ps: PlotStateRef = NARROW[self.data]; x: INT = MAX[INT[0], (ps.bitmap.width-self.cw)/2]; y: INT = MAX[INT[0], (ps.bitmap.height-self.ch)/2]; context.SetCP[self.cw/2, self.ch/2]; ImagerBackdoor.DrawBitmap[self: context, bitmap: ps.bitmap, w: MIN[self.cw, ps.bitmap.width], h: MIN[self.ch, ps.bitmap.height], x: x, y: y, xorigin: ps.bitmap.width/2, yorigin: ps.bitmap.height/2]; END; AbortProc: Menus.MenuProc = {abortPlot _ TRUE}; AbortEvent: CDEvents.EventProc = { IF designIfAbort#NIL AND (design=NIL OR design=designIfAbort) THEN { abortPlot _ TRUE; designIfAbort _ NIL } }; AbortFile: PROC [s: IO.STREAM ] RETURNS [ IO.STREAM ] = {IF s#NIL THEN s.Close[abort: TRUE]; RETURN[NIL]}; SpoolToPlotter: ENTRY PROC = {SpoolFileToPlotter[latestPlotFile]}; SpoolFileToPlotter: PROC [name: Rope.ROPE] = BEGIN IF name # NIL THEN { TerminalIO.WriteRope["spool file """]; TerminalIO.WriteRope[name]; TerminalIO.WriteRope[""".."]; FS.Copy[from: name, to: plotFileToSpool ! FS.Error => IF error.group # bug THEN { TerminalIO.WriteRope[" not done: "]; TerminalIO.WriteRope[error.explanation]; TerminalIO.WriteLn[]; CONTINUE; } ]; TerminalIO.WriteRope[" spool finished\n"]; }; END; Init[]; END. -- of VersatecImpl FCDBWVersatecImpl.mesa Copyright c 1983, 1985 by Xerox Corporation. All rights reserved. Jacobi, May 29, 1985 6:17:24 pm PDT A package to output a ChipnDale design for the Versatec plotter in Oliver format. That format is defined thus: Bytes 0, 1 (high-order first): The number of bits per Versatec scan line (probably must be divisible by 4). Byte j: Two four-bit nibbles. The high-order nibble tells how many times to repeat the low-order nibble in the output bit stream. A data byte may not carry from one scan line to the next. N. B. This is not a very economical format. You should be able at least to duplicate previous scan lines. written by E. McCreight, August 1, 1983 2:00 PM Last Edited by: McCreight, November 23, 1983 4:58 pm Last Edited by: Jacobi, October 27, 1983 12:36 pm Last Edited by: Jacobi, April 11, 1985 3:20:50 pm PST rectangles in design space touching all geometry in the plot, or this band ---Center the x range of the selected area of the design on the plotter bed, with at most 32 pixels per lambda. If multiple strips are called for, overlap adjacent ones by 100 pixels. --divisible by stippleRepeat, so that textures work out send the length of a scan line to the Versatec clear the bitmap clip to the user-specified design rectangle rectangle in design space that ChipNDale can use to clip its recursive drawing for debugging and to pacify the user --Put lines at boundaries with regions of other color --going south along east edge of tile --going west along north edge of tile This area needs considerable improvement. The ultimate goal is to find a place to put the signal name where it will not be confused with any other geometry (than the named piece, or continuations on the same layer) or signal name. CornerStitching.PerTileProc -- leave a two-scan-line white patch all around Module START code... Κ™˜šœ™Jšœ Οmœ7™BIcode™#—J˜šœo™ošœ™JšœL™L—šœ™Jšœ΅™΅—J˜Jšœk™k—J˜Jšœ0™0J™4J™1J™5J˜šΟk ˜ Jšœ˜Jšžœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšžœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ J˜—šΟbœžœž˜Jšžœžœ₯žœA˜ψJšžœ˜ Jšž˜J˜Jšœžœ Οc˜;Jšœžœ˜+J˜Jšœžœ ˜.J˜Jšœžœ˜J˜Jšœžœ ˜J˜Jš œ žœžœžœžœžœ˜-Jš œžœžœžœžœ˜8J˜šœžœžœ˜Jšœžœ˜Jšœ žœ ˜—Jš œ žœžœžœžœ ˜Aš œ žœžœž œžœ˜+J˜Jšœ˜J˜—Jš œ žœžœžœžœžœžœ˜BJ˜Jšœ žœžœ˜Jšœ žœžœ˜Jšœ žœžœ˜Jšœžœžœ˜J˜Jšœžœžœ ˜#šœ žœžœ˜Jšœžœžœ˜,Jš œžœžœžœžœžœžœ˜BJšœ žœ˜$Jšœ"žœ˜&Jšœžœ ˜*šœžœ˜0JšœJ™J—Jšœ"žœ˜(Jšœ˜J˜J˜—JšœC˜CJ˜šΟnœžœžœ˜Jšœ&˜&Jšœhžœ˜oJšœ/˜/Jšœ<žœK˜ŠJšœW˜WJšœW˜WJšœL˜LJšœU˜UJšœZ˜ZJšœGžœ˜MJšœ?˜?JšœF˜FJ˜J˜—J™š‘œžœžœ˜8Jšžœžœžœžœ˜šœžœ˜*Jšœ˜Jšœžœ$˜0Jšœ˜—šžœž˜ Jšœ#˜#Jšœ%˜%Jšœ+˜+Jšžœ&˜-—Jšžœ˜J˜—š‘œžœžœ˜>Jšžœžœžœžœ˜Jšœ ˜ Jšžœ˜J˜J˜—š‘œžœžœ˜