DIRECTORY AIS, Basics, CedarProcess, Process, DynamicBits, BitmapViewer, Commander, Imager, ImagerBox, ImagerPixelMap, ImagerPressFontSubst, ImagerTransformation, IO, ImagerFont, FontEdit, Real, Rope, RasterFontIO, ViewerClasses, GridModulation, FontTuningParameters, ImagerPixelSeq, PixelMapOps, ImagerMaskCapture, ProcessProps; MakeTunedRasterFontImpl: CEDAR PROGRAM IMPORTS AIS, Basics, CedarProcess, Process, DynamicBits, BitmapViewer, Commander, Imager, ImagerBox, ImagerPixelMap, ImagerPressFontSubst, ImagerTransformation, IO, ImagerFont, FontEdit, Real, Rope, RasterFontIO, GridModulation, FontTuningParameters, ImagerPixelSeq, PixelMapOps, ImagerMaskCapture, ProcessProps ~ BEGIN ROPE: TYPE ~ Rope.ROPE; Font: TYPE ~ ImagerFont.Font; PixelMap: TYPE ~ ImagerPixelMap.PixelMap; DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle; InternalFont: TYPE ~ RasterFontIO.InternalFont; visible: BOOLEAN _ TRUE; bc: CHAR _ CHAR.FIRST; ec: CHAR _ CHAR.LAST; debugpm: PixelMap; VideoInvert: PROC [pm: PixelMap] RETURNS [PixelMap] ~ { pm.Fill[pm.Window, CARDINAL.LAST, [xor, null]]; debugpm _ pm; RETURN [pm]; }; Threshold: PROC [pm: PixelMap] RETURNS [PixelMap] ~ { bb: DeviceRectangle _ pm.Window; new: PixelMap _ ImagerPixelMap.Create[0, bb]; seq: ImagerPixelSeq.PixelSeq _ ImagerPixelSeq.ObtainScratch[bb.fSize]; FOR s: INTEGER IN [bb.sMin..bb.sMin+bb.sSize) DO seq.LoadF[s, bb.fMin, bb.fSize, pm]; FOR j: NAT IN [0..bb.fSize) DO seq[j] _ seq[j] / 128; ENDLOOP; seq.StoreF[s, bb.fMin, bb.fSize, new]; ENDLOOP; ImagerPixelSeq.ReleaseScratch[seq]; RETURN [new]; }; alternating: BOOL _ TRUE; FromFont: PROC [font: Font, param: FontTuningParameters.Ref] RETURNS [internalFont: InternalFont] ~ { bb: Imager.Box _ ImagerBox.BoxFromExtents[ImagerFont.FontBoundingBox[font]]; dbb: ImagerPixelMap.DeviceRectangle _ [Real.RoundLI[-bb.ymax], Real.RoundLI[+bb.xmin], Real.RoundLI[bb.ymax]-Real.RoundLI[bb.ymin], Real.RoundLI[bb.xmax]-Real.RoundLI[bb.xmin]]; viewer: ViewerClasses.Viewer _ IF visible THEN BitmapViewer.Create[[name: font.name], TRUE, center, center] ELSE NIL; pfd: ImagerPressFontSubst.PressFontDescription ~ ImagerPressFontSubst.FindSubstitute[font.name, font.charToClient, press]; internalFont _ RasterFontIO.Create[dbb, dbb.fSize/param.gridReductionFactor]; IF pfd#NIL THEN { internalFont.family _ pfd.family; internalFont.face _ pfd.face; }; internalFont.bitsPerEmQuad _ font.charToClient.SingularValues.x/param.gridReductionFactor; CedarProcess.SetPriority[background]; BEGIN inputBB: ImagerPixelMap.DeviceRectangle _ [dbb.sMin-2, dbb.fMin-2, dbb.sSize+4, dbb.fSize+4]; antialiasingFilter: PixelMap ~ GridModulation.ComputeConvolutionKernel[param.gridReductionFactor]; pmScratch: REF ImagerPixelMap.PixelMapRep _ NIL; sScratch: GridModulation.EdgeProjection _ GridModulation.CreateEdgeProjection[TRUE, 0, inputBB.sSize, param.gridReductionFactor]; fScratch: GridModulation.EdgeProjection _ GridModulation.CreateEdgeProjection[FALSE, 0, inputBB.fSize, param.gridReductionFactor]; model: DynamicBits.Model; ConvertPixelMap: PROC [pixelMap: PixelMap] RETURNS [PixelMap] ~ { rawGray: PixelMap _ GridModulation.ConvertGrayPixelMap[ pixelMap: pixelMap, reductionFactor: param.gridReductionFactor, param: param.gridParam, runSizeMap: runSizeMap, kernel: antialiasingFilter, sScratch: sScratch, fScratch: fScratch, pmScratch: pmScratch ]; gray: PixelMap _ VideoInvert[DynamicBits.AddBorder[rawGray.Trim[0], 2, 0]]; new: PixelMap _ Threshold[gray]; fixedBits: PixelMap; scratch: REF _ NIL; DoTestPass: PROC [passNumber: NAT] ~ { w: DeviceRectangle ~ gray.Window; swath: DeviceRectangle _ [w.sMin, w.fMin, w.sSize, param.swathWidth]; IF alternating AND passNumber MOD 2 = 1 THEN { FOR f: INT DECREASING IN [w.fMin..w.fMin+w.fSize-param.swathWidth) DO swath: DeviceRectangle _ [w.sMin, f, w.sSize, param.swathWidth]; scratch _ DynamicBits.TuneSwath[blurred, new, fixedBits, swath, model, scratch]; Process.CheckForAbort[]; ENDLOOP; } ELSE { FOR f: INT IN [w.fMin..w.fMin+w.fSize-param.swathWidth) DO swath: DeviceRectangle _ [w.sMin, f, w.sSize, param.swathWidth]; scratch _ DynamicBits.TuneSwath[blurred, new, fixedBits, swath, model, scratch]; Process.CheckForAbort[]; ENDLOOP; }; IF viewer # NIL THEN { BitmapViewer.SetBitmap[viewer, VideoInvert[new.Copy]]; }; }; blurred: PixelMap _ gray.Copy; DynamicBits.Convolve[blurred, model.kernel, 255]; fixedBits _ DynamicBits.FindFixedBits[blurred, -model.neighborhood.sMin-model.kernel.sOrigin]; IF viewer # NIL THEN { BitmapViewer.SetBitmap[viewer, VideoInvert[new.Copy]]; }; FOR i: INT IN [0..param.tuningPasses) DO DoTestPass[i]; ENDLOOP; pmScratch _ rawGray.refRep; new _ VideoInvert[new]; RETURN [new.Trim[0]]; }; runSizeMap: GridModulation.RunSizeMap _ GridModulation.SimpleRunSizeMap[MAX[inputBB.sSize, inputBB.fSize], param.gridReductionFactor]; sProjection: GridModulation.EdgeProjection _ GridModulation.CreateEdgeProjection[TRUE, inputBB.sMin-param.gridReductionFactor, inputBB.sSize+2*param.gridReductionFactor, param.gridReductionFactor, NIL]; fProjection: GridModulation.EdgeProjection _ GridModulation.CreateEdgeProjection[FALSE, inputBB.fMin-param.gridReductionFactor, inputBB.fSize+2*param.gridReductionFactor, param.gridReductionFactor, NIL]; printerModel: DynamicBits.PrinterModel ~ { intensity: REAL _ param.intensity[encoding]; scaledIntensity: REAL _ (intensity-minMeanIntensity) / (maxMeanIntensity-minMeanIntensity); RETURN [Real.RoundLI[scaledIntensity*DynamicBits.Intensity.LAST], Real.RoundLI[param.noiseWeight*param.noisePenalty[encoding]]] }; minMeanIntensity: REAL _ 9999999999.9; maxMeanIntensity: REAL _ 0; m: Imager.Transformation ~ ImagerTransformation.Rotate[90]; FOR c: NAT IN [0..param.intensity.length) DO minMeanIntensity _ MIN[minMeanIntensity, param.intensity[c]]; maxMeanIntensity _ MAX[maxMeanIntensity, param.intensity[c]]; ENDLOOP; model _ DynamicBits.CreatePrinterModel[param.printerModelNeighborhood, printerModel, param.comparisonKernel]; FOR c: CHAR IN [bc..ec] DO IF font.Contains[[0,ORD[c]]] THEN { op: PROC[context: Imager.Context] ~ { Char: ImagerFont.XStringProc ~ {charAction[[0, ORD[c]]]}; Imager.SetFont[context, font]; Imager.Show[context, Char]; }; widthVector: Imager.VEC _ ImagerFont.Width[font, [0, ORD[c]]]; pixels: ImagerPixelMap.PixelMap _ ImagerMaskCapture.CaptureBitmap[op, m]; pixels _ pixels.Trim[0]; IF viewer # NIL THEN BitmapViewer.SetBitmap[viewer, pixels]; internalFont.charRep[c] _ [ fWidth: widthVector.x/param.gridReductionFactor, sWidth: -widthVector.y/param.gridReductionFactor, pixels: ConvertPixelMap[pixels] ]; }; ENDLOOP; END; }; ConvertFile: PUBLIC PROC [outputFileName: ROPE, fontName: ROPE, size: REAL, rotation: REAL, bitsPerInch: REAL, param: FontTuningParameters.Ref] ~ { t: Imager.Transformation ~ ImagerTransformation.Scale[size*param.gridReductionFactor].Concat[ImagerTransformation.Rotate[rotation]]; font: Font _ ImagerFont.Find[fontName].Modify[t]; internalFont: InternalFont _ FromFont[font, param]; internalFont.bitsPerInch _ bitsPerInch; FontEdit.WriteFormatDerivedFromName[internalFont, outputFileName]; }; DoTestPass: PROC [passNumber: NAT, blurred: PixelMap, new: PixelMap, fixedBits: PixelMap, model: DynamicBits.Model, scratch: REF, param: FontTuningParameters.Ref, viewer: ViewerClasses.Viewer] RETURNS [newScratch: REF] ~ { w: DeviceRectangle ~ blurred.Window; n: NAT _ SELECT passNumber MOD 4 FROM 0, 2 => w.fSize, 1, 3 => w.sSize, ENDCASE => ERROR; FOR i: INT IN [0..n) DO swath: DeviceRectangle _ SELECT passNumber MOD 4 FROM 0 => [w.sMin, w.fMin+i, w.sSize, param.swathWidth], 1 => [w.sMin+i, w.fMin, param.swathWidth, w.fSize], 2 => [w.sMin, w.fMin+w.fSize-1-i, w.sSize, param.swathWidth], 4 => [w.sMin+w.sSize-1-i, w.fMin, param.swathWidth, w.fSize], ENDCASE => ERROR; scratch _ DynamicBits.TuneSwath[blurred, new, fixedBits, swath, model, scratch]; IF viewer # NIL THEN { BitmapViewer.SetBitmap[viewer, new]; }; Process.CheckForAbort[]; ENDLOOP; RETURN [newScratch] }; rotate: BOOL _ TRUE; randomInit: BOOL _ TRUE; paranoidPass: INT _ LAST[INT]; ConvertAIS: PUBLIC PROC [outputFileName: ROPE, aisName: ROPE, param: FontTuningParameters.Ref, comment: ROPE] ~ { viewer: ViewerClasses.Viewer _ IF visible THEN BitmapViewer.Create[[name: outputFileName]] ELSE NIL; gray: PixelMap _ PixelMapOps.LoadAIS[aisName].pixelMap; new: PixelMap; fixedBits: PixelMap; scratch: REF _ NIL; printerModel: DynamicBits.PrinterModel ~ { intensity: REAL _ param.intensity[encoding]; scaledIntensity: REAL _ (intensity-minMeanIntensity) / (maxMeanIntensity-minMeanIntensity); RETURN [Real.RoundLI[scaledIntensity*DynamicBits.Intensity.LAST], Real.RoundLI[param.noiseWeight*param.noisePenalty[encoding]]] }; model: DynamicBits.Model; minMeanIntensity: REAL _ 9999999999.9; maxMeanIntensity: REAL _ 0; DoTestPass: PROC [passNumber: NAT] ~ { w: DeviceRectangle ~ blurred.Window; FOR f: INT IN [w.fMin..w.fMin+w.fSize-param.swathWidth) DO swath: DeviceRectangle _ [w.sMin, f, w.sSize, param.swathWidth]; scratch _ DynamicBits.TuneSwath[blurred, new, fixedBits, swath, model, scratch]; IF viewer # NIL THEN { BitmapViewer.SetBitmap[viewer, new]; }; IF passNumber>paranoidPass THEN PrintBadness[passNumber*1000+f]; Process.CheckForAbort[]; ENDLOOP; }; PrintBadness: PROC [pass: INT] ~ { WITH ProcessProps.GetProp[$CommanderHandle] SELECT FROM cmd: Commander.Handle => { err: INT _ DynamicBits.ErrorOf[blurred, new, model]; perPixelErr: REAL _ REAL[err]/Basics.LongMult[new.sSize, new.fSize]; cmd.out.PutF["After %g pass(es), badness = %g (%g per pixel)\n", IO.int[pass], IO.int[err], IO.real[perPixelErr]]; }; ENDCASE => NULL; }; rotation: [0..4) _ 0; Rotate: PROC ~ { new _ ImagerPixelMap.Rotate[new]; fixedBits _ ImagerPixelMap.Rotate[fixedBits]; blurred _ ImagerPixelMap.Rotate[blurred]; rotation _ (CARDINAL[rotation] + 1) MOD 4; model _ DynamicBits.RotateModel[model]; scratch _ NIL; new.sOrigin _ new.fOrigin _ fixedBits.sOrigin _ fixedBits.fOrigin _ blurred.sOrigin _ blurred.fOrigin _ 0; }; blurred: PixelMap _ gray.Copy; p: PixelMap; IF randomInit THEN { new _ VideoInvert[DynamicBits.RandomDither[gray]]; } ELSE { new _ ImagerPixelMap.Create[0, gray.Window]; new.TransferTile[ImagerPixelMap.TileFromStipple[5A5AH]]; }; FOR c: NAT IN [0..param.intensity.length) DO minMeanIntensity _ MIN[minMeanIntensity, param.intensity[c]]; maxMeanIntensity _ MAX[maxMeanIntensity, param.intensity[c]]; ENDLOOP; model _ DynamicBits.CreatePrinterModel[param.printerModelNeighborhood, printerModel, param.comparisonKernel]; DynamicBits.Convolve[blurred, model.kernel, 255]; fixedBits _ ImagerPixelMap.Create[0, gray.Window]; fixedBits.Clear[]; PrintBadness[0]; FOR i: INT IN [0..param.tuningPasses) DO DoTestPass[i]; PrintBadness[i+1]; IF rotate THEN Rotate[]; IF viewer # NIL THEN { BitmapViewer.SetBitmap[viewer, new]; }; ENDLOOP; UNTIL rotation = 0 DO Rotate[] ENDLOOP; IF viewer # NIL THEN { BitmapViewer.SetBitmap[viewer, new]; }; StorePixelMap[outputFileName, new, TRUE, comment]; p _ DynamicBits.ApplyModel[new, model]; StorePixelMap[outputFileName.Concat["p"], p, FALSE, comment.Concat[" printer Model"]]; DynamicBits.Convolve[p, model.kernel, 255]; StorePixelMap[outputFileName.Concat["pb"], p, FALSE, comment.Concat[" printer and brain Model"]]; StorePixelMap[outputFileName.Concat["b"], blurred, FALSE, comment.Concat[" original with brain Model"]]; }; StorePixelMap: PROC [aisFileName: ROPE, source: ImagerPixelMap.PixelMap, bitmap: BOOLEAN _ TRUE, comment: ROPE _ NIL] ~ TRUSTED { output: AIS.FRef _ AIS.CreateFile[name: aisFileName, raster: NEW[AIS.RasterPart _ [ scanCount: source.sSize, scanLength: source.fSize, scanMode: rd, bitsPerPixel: IF source.refRep.lgBitsPerPixel = 0 AND bitmap THEN 0 ELSE Basics.BITSHIFT[1, source.refRep.lgBitsPerPixel], linesPerBlock: -1, paddingPerBlock: 65535 ]]]; outputWindow: AIS.WRef _ AIS.OpenWindow[output]; lineMap: ImagerPixelMap.PixelMap _ ImagerPixelMap.Create[source.refRep.lgBitsPerPixel, [source.sOrigin+source.sMin, source.fOrigin+source.fMin, 1, source.fSize]]; lineBufferDesc: AIS.Buffer _ [length: lineMap.refRep.words, addr: lineMap.refRep.pointer]; AIS.WriteComment[output, comment]; FOR i: NAT IN [0..source.sSize) DO lineMap.Clear; lineMap.Transfer[source]; lineMap.sOrigin _ lineMap.sOrigin + 1; AIS.UnsafeWriteLine[outputWindow, lineBufferDesc, i]; ENDLOOP; AIS.CloseFile[output]; }; Break: PROC [char: CHAR] RETURNS [IO.CharClass] = { IF char = '_ OR char = '; THEN RETURN [break]; IF char = ' OR char = ' OR char = ', OR char = '\n THEN RETURN [sepr]; RETURN [other]; }; GetToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE _ NIL] = { rope _ stream.GetTokenRope[Break ! IO.EndOfStream => CONTINUE].token; }; GetReal: PROC [stream: IO.STREAM] RETURNS [real: REAL _ 0.0] = { real _ stream.GetReal[! IO.Error, IO.EndOfStream => CONTINUE]; }; MakeTunedRasterFontCommand: Commander.CommandProc ~ { stream: IO.STREAM _ IO.RIS[cmd.commandLine]; outputName: ROPE _ GetToken[stream]; gets: ROPE _ GetToken[stream]; modelName: ROPE _ GetToken[stream]; inputName: ROPE _ GetToken[stream]; size: REAL _ GetReal[stream]; sizeUnits: ROPE _ GetToken[stream]; bitsPerInch: REAL _ GetReal[stream]; rotation: REAL _ GetReal[stream]; param: FontTuningParameters.Ref _ NIL; IF bitsPerInch = 0.0 THEN bitsPerInch _ 384.0; SELECT TRUE FROM sizeUnits = NIL OR sizeUnits.Equal["pxl", FALSE] => NULL; sizeUnits.Equal["pt", FALSE] => {size _ size/72.0*bitsPerInch}; sizeUnits.Equal["mica", FALSE] => {size _ size/2540.0*bitsPerInch}; ENDCASE => gets _ NIL; IF NOT gets.Equal["_"] OR size <= 0.0 THEN { cmd.out.PutRope[helpRope]; cmd.out.PutChar['\n]; RETURN; }; param _ FontTuningParameters.Load[modelName.Concat[".fontTune"]]; ConvertFile[outputName, inputName, size, rotation, bitsPerInch, param]; }; helpRope: ROPE ~ "Convert a UnifiedFont to raster format\n _ \n is the name of a printer model\n is an Interpress hierarchical name\n is the desired output size\n is pt, mica, or pxl\n is in bits per inch\n is in degrees"; BitTuneAISCommand: Commander.CommandProc ~ { stream: IO.STREAM _ IO.RIS[cmd.commandLine]; outputName: ROPE _ GetToken[stream]; gets: ROPE _ GetToken[stream]; inputName: ROPE _ GetToken[stream]; modelName: ROPE _ GetToken[stream]; param: FontTuningParameters.Ref _ NIL; proc: PROC ~ {ConvertAIS[outputName, inputName, param, Rope.Concat["BitTuneAIS ", cmd.commandLine]]}; IF NOT gets.Equal["_"] OR modelName = NIL THEN { cmd.out.PutRope[helpRopeAIS]; cmd.out.PutChar['\n]; RETURN; }; param _ FontTuningParameters.Load[modelName.Concat[".fontTune"]]; CedarProcess.DoWithPriority[priority: background, action: proc] }; helpRopeAIS: ROPE ~ "Convert a Gray-scale AIS file to one bit per pixel\n _ \n is the name of a printer model\n"; Commander.Register["MakeTunedRasterFont", MakeTunedRasterFontCommand, helpRope]; Commander.Register["BitTuneAIS", BitTuneAISCommand, helpRopeAIS]; END. ’MakeTunedRasterFontImpl.mesa Copyright (C) 1984, Xerox Corporation. All rights reserved. Michael Plass, November 6, 1985 10:27:46 am PST Κ– "cedar" style˜Jšœ™J™<šœ/™/J™—šΟk œœ–œ€˜ΙJ˜—šœœ˜&Jšœœ–œ”˜·šœ˜J˜——Jšœœœ˜Jšœœ˜Jšœ œ˜)Jšœœ"˜7Jšœœ˜/J˜Jšœ œœ˜Jšœœœœ˜šœœœœ˜J˜—Jšœ˜šΟn œœœ˜7Jšœœœ˜/Jšœ ˜ Jšœ˜ Jšœ˜J˜—šž œœœ˜5Jšœ ˜ Jšœ-˜-JšœF˜Fšœœœ˜0Jšœ$˜$šœœœ˜Jšœ˜Jšœ˜—Jšœ&˜&Jšœ˜—Jšœ#˜#Jšœ˜ Jšœ˜J˜—Jšœ œœ˜šžœœ/œ!˜eJšœL˜LJšœ±˜±Jš œœ œ(œœœ˜uJšœz˜zJšœM˜Mšœœœ˜Jšœ!˜!Jšœ˜Jšœ˜—JšœZ˜ZJ˜%š˜Jšœ]˜]Jšœb˜bJšœ œœ˜0JšœNœ/˜JšœNœ/˜‚Jšœ˜šžœœœ˜Ašœ7˜7Jšœ˜Jšœ+˜+Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜—JšœK˜KJšœ ˜ Jšœ˜Jšœ œœ˜šž œœœ˜&Jšœ!˜!JšœE˜Ecodešœ œ œœ˜.š œœ œœ+˜EJšœ@˜@JšœP˜PJšœ˜Jšœ˜—Kšœ˜—šœ˜šœœœ+˜:Jšœ@˜@JšœP˜PJšœ˜Jšœ˜—Kšœ˜—šœ œœ˜Jšœ6˜6J˜—Jšœ˜—Jšœ˜Jšœ1˜1Jšœ^˜^šœ œœ˜Jšœ6˜6J˜—šœœœ˜(Jšœ˜Jšœ˜—Jšœ˜Jšœ˜Jšœ˜Jšœ˜—JšœHœ;˜†JšœQœpœ˜ΚJšœQœpœ˜Λšœ*˜*Jšœ œ˜,šœœ˜JšœC˜C—Jšœ5œ@˜Jšœ˜—Jšœœ˜&Jšœœ˜Jšœ;˜;šœœœ˜,Jšœœ'˜=Jšœœ'˜=Jšœ˜—Jšœm˜mšœœœ ˜šœœœ˜#šœœ˜%Jšœ/œ˜9Jšœ˜Jšœ˜Jšœ˜—Jšœœœ˜>JšœI˜IJšœ˜Jšœ œœ(˜<šœ˜Jšœ0˜0Jšœ1˜1Jšœ˜J˜—J˜—Jš˜—Jšœ˜—Jšœ˜J˜—šž œœœœ œœ œœ&˜“Jšœ„˜„Jšœ1˜1Jšœ3˜3Jšœ'˜'JšœB˜BJšœ˜J˜—š ž œœœ\œAœœ˜ήJšœ$˜$šœœœ œ˜%Kšœ˜Kšœ˜Kšœœ˜—šœœœ˜šœ˜šœ œ˜Kšœ3˜3Kšœ3˜3Kšœ=˜=Kšœ=˜=Kšœœ˜——JšœP˜Pšœ œœ˜Jšœ$˜$J˜—Jšœ˜Jšœ˜—Kšœ ˜Kšœ˜K˜—Jšœœœ˜Jšœ œœ˜Jšœœœœ˜š ž œœœœ œ,œ˜qJš œœ œ-œœ˜dJšœ7˜7Jšœ˜Jšœ˜Jšœ œœ˜šœ*˜*Jšœ œ˜,šœœ˜JšœC˜C—Jšœ5œ@˜Jšœ˜—Jšœ˜Jšœœ˜&Jšœœ˜šž œœœ˜&Jšœ$˜$šœœœ+˜:Jšœ@˜@JšœP˜Pšœ œœ˜Jšœ$˜$J˜—Jšœœ!˜@Jšœ˜Jšœ˜—Jšœ˜—šž œœœ˜"šœ(œ˜7šœ˜Kšœœ,˜4Kšœ œœ,˜DKšœAœ œ œ˜rKšœ˜—Kšœœ˜—Kšœ˜—Kšœ˜šžœœ˜Kšœ!˜!Kšœ-˜-Kšœ)˜)Kšœ œœ˜*Kšœ'˜'Kšœ œ˜Kšœj˜jKšœ˜—Jšœ˜Jšœ ˜ šœ œ˜Kšœ2˜2Kšœ˜—šœ˜Kšœ,˜,Kšœ0Οfœ˜8Kšœ˜—šœœœ˜,Jšœœ'˜=Jšœœ'˜=Jšœ˜—Jšœm˜mJšœ1˜1Jšœ2˜2Jšœ˜J˜šœœœ˜(Jšœ˜Jšœ˜Jšœœ ˜šœ œœ˜Jšœ$˜$J˜—Jšœ˜—Jšœœ œ˜'šœ œœ˜Jšœ$˜$J˜—Jšœ#œ ˜2Jšœ'˜'Jšœ-œ$˜VJšœ+˜+Jšœ.œ.˜aJšœ3œ0˜hJšœ˜J˜—šž œœœ+œœ  œœ˜š œœœ'œœ˜SJšœ˜Jšœ˜Jšœ ˜ Jš œœ"œœœœ"˜zJšœ˜Jšœ˜Jšœ˜—Jšœ0˜0Jšœ’˜’JšœœG˜ZJšœ˜"šœœœ˜"Jšœ˜Jšœ˜Jšœ&˜&Jšœ2˜5Jš˜—Jšœ˜Jšœ˜J˜—– "cedar" styleš žœœœœœ˜3Jšœ œ œœ ˜.Jš œ œ œ œ œœ˜HJšœ ˜Jšœ˜J˜—– "cedar" stylešžœœ œœœœœ˜AJšœ#œœ˜EJšœ˜J˜—– "cedar" styleš žœœ œœœœ ˜@Jšœœœœ˜>Jšœ˜J˜—šžœ˜5Jš œœœœœ˜,Jšœ œ˜$Jšœœ˜Jšœ œ˜#Jšœ œ˜#Jšœœ˜Jšœ œ˜#Jšœ œ˜$Jšœ œ˜!Jšœ"œ˜&Jšœœ˜.šœœ˜Jš œ œœœœ˜9Jšœœ$˜?Jšœœ&˜CJšœ œ˜—šœœœ œ˜,Jšœ˜Jšœ˜Jšœ˜Jšœ˜—JšœA˜AJšœG˜GJšœ˜J˜—šœ œί˜νJ˜—šžœ˜,Jš œœœœœ˜,Jšœ œ˜$Jšœœ˜Jšœ œ˜#Jšœ œ˜#Jšœ"œ˜&Jšœœ[˜eš œœœ œœ˜0Jšœ˜Jšœ˜Jšœ˜Jšœ˜—JšœA˜AJ•StartOfExpansion3[priority: CedarProcess.Priority, action: PROC]šœ?˜?Jšœ˜J˜—šœ œŠ˜›J˜—JšœP˜PšœA˜AJ˜—Jšœ˜J˜—…—:J4