DIRECTORY Args USING [Arg, ArgsGet, Error, NArgs], Atom USING [GetPName], CD USING [Layer, LayerKey], CDColorsExtras USING [ColorNotRegistered, InitialColor, RegisteredColor], Checksum USING [ComputeChecksum], Commander USING [CommandProc, Register], CommandTool USING [NextArgument], FS USING [ComponentPositions, Error, ExpandName, StreamOpen, tText], FSExtras USING [GetWDir], Imager USING [black, Error], ImagerColor USING [ColorFromRGB, ColorOperator, ColorRep, ConstantColor, Find, NarrowToOpConstantColor, OpConstantColor, RGB, SpecialColor], ImagerColorFns USING [CMY, CMYK, CMYFromRGB, HSLFromRGB, NewColorOperatorCMYK], ImagerColorPrivate USING [RGBFromColor], ImagerInterpress USING [DeclareColor, Ref], IO USING [atom, card, Close, EndOf, EndOfStream, Error, GetAtom, GetCard, GetCedarTokenRope, GetIndex, GetInt, GetLength, GetLineRope, int, PutF, PutFR, PutRope, RIS, real, rope, SetIndex, STREAM, TokenKind], MessageWindow USING [Append, Blink, Clear], NamedColors USING [HSLToRope], NectarineColors, Real USING [Float, InlineRoundC, Round], RealFns USING [AlmostZero], RefTab USING [Create, EachPairAction, EqualProc, Erase, Fetch, GetSize, HashProc, Insert, Pairs, Ref], Rope USING [Cat, Equal, Fetch, IsEmpty, ROPE, Substr], RuntimeError USING [UNCAUGHT], SymTab USING [Ref, Create, GetSize, Fetch, Store, Val], TerminalIO USING [PutF, PutRope], UserProfile USING [Boolean, Token], ViewerOps USING [BlinkDisplay]; NectarineColorsImpl: CEDAR PROGRAM IMPORTS Args, Atom, CD, CDColorsExtras, Checksum, Commander, CommandTool, FS, FSExtras, Imager, ImagerColor, ImagerColorFns, ImagerColorPrivate, ImagerInterpress, IO, MessageWindow, NamedColors, Real, RealFns, RefTab, Rope, RuntimeError, SymTab, TerminalIO, UserProfile, ViewerOps EXPORTS NectarineColors ~ BEGIN OPEN NectarineColors, Real, RealFns; ROPE: TYPE ~ Rope.ROPE; RGB: TYPE ~ ImagerColor.RGB; CMYK: TYPE ~ ImagerColorFns.CMYK; cmyk255: ImagerColor.ColorOperator ~ ImagerColorFns.NewColorOperatorCMYK [255]; colSubDef: PUBLIC BOOL _ TRUE; -- default for colour substitution traceColourInferences: PUBLIC BOOL _ FALSE; obeyToChipNDale: BOOL _ FALSE; magicNumber: CARDINAL ~ 557; -- or 997 debug: BOOL _ TRUE; break: SIGNAL ~ CODE; -- for debugging argError, lastWDir: ROPE; currentlyUsedLayers: Bitset; currentlyUsedLayerNames: SymTab.Ref _ SymTab.Create [magicNumber]; aqua, black, blue, brown, colourBlack, cyan, doubleYellow, green, grey, lightMagenta, lightYellow, lime, magenta, orange, pink, red, turquise, ultraviolet, undefColour, violet, white, yellow: Color; blackRGB, blueRGB, cyanRGB, doubleYellowRGB, greenRGB, magentaRGB, redRGB, yellowRGB: RGB; blackBlack, orableBackground: PUBLIC Color; unColour: PUBLIC RGB; cyanCMYK: Color ~ ColorFromCMYK [[1.0, 0.0, 0.0, 0.0]]; magentaCMYK: Color ~ ColorFromCMYK [[0.0, 1.0, 0.0, 0.0]]; yellowCMYK: Color ~ ColorFromCMYK [[0.0, 0.0, 1.0, 0.0]]; blackCMYK: Color ~ ColorFromCMYK [[0.0, 0.0, 0.0, 1.0]]; blueCMYK: Color ~ ColorFromCMYK [[1.0, 1.0, 0.0, 0.0]]; redCMYK: Color ~ ColorFromCMYK [[0.0, 1.0, 1.0, 0.0]]; greenCMYK: Color ~ ColorFromCMYK [[1.0, 0.0, 1.0, 0.0]]; greenishBlackCMYK: Color ~ ColorFromCMYK [[1.0, 0.0, 1.0, 1.0]]; greyCMYK: Color ~ ColorFromCMYK [[0.0, 0.0, 0.0, 0.5]]; UseSimpleColours: PUBLIC PROC [] ~ BEGIN undefColour _ NIL; unColour _ [0.0, 0.0, 0.0]; blackRGB _ [0.0, 0.0, 0.0]; blackBlack _ blackCMYK; colourBlack _ Imager.black; grey _ greyCMYK; white _ ImagerColor.ColorFromRGB [rgb: [R: 1, G: 1, B: 1]]; red _ redCMYK; green _ greenCMYK; blueRGB _ [0.0, 0.0, 1.0]; cyan _ cyanCMYK; magentaRGB _ [1.0, 0.0, 1.0]; magenta _ magentaCMYK; lightMagenta _ ImagerColor.ColorFromRGB [[5.0/7.0, 0.0, 5.0/7.0]]; doubleYellowRGB _ [2.0, 2.0, 0.0]; doubleYellow _ ImagerColor.ColorFromRGB [doubleYellowRGB]; lightYellow _ ImagerColor.ColorFromRGB [[13.0/14.0, 13.0/14.0, 10.0/21.0]]; yellow _ yellowCMYK; violet _ ImagerColor.ColorFromRGB [rgb: [R: 0.45, G: 0.25, B: 0.75]]; brown _ ImagerColor.ColorFromRGB [rgb: [R: 0.64, G: 0.2752, B: 0.16]]; orange _ ImagerColor.ColorFromRGB [rgb: [R: 0.64, G: 0.2752, B: 0.16]]; -- we prefer our orange lime _ ImagerColor.ColorFromRGB [rgb: [R: 0.39, G: 0.75, B: 0.75]]; turquise _ ImagerColor.ColorFromRGB [rgb: [R: 0.42, G: 0.7, B: 0.92]]; aqua _ ImagerColor.ColorFromRGB [rgb: [R: 0.42, G: 0.92, B: 0.55]]; ultraviolet _ ImagerColor.ColorFromRGB [rgb: [R: 0.13, G: 0, B: 0.33]]; pink _ ImagerColor.ColorFromRGB [rgb: [R: 0.9, G: 0.45, B: 0.55]]; -- we need a bit more red and less green in it orableBackground _ CDColorsExtras.InitialColor []; black _ blackCMYK; blue _ blueCMYK END; -- UseSimpleColours UseSqueezedColours: PUBLIC PROC [] ~ BEGIN undefColour _ NIL; unColour _ [0.0, 0.0, 0.0]; blackRGB _ [0.0, 0.0, 0.0]; blackBlack _ blackCMYK; colourBlack _ Imager.black; grey _ greyCMYK; white _ ImagerColor.ColorFromRGB [rgb: [R: 1, G: 1, B: 1]]; redRGB _ [R: 0.916726, G: 2.183968e-2, B: 2.917295e-2]; -- [0.59, 0.335], 5.31 red _ ImagerColor.ColorFromRGB [redRGB]; greenRGB _ [R: -0.2129092, G: 1.04013, B: 0.1963416]; -- [0.25, 0.525], 17.53 green _ ImagerColor.ColorFromRGB [greenRGB]; blueRGB _ [R: 1.158857e-2, G: 8.760574e-2, B: 0.2601715]; -- [0.2, 0.2], 2.16 cyanRGB _ [R: -0.2437036, G: 1.042247, B: 1.25352]; -- [0.2, 0.3], 19.69 cyan _ ImagerColor.ColorFromRGB [cyanRGB]; magentaRGB _ [R: 0.5401293, G: 0.1748126, B: 0.7118298]; -- [0.29, 0.21], 7.47 magenta _ ImagerColor.ColorFromRGB [rgb: magentaRGB]; lightMagenta _ ImagerColor.ColorFromRGB [[5.0/7.0*magentaRGB.R, 0.0, 5.0/7.0*magentaRGB.B]]; yellowRGB _ [R: 1.495448, G: 0.8532933, B: -0.0296737]; -- [0.47, 0.48], 22.83 yellow _ ImagerColor.ColorFromRGB [rgb: yellowRGB]; doubleYellowRGB _ [2*yellowRGB.R, 2*yellowRGB.G, 2*yellowRGB.B]; lightYellow _ ImagerColor.ColorFromRGB [[13.0/14.0*yellowRGB.R, 13.0/14.0*yellowRGB.G, 10.0/21.0*yellowRGB.B]]; violet _ ImagerColor.ColorFromRGB [rgb: [R: 0.45, G: 0.25, B: 0.75]]; brown _ ImagerColor.ColorFromRGB [rgb: [R: 0.64, G: 0.2752, B: 0.16]]; orange _ ImagerColor.ColorFromRGB [rgb: [R: 0.64, G: 0.2752, B: 0.16]]; -- we prefer our orange lime _ ImagerColor.ColorFromRGB [rgb: [R: 0.39, G: 0.75, B: 0.75]]; turquise _ ImagerColor.ColorFromRGB [rgb: [R: 0.42, G: 0.7, B: 0.92]]; aqua _ ImagerColor.ColorFromRGB [rgb: [R: 0.42, G: 0.92, B: 0.55]]; ultraviolet _ ImagerColor.ColorFromRGB [rgb: [R: 0.13, G: 0, B: 0.33]]; pink _ ImagerColor.ColorFromRGB [rgb: [R: 0.9, G: 0.45, B: 0.55]]; -- we need a bit more red and less green in it orableBackground _ CDColorsExtras.InitialColor []; black _ ImagerColor.ColorFromRGB [blackRGB]; blue _ ImagerColor.ColorFromRGB [blueRGB]; doubleYellow _ ImagerColor.ColorFromRGB [doubleYellowRGB] END; -- UseSqueezedColours layerColorTable: ARRAY CD.Layer OF Color; -- must be set for each task Rule: TYPE ~ PROC [layer: ATOM, colour: REF ANY] RETURNS [next: Rule, sameLayer: ATOM, newColour: Color]; decided: Rule ~ NIL; r1, r2, esc: Color _ NIL; -- to monitor the contents of the registries layerNumberHack: CD.Layer; -- cd registry uses number instead of name LayerColour: PUBLIC PROC [l: CD.Layer] RETURNS [Color] ~ BEGIN RETURN [layerColorTable[l]] END; -- LayerColour MakeConstant: PROC [any: REF ANY] RETURNS [c: Color] ~ BEGIN cc: ImagerColor.ConstantColor ~ NARROW [any]; TRUSTED BEGIN c _ LOOPHOLE [ImagerColor.NarrowToOpConstantColor [cc ! Imager.Error => {c _ NIL; ViewerOps.BlinkDisplay; CONTINUE}]] END END; -- MakeConstant ColourName: PROC [c: Color] RETURNS [ROPE] ~ BEGIN IF (c = NIL) THEN RETURN ["---"]; IF (ISTYPE [c, ImagerColor.SpecialColor]) THEN BEGIN sc: ImagerColor.SpecialColor ~ NARROW [c, ImagerColor.SpecialColor]; RETURN [sc.name] END; RETURN [NamedColors.HSLToRope [ImagerColorFns.HSLFromRGB[RGBFromColour[c]],3]] END; -- ColourName Decide: PROC [rule: Rule, l: ATOM, c: Color] RETURNS [Color] ~ BEGIN WHILE (rule # decided) DO [rule, l, c] _ rule [l, c] ENDLOOP; InferenceStatus [l, "NIL", "has been inferred"]; RETURN [c] END; -- Decide InferenceStatus: PROC [object: ATOM, rule, status: ROPE] ~ BEGIN msg: ROPE ~ Atom.GetPName[object].Cat [". Deciding rule ", rule, ": ", status]; MessageWindow.Clear; MessageWindow.Append [msg]; IF traceColourInferences THEN TerminalIO.PutF ["%g\n", IO.rope [msg]] END; -- InferenceStatus InferenceResult: PROC [object: ATOM, colour: Color] ~ BEGIN rgb: RGB ~ RGBFromColour [colour]; cmyk: CMYK ~ CMYKFromRGB [rgb]; TerminalIO.PutF ["%l%g.%l ", IO.rope ["b"], IO.atom [object], IO.rope ["B"]]; TerminalIO.PutF ["CNS: (registry 1: %g; registry 2: %g) inferred: %g\n", IO.rope [ColourName [r1]], IO.rope [ColourName [r2]], IO.rope [ColourName [colour]]]; TerminalIO.PutF ["CMYK: [%g, %g, %g, %g]\n", IO.real [cmyk.C], IO.real [cmyk.M], IO.real [cmyk.Y], IO.real [cmyk.K]]; TerminalIO.PutF ["RGB: [%g, %g, %g]\n", IO.real [rgb.R], IO.real [rgb.G], IO.real [rgb.B]] END; -- InferenceResult One: Rule ~ BEGIN InferenceStatus [layer, "One", "registry-1/cmos-b"]; r1 _ newColour _ ImagerColor.Find [Rope.Cat ["Xerox/Research/ChipNDale/CMosB/", Atom.GetPName [layer]]]; IF (newColour # NIL) THEN RETURN [Six, layer, newColour] ELSE RETURN [Two, layer, newColour] END; -- One Two: Rule ~ BEGIN InferenceStatus [layer, "Two", "registry-1/chipndale"]; r1 _ newColour _ ImagerColor.Find [Rope.Cat ["Xerox/Research/ChipNDale/CD/", Atom.GetPName [layer]]]; IF (newColour # NIL) THEN RETURN [Seven, layer, newColour] ELSE RETURN [Five, layer, newColour] END; -- Two Three: Rule ~ BEGIN InferenceStatus [layer, "Three", "registry-1/cmos-b"]; r1 _ newColour _ ImagerColor.Find [Rope.Cat ["Xerox/Research/ChipNDale/CMosB/", Atom.GetPName [layer]]]; IF (newColour # NIL) THEN RETURN [Ten, layer, newColour] ELSE RETURN [Four, layer, newColour] END; -- Three Four: Rule ~ BEGIN InferenceStatus [layer, "Four", "registry-1/chipndale"]; r1 _ newColour _ ImagerColor.Find [Rope.Cat ["Xerox/Research/ChipNDale/CD/", Atom.GetPName [layer]]]; IF (newColour # NIL) THEN RETURN [Ten, layer, newColour] ELSE RETURN [NIL, layer, blackBlack] END; -- Four Five: Rule ~ BEGIN InferenceStatus [layer, "Five", "registry-2"]; r2 _ newColour _ CDColorsExtras.RegisteredColor [layerNumberHack ! CDColorsExtras.ColorNotRegistered => {newColour _ NIL; CONTINUE}]; IF (newColour # NIL) THEN RETURN [Eight, layer, newColour] ELSE RETURN [Eleven, layer, newColour] END; -- Five Six: Rule ~ BEGIN InferenceStatus [layer, "Six", "constant inheritance"]; newColour _ MakeConstant [colour]; IF (newColour # NIL) THEN RETURN [NIL, layer, newColour] ELSE RETURN [Two, layer, newColour] END; -- Six Seven: Rule ~ BEGIN InferenceStatus [layer, "Seven", "constant inheritance"]; newColour _ MakeConstant [colour]; IF (newColour # NIL) THEN RETURN [NIL, layer, newColour] ELSE RETURN [Five, layer, newColour] END; -- Seven Eight: Rule ~ BEGIN InferenceStatus [layer, "Eight", "constant inheritance"]; newColour _ MakeConstant [colour]; IF (newColour # NIL) THEN RETURN [NIL, layer, newColour] ELSE RETURN [Eleven, layer, newColour] END; -- Eight Nine: Rule ~ BEGIN InferenceStatus [layer, "Nine", "escape value"]; esc _ newColour _ SELECT layer FROM $nwel => lightYellow, $met => cyan, $met2 => lightMagenta, $cut, $comment => blackBlack, $cut2 => blue, $gate => doubleYellow, $xneutral => blackBlack, $xred => red, $xyellow => yellow, $xgreen => green, $xcyan => cyan, $xviolet => violet, $xmagenta => magenta, $xwhite => white, $xbrown => brown, $xorange => orange, $xlime => lime, $xturquise => turquise, $xaqua => aqua, $xultraviolet => ultraviolet, $xpink => pink, $xsmoke => grey, $xblue => blue, ENDCASE => NIL; IF (newColour # NIL) THEN RETURN [NIL, layer, newColour] ELSE RETURN [One, layer, newColour] END; -- Nine Ten: Rule ~ BEGIN InferenceStatus [layer, "Ten", "constant inheritance"]; newColour _ MakeConstant [colour]; IF (newColour # NIL) THEN RETURN [NIL, layer, newColour] ELSE RETURN [NIL, layer, blackBlack] END; -- Ten Eleven: Rule ~ BEGIN InferenceStatus [layer, "Eleven", "no colour"]; RETURN [NIL, layer, undefColour] END; -- Eleven Twelve: Rule ~ BEGIN InferenceStatus [layer, "Twelve", "discriminable value"]; IF (currentColourMap = NIL) THEN RETURN [Nine, layer, newColour]; FOR i: CARDINAL IN [0 .. currentColourMap.size) DO IF (currentColourMap[i].layers.GetSize = 1) THEN BEGIN fetched: ATOM; found: BOOL; val: SymTab.Val; [found, val] _ currentColourMap[i].layers.Fetch [Atom.GetPName [layer]]; fetched _ NARROW [val, ATOM]; IF found AND (fetched = layer) THEN BEGIN newColour _ ColorFromRGB [currentColourMap[i].colour, currentColourMap[i].index]; IF (newColour = NIL) THEN ERROR; RETURN [NIL, layer, newColour] END -- found it END -- entry is for a single layer ENDLOOP; RETURN [Nine, layer, newColour] END; -- Twelve SetLayerColourTable: PUBLIC PROC RETURNS [ok: BOOL _ TRUE] ~ BEGIN r1 _ undefColour; IF (undefColour = NIL) THEN undefColour _ Decide [Three, $UndefLayer, NIL]; IF traceColourInferences THEN InferenceResult [$UndefLayer, undefColour]; ok _ (r1 # NIL); FOR i: CD.Layer IN CD.Layer DO layer: ATOM ~ CD.LayerKey [i]; IF (layer = NIL) OR (layerColorTable[i] # NIL) THEN LOOP; IF DoLineArt[] THEN BEGIN IF UseProcessColors[] THEN SELECT layer FROM $met => layerColorTable[i] _ cyanCMYK; $met2 => layerColorTable[i] _ magentaCMYK; $ndif, $pdif => layerColorTable[i] _ greenCMYK; $pol => layerColorTable[i] _ redCMYK; $cut, $cut2 => layerColorTable[i] _ blackCMYK; ENDCASE => layerColorTable[i] _ NIL ELSE SELECT layer FROM $met => -- cyan separation for C28 blue layerColorTable[i] _ cyanCMYK; $met2 => -- yellow separation for M35/2 magenta layerColorTable[i] _ yellowCMYK; $ndif, $pdif => -- black separation for GT4 green layerColorTable[i] _ IF UserProfile.Boolean ["Nectarine.ContinuousTone", FALSE] THEN greenCMYK ELSE blackCMYK; $pol => -- magenta separation for RT6 red layerColorTable[i] _ magentaCMYK; $cut, $cut2 => -- cyan, black, & magenta separations for black layerColorTable[i] _ greenishBlackCMYK; ENDCASE => layerColorTable[i] _ NIL; ok _ TRUE; LOOP END; IF SubColours[] THEN BEGIN usedColour: Color; layerNumberHack _ i; usedColour _ IF obeyToChipNDale THEN Decide [One, layer, NIL] ELSE Decide [Twelve, layer, NIL]; IF traceColourInferences THEN InferenceResult [layer, usedColour]; IF (r1 = NIL) THEN ok _ FALSE; IF (r2 # NIL) AND traceColourInferences THEN BEGIN MessageWindow.Clear; MessageWindow.Append [IO.PutFR ["Substituting color %g for %g\n", IO.rope [ColourName [usedColour]], IO.rope [ColourName [r2]]]] END; IF (usedColour = NIL) THEN break; layerColorTable[i] _ usedColour END ELSE BEGIN IF (layerColorTable[i] # NIL) THEN LOOP; layerColorTable[i] _ CDColorsExtras.RegisteredColor [i ! CDColorsExtras.ColorNotRegistered => {layerColorTable[i] _ undefColour; ok _ FALSE; CONTINUE}]; IF (layerColorTable[i] = undefColour) THEN TerminalIO.PutF ["\nNo color is available from ChipNDale for layer %g\n",IO.atom [layer]]; IF (layerColorTable[i] = NIL) THEN break; END ENDLOOP END; -- SetLayerColourTable ResetLayerColourTable: PUBLIC PROC RETURNS [ok: BOOL _ TRUE] ~ BEGIN IF NOT DoLineArt[] THEN UseSimpleColours; FOR i: CD.Layer IN CD.Layer DO layerColorTable[i] _ NIL; currentlyUsedLayers[i] _ FALSE ENDLOOP; blendedColourTable.Erase; ok _ SetLayerColourTable [] END; -- ResetLayerColourTable blendedColourTable: RefTab.Ref ~ RefTab.Create [magicNumber, Match, Hash]; EachCTEntry: TYPE ~ PROC [colour: Color, layers: LIST OF ATOM]; colourCacheSize: CARDINAL ~ 256; ColourCacheRep: TYPE ~ ARRAY [1 .. colourCacheSize] OF Color _ ALL [NIL]; colourCache: REF ColourCacheRep _ NEW [ColourCacheRep]; ColourTile: PUBLIC PROC [old: Blend, l: CD.Layer] RETURNS [new: Blend] ~ BEGIN key: BlendKey ~ NEW [Bitset _ old.flavours]; key[l] _ TRUE; new _ NARROW [blendedColourTable.Fetch[key].val, Blend]; IF (new = NIL) THEN BEGIN copy: Blend _ NEW [BlendRec _ [flavours: old.flavours]]; copy.count _ SUCC [old.count]; copy.flavours[l] _ TRUE; copy.used _ TRUE; new _ copy; IF NOT blendedColourTable.Insert [key, copy] THEN ERROR; currentlyUsedLayers[l] _ TRUE END ELSE BEGIN new.used _ TRUE; END END; -- ColourTile BlendColourForATile: RefTab.EachPairAction ~ BEGIN components: Blend ~ NARROW [val]; n: REAL _ Float [components.count]; comp: PACKED ARRAY CD.Layer OF BOOLEAN _ components.flavours; mix, v: RGB _ unColour; IF (components.blend # NIL) THEN RETURN [FALSE]; -- caching across sessions SELECT n FROM 0 => ERROR; -- should never have been allocated 1 => IF (currentColourMap = NIL) THEN BEGIN i: CD.Layer _ 0; WHILE NOT comp[i] DO i _ SUCC [i] ENDLOOP; components.blend _ LayerColour [i]; IF (components.blend = NIL) THEN ERROR; RETURN [FALSE] END; ENDCASE => NULL; -- the normal case IF (currentColourMap # NIL) THEN BEGIN fetched: ATOM; val: SymTab.Val; found, allFound: BOOL; FOR i: CARDINAL IN [0 .. currentColourMap.size) DO IF (currentColourMap[i].layers.GetSize # components.count) THEN LOOP; allFound _ TRUE; FOR k: CD.Layer IN CD.Layer DO IF comp[k] THEN BEGIN layer: ATOM ~ CD.LayerKey [k]; [found, val] _ currentColourMap[i].layers.Fetch [Atom.GetPName [layer]]; fetched _ NARROW [val, ATOM]; IF (NOT found) OR (fetched # layer) THEN {allFound _ FALSE; LOOP} END ENDLOOP; IF allFound THEN BEGIN components.index _ currentColourMap[i].index; components.blend _ ColorFromRGB [currentColourMap[i].colour, currentColourMap[i].index]; RETURN [FALSE] END ENDLOOP; IF traceColourInferences THEN BEGIN TerminalIO.PutRope ["\nThere is no colour for"]; FOR k: CD.Layer IN CD.Layer DO IF comp[k] THEN TerminalIO.PutF [" %g", IO.atom [CD.LayerKey [k]]] ENDLOOP; TerminalIO.PutRope ["\n"] END END; BEGIN poly, diff, met, met2, cut, cut2, well: CD.Layer _ 0; IF (n = 1) THEN BEGIN i: CD.Layer _ 0; WHILE NOT comp[i] DO i _ SUCC [i] ENDLOOP; components.blend _ LayerColour [i]; IF (components.blend = NIL) THEN ERROR; RETURN [FALSE] END; FOR i: CD.Layer IN CD.Layer DO IF comp[i] THEN SELECT CD.LayerKey [i] FROM $pol => poly _ i; $ndif, $pdif => diff _ i; $met => met _ i; $met2 => met2 _ i; $nwel => well _ i; $cut, $comment => cut _ i; $cut2 => {cut _ i; cut2 _ i}; ENDCASE => NULL ENDLOOP; IF (cut # 0) THEN components.blend _ LayerColour [cut] ELSE BEGIN -- Assume: all other colours have the same weight. IF (poly # 0) AND (diff # 0) THEN BEGIN -- Handle gates. mix _ doubleYellowRGB; comp[poly] _ comp[diff] _ FALSE END; IF (poly # 0) AND (met # 0) AND (diff = 0) THEN BEGIN mix _ magentaRGB; n _ n - 1.0; comp[poly] _ comp[met] _ FALSE END; FOR i: CD.Layer IN CD.Layer DO -- Compute mean colour. IF comp[i] THEN BEGIN IF CD.LayerKey[i] = $nwel THEN LOOP; -- ignore wells under material v _ RGBFromColour [layerColorTable[i]]; mix.R _ mix.R + v.R; mix.G _ mix.G + v.G; mix.B _ mix.B + v.B END ENDLOOP; IF (well # 0) THEN BEGIN -- make wells transparent n _ n - 1.0 END; IF (met2 # 0) AND (well # 0) AND (n > 2) THEN BEGIN -- make metal-2 transparent mix.R _ mix.R - 4.0/7.0; mix.B _ mix.B - 4.0/7.0; n _ n - 4.0/7.0 END; mix.R _ mix.R / n; mix.G _ mix.G / n; mix.B _ mix.B / n; components.blend _ ColorFromRGB [mix, 0]; components.index _ 1; components.used _ TRUE END; -- not a contact IF (components.blend = NIL) THEN break; END; RETURN [FALSE] END; -- BlendColourForATile BlendTileColours: PUBLIC PROC ~ BEGIN [] _ blendedColourTable.Pairs [BlendColourForATile]; END; -- BlendTileColours Hash: RefTab.HashProc ~ BEGIN TRUSTED BEGIN RETURN [Checksum.ComputeChecksum [0, SIZE [BlendKey], LOOPHOLE [key]]] END END; -- Hash Match: RefTab.EqualProc ~ BEGIN k1: BlendKey ~ NARROW [key1]; k2: BlendKey ~ NARROW [key2]; RETURN [(k1^ = k2^)] END; -- Match NumberOfColours: PUBLIC PROC RETURNS [INT] ~ BEGIN n: CARD _ 0; IF DoLineArt[] THEN RETURN [4]; IF SubColours[] THEN BEGIN FOR index: CARDINAL IN [1 .. colourCacheSize] DO IF (colourCache[index] # NIL) THEN n _ n.SUCC ENDLOOP; RETURN [n] END ELSE BEGIN FOR c: CD.Layer IN CD.Layer DO IF (layerColorTable[c] # NIL) THEN n _ n.SUCC; ENDLOOP; RETURN [n] END END; -- NumberOfColours DeclareColours: PUBLIC PROC [master: ImagerInterpress.Ref] ~ BEGIN master.DeclareColor [blackCMYK]; IF DoLineArt[] THEN BEGIN master.DeclareColor [cyanCMYK]; master.DeclareColor [magentaCMYK]; master.DeclareColor [greenCMYK]; IF UseProcessColors[] THEN master.DeclareColor [redCMYK] ELSE BEGIN master.DeclareColor [yellowCMYK]; master.DeclareColor [greenishBlackCMYK] END; RETURN END; IF SubColours[] THEN FOR index: CARDINAL IN [1 .. colourCacheSize] DO IF (colourCache[index] # NIL) THEN master.DeclareColor [colourCache[index]] ENDLOOP ELSE FOR c: CD.Layer IN CD.Layer DO IF (layerColorTable[c] # NIL) THEN master.DeclareColor [layerColorTable[c]] ENDLOOP END; -- DeclareColours IthColour: PUBLIC PROC [i: INT] RETURNS [Color] ~ BEGIN RETURN [colourCache[i.ABS]] END; -- IthColour ListColourStatistics: PUBLIC PROC [numberOfTiles: CARD] ~ BEGIN totalArea: REAL _ 0.0; -- It is the way it is because of numerical stability. ComputeArea: RefTab.EachPairAction ~ BEGIN data: Blend ~ NARROW [val]; totalArea _ totalArea + Float [data.area] END; -- ComputeArea ListEntry: RefTab.EachPairAction ~ BEGIN data: Blend ~ NARROW [val]; cmyk: CMYK ~ CMYKFromRGB [RGBFromColour [data.blend]]; IF NOT data.used THEN RETURN; IF totalArea = 0.0 THEN totalArea _ 1.0; TerminalIO.PutF ["%g\t%g\t%g\t\t%g\t\t%g\t", IO.real [cmyk.C], IO.real [cmyk.M], IO.real [cmyk.Y], IO.real [cmyk.K], IO.real [Float[data.area] / totalArea]]; FOR i: CD.Layer IN CD.Layer DO IF data.flavours[i] THEN TerminalIO.PutF [" %g", IO.atom [CD.LayerKey[i]]] ENDLOOP; TerminalIO.PutF ["\t-- %g --\n", IO.rope [ColourName[data.blend]]] END; -- ListEntry TerminalIO.PutF ["Statistical data gathered by Nectarine:\n\tSize of color table: %g; number of tiles: %g\n\tColor (CMYK), relative area and layers\n", IO.int [blendedColourTable.GetSize[]], IO.int [numberOfTiles]]; [] _ blendedColourTable.Pairs [ComputeArea]; IF debug THEN BEGIN [] _ blendedColourTable.Pairs [ListEntry]; TerminalIO.PutRope ["Colors with null area were intermediate.\n"] END END; -- ListColourStatistics ResetColourStatistics: PUBLIC PROC ~ BEGIN ResetArea: RefTab.EachPairAction ~ {rec: Blend ~ NARROW [val]; rec.area _ 0}; [] _ blendedColourTable.Pairs [ResetArea] END; -- ResetColourStatistics ExpandBlendedColourTable: PROC [action: EachCTEntry] ~ BEGIN DoEntry: RefTab.EachPairAction ~ BEGIN data: Blend ~ NARROW [val]; layers: LIST OF ATOM; FOR l: CD.Layer IN CD.Layer DO IF data.flavours[l] THEN layers _ CONS [CD.LayerKey[l], layers]; ENDLOOP; action [data.blend, layers] END; -- DoEntry [] _ blendedColourTable.Pairs [DoEntry]; END; -- ExpandBlendedColourTable WriteMap: PUBLIC PROC [fileName: ROPE, msg: IO.STREAM _ NIL] ~ BEGIN file: IO.STREAM; i: CARDINAL _ 0; WriteColor: EachCTEntry ~ BEGIN rgb: RGB ~ RGBFromColour [colour]; file.PutF ["%g\t%g\t%g\t%g", IO.card [i], IO.card [Round [255.0 * rgb.R]], IO.card [Round [255.0 * rgb.G]], IO.card [Round [255.0 * rgb.B]]]; FOR l: LIST OF ATOM _ layers, l.rest WHILE (l # NIL) DO file.PutF [" %g", IO.atom [l.first]] ENDLOOP; file.PutRope ["\n"]; i _ i.SUCC END; -- WriteColor file _ FS.StreamOpen [fileName: fileName, accessOptions: create, keep: 3, createByteCount: 5000, fileType: FS.tText, extendFileProc: NIL]; file.PutRope ["ColorMap\nonesAreWhite\nBitsPerPixel 8\n"]; ExpandBlendedColourTable [WriteColor]; IF (msg # NIL) THEN msg.PutF ["\nRename pippo _ %g\n", IO.rope [fileName]]; file.Close []; ImportantMessage [fileName] END; -- WriteMap WriteMapCommand: Commander.CommandProc ~ BEGIN fn: Args.Arg; cp: FS.ComponentPositions; pippo: BOOL; name: ROPE _ "New.ColorMap"; lastWDir _ cmd.command.Substr [0, FS.ExpandName[cmd.command].cp.base.start-1]; IF (NumberOfColours[] = 0) THEN RETURN [$Failure, "Process some layout first (e.g. NectarineTest, VTIRules)."]; IF (Args.NArgs [cmd] # 0) THEN BEGIN [fn] _ Args.ArgsGet [cmd, "-a%s" ! Args.Error => {argError _ reason; GOTO failure}]; IF fn.ok THEN name _ fn.rope END; [name, cp, pippo] _ FS.ExpandName [name, WDir []]; IF (cp.ext.length = 0) THEN name _ name.Cat [".ColorMap"]; WriteMap [name, cmd.out]; EXITS failure => RETURN [$Failure, argError] END; -- WriteMapCommand ColourMapEntry: TYPE ~ RECORD [colour: RGB, index: INT, layers: SymTab.Ref]; ColourMapRep: TYPE ~ RECORD [SEQUENCE size: CARDINAL OF ColourMapEntry]; currentColourMap: REF ColourMapRep; -- cache ReadMap: PUBLIC PROC [fileName: ROPE] ~ BEGIN rec, file: IO.STREAM; token: ROPE; firstToken: IO.TokenKind; size, i: CARDINAL _ 0; rgb: RGB; cp: FS.ComponentPositions; [fileName, cp, ] _ FS.ExpandName [fileName, WDir []]; IF (cp.ext.length = 0) THEN fileName _ fileName.Cat [".ColorMap"]; file _ FS.StreamOpen [fileName: fileName, wDir: WDir [], extendFileProc: NIL ! FS.Error => GOTO noFile]; DO rec _ IO.RIS [file.GetLineRope [! IO.EndOfStream => {EXIT}; IO.Error => {break}], rec]; [tokenKind: firstToken, token: token] _ rec.GetCedarTokenRope [! IO.EndOfStream => {EXIT}]; IF ((firstToken = tokenDECIMAL) OR ((firstToken = tokenSINGLE) AND (token.Fetch [] = '-))) THEN size _ size.SUCC ENDLOOP; file.SetIndex [0]; currentColourMap _ NEW [ColourMapRep[size]]; blendedColourTable.Erase; FOR i: CARDINAL IN [1 .. colourCacheSize] DO colourCache[i] _ NIL ENDLOOP; DO rec _ IO.RIS [file.GetLineRope [! IO.EndOfStream => {EXIT}], rec]; currentColourMap[i].index _ rec.GetInt [! IO.EndOfStream, IO.Error => {LOOP}]; -- header rgb _ [Float [rec.GetCard[]] / 255.0, Float [rec.GetCard[]] / 255.0, Float [rec.GetCard[]] / 255.0]; currentColourMap[i].colour _ rgb; IF (currentColourMap[i].index > 0) AND (currentColourMap[i].index <= colourCacheSize) THEN [] _ ColorFromRGB [rgb, currentColourMap[i].index]; currentColourMap[i].layers _ SymTab.Create [7]; DO -- find all layers to which this entry concerns IF (rec.GetIndex < rec.GetLength) THEN BEGIN layer: ATOM _ rec.GetAtom; [] _ currentColourMap[i].layers.Store [key: Atom.GetPName [layer], val: layer] END ELSE EXIT ENDLOOP; IF file.EndOf [] THEN EXIT; i _ i.SUCC; IF (i > size) THEN break ENDLOOP; file.Close; rec.Close; [] _ ResetLayerColourTable []; BlendTileColours; TerminalIO.PutRope [fileName.Cat[" loaded.\n"]] EXITS noFile => ImportantMessage [fileName.Cat[" not found. Check pseudo-servers."]] END; -- ReadMap ReadMapCommand: Commander.CommandProc ~ BEGIN name: ROPE _ CommandTool.NextArgument [cmd]; lastWDir _ cmd.command.Substr [0, FS.ExpandName[cmd.command].cp.base.start-1]; IF name.IsEmpty THEN name _ "[DATools7.0]Discriminable.ColorMap"; ReadMap [name] END; -- ReadMapCommand RGBFromColour: PROC [c: Color] RETURNS [rgb: RGB] ~ BEGIN WITH c SELECT FROM constant: ImagerColor.ConstantColor => rgb _ ImagerColorPrivate.RGBFromColor [constant]; ENDCASE => rgb _ unColour; RETURN [rgb] END; -- RGBFromColour CMYKFromRGB: PROC [rgb: RGB] RETURNS [CMYK] ~ BEGIN IF (AlmostZero [rgb.R, -9]) AND (AlmostZero [rgb.G, -9]) AND (AlmostZero [rgb.B, -9]) THEN RETURN [[0.0, 0.0, 0.0, 1.0]] ELSE BEGIN cmy: ImagerColorFns.CMY ~ ImagerColorFns.CMYFromRGB [rgb]; min: REAL ~ MIN [cmy.C, cmy.M, cmy.Y]; RETURN [[cmy.C - min, cmy.M - min, cmy.Y - min, min]] END END; -- CMYKFromRGB ColorFromRGB: PROC [rgb: RGB, hint: INTEGER _ 0] RETURNS [Color] ~ BEGIN colour: Color _ NIL; IF (hint # 0) AND (hint <= colourCacheSize) THEN colour _ colourCache[hint.ABS]; IF (colour # NIL) THEN RETURN [colour]; IF UserProfile.Boolean [key: "Nectarine.ContinuousTone", default: FALSE] THEN colour _ ImagerColor.ColorFromRGB [rgb] ELSE colour _ IF (AlmostZero [rgb.R, -9]) AND (AlmostZero [rgb.G, -9]) AND (AlmostZero [rgb.B, -9]) THEN blackCMYK ELSE ColorFromCMYK [CMYKFromRGB [rgb]]; IF (hint # 0) AND (hint <= colourCacheSize) THEN colourCache[hint.ABS] _ colour; RETURN [colour] END; -- ColorFromRGB SampleFromReal: PROC [r: REAL] RETURNS [CARDINAL] ~ BEGIN RETURN [InlineRoundC [MIN[MAX[r, 0.0], 1.0] * 255]]; END; -- SampleFromReal ColorFromCMYK: PROC [cmyk: CMYK] RETURNS [ImagerColor.OpConstantColor] ~ BEGIN colour: ImagerColor.OpConstantColor ~ NEW [ImagerColor.ColorRep.constant.op[4]]; colour.colorOperator _ cmyk255; colour.pixel[0] _ SampleFromReal [cmyk.C]; colour.pixel[1] _ SampleFromReal [cmyk.M]; colour.pixel[2] _ SampleFromReal [cmyk.Y]; colour.pixel[3] _ SampleFromReal [cmyk.K]; RETURN [colour]; END; -- ColorFromCMYK ImportantMessage: PROC [msg: ROPE] ~ BEGIN TerminalIO.PutRope [msg]; TerminalIO.PutRope ["\n"]; MessageWindow.Clear []; MessageWindow.Append [msg]; MessageWindow.Blink [] END; -- ImportantMessage doc: ROPE ~ "explains why a color is selected.\nUsage: NQuery CD.Layer\n\tExample: _ CMosB.met\n\t6\n\tNQuery 6"; QueryRule: Commander.CommandProc ~ BEGIN layer: ROPE ~ CommandTool.NextArgument [cmd]; layerName: ATOM; layerColour: Color; prevTraceValue: BOOL ~ traceColourInferences; lastWDir _ cmd.command.Substr [0, FS.ExpandName[cmd.command].cp.base.start-1]; IF layer.IsEmpty THEN layerNumberHack _ CD.Layer.LAST ELSE layerNumberHack _ IO.GetInt [IO.RIS [layer] ! RuntimeError.UNCAUGHT => {result _ $Failure; msg _ doc; CONTINUE}]; IF (result = $Failure) THEN RETURN; layerName _ CD.LayerKey [layerNumberHack]; traceColourInferences _ TRUE; IF (layerName = NIL) THEN layerColour _ Decide [Three, $UndefLayer, NIL] ELSE layerColour _ IF obeyToChipNDale THEN Decide [One, layerName, NIL] ELSE Decide [Twelve, layerName, NIL]; InferenceResult [layerName, layerColour]; traceColourInferences _ prevTraceValue END; -- QueryRule ChangeColours: Commander.CommandProc ~ BEGIN a, b: Args.Arg; what: INTEGER _ 0; colours: ROPE _ "[DATools7.0]Discriminable.ColorMap"; lastWDir _ cmd.command.Substr [0, FS.ExpandName[cmd.command].cp.base.start-1]; IF (Args.NArgs [cmd] # 0) THEN BEGIN [a, b] _ Args.ArgsGet [cmd, "-a[i-b[s" ! Args.Error => {argError _ reason; GOTO failure}]; IF a.ok THEN what _ a.int; IF b.ok THEN colours _ b.rope END; obeyToChipNDale _ FALSE; UseSimpleColours; SELECT what FROM 0 => ReadMap [colours]; 1 => obeyToChipNDale _ TRUE; 2 => NULL; 3 => UseSqueezedColours; ENDCASE => ERROR; IF (what # 0) THEN BEGIN currentColourMap _ NIL; colourCache _ NEW [ColourCacheRep]; [] _ ResetLayerColourTable [] END; EXITS failure => RETURN [$Failure, argError] END; -- ChangeColours UseProcessColors: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [UserProfile.Boolean [key: "Nectarine.ProcessColors", default: TRUE]] END; -- UseProcessColors DoLineArt: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [UserProfile.Boolean [key: "Nectarine.LineArt", default: FALSE]] END; -- DoLineArt SubColours: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [UserProfile.Boolean [key: "Nectarine.SubstituteColors", default: colSubDef]] END; -- SubColours WDir: PROC RETURNS [wDir: ROPE] ~ BEGIN wDir _ FSExtras.GetWDir []; IF wDir.Equal ["[]<>"] AND (NOT lastWDir.IsEmpty) THEN wDir _ lastWDir; IF wDir.Equal ["[]<>"] THEN wDir _ "[]<>7.0>DATools>" END; -- WDir IF NOT DoLineArt[] THEN UseSimpleColours; IF SubColours [] THEN ReadMap [UserProfile.Token ["Nectarine.Palette", "[DATools7.0]Discriminable.ColorMap"]]; Commander.Register [key: "NQuery", proc: QueryRule, doc: doc]; Commander.Register [key: "NWriteColors", proc: WriteMapCommand, doc: "Writes the colors used by Nectarine in a file using the extended color map format.\nSwitch a: file name."]; Commander.Register [key: "NReadColors", proc: ReadMapCommand, doc: "Loads the table of blended colours from a extended color map file.\nSwitch a: file name."]; Commander.Register [key: "NOldColors", proc: ChangeColours, doc: "Do not use (recrerates the colors used in the past). Switch a:\n\t1: obey to ChipNDale\n\t2: simple colors\n\t3: compressed colors\nno switch: used balanced colors.\nSwitch b overrides the default extended color map."] END. =ΚNectarineColorsImpl.mesa Copyright Σ 1987, 1988 by Xerox Corporation. All rights reserved. Giordano Bruno Beretta, June 24, 1987 9:16:35 am PDT gbb October 14, 1988 11:46:24 am PDT Jean-Marc Frailong December 12, 1988 12:04:27 pm PST Inference engine for the colour registries and colour blending. WARNING: Because of the mapping from layers to ChipNDale numbers, it is assumed that only one technology at the time is used (caches in global variables). Inference engine [registry-1 = Imager, registry-2 = ChipNDale]: Rule 1: if registry-1/cmos-b defines named colour then Decide [rule 6, registered colour], else Decide [rule 2, named colour]. Rule 2: if registry-1/ChipNDale defines named colour then Decide [rule 7, registered colour], else Decide [rule 5, named colour]. Rule 3: if registry-1/cmos-b defines named colour then Decide [rule 10, registered colour], else Decide [rule 4, named colour]. Rule 4: if registry-1/ChipNDale defines named colour then Decide [rule 10, registered colour], else Decide [NIL, BLACK]. Rule 5: if registry-2 defines named colour then Decide [rule 8, registered colour], else Decide [rule 11, name]. Rule 6: if named colour can inherit a constant color then Decide [NIL, constant color] else Decide [rule 2, registered colour]. Rule 7: if named colour can inherit a constant color then Decide [NIL, constant color] else Decide [rule 5, registered colour]. Rule 8: if named colour can inherit a constant color then Decide [NIL, constant color] else Decide [rule 11, registered colour]. Rule 9: if colour has an escape value then Decide [NIL, escape color] else Decide [Rule 1, registered colour]. Rule 10: if named colour can inherit a constant color then Decide [NIL, constant color] else Decide [NIL, BLACK]. Rule 11: Decide [NIL, undefined colour] Rule 12: if layer is in the extended color map or was previously determined then Decide [NIL, this color] else Decide [Rule 9, any colour]. Basic palette Cached colours: Set the colors to the values obtained by simply speading the hues. Set the colors to the values obtained by simply speading the hues. "-- [x, y], Y" means that we computed CalibratedColorFns.XYZFromChromaticity [[x, y], Y] cyanRGB _ [R: 0.0, G: 1.285951, B: 1.497224]; Colouring single layers Recurses down the inheritance hierarchy until a constant colour is found. If at the end there is no constant colour, the Imager blinks the screen and raises Error. I catch the error, reproduce the blinking, and recover. Can handle nil and named colours. Spread out hues & make "more subtractive". In ChipNdale 23 cut (cut-2) was always black (blue), but in rel. 24 was displayed black (blue) and printed blue (green). Look up in extended color map. The reason this prodedure is so complex is that at the time it was last revised, ChipNDale no longer allowed clients to get the contastant colours for the layers. An alternate source for these colours is the colour registry. Unfortunately, at the time of this writing, ChipNDale does not load the colour registry before it starts. Furthermore, ChipNdale duplicates the code and state of the colour registry, so that colour rendition depends on the load state, rendering useless Nectarine's loading of the colour registry. All this towaboo has cost a month and a half of wated work. Original code in this procedure: Spread out hues & make "more subtractive" using the HSL colour model. Infer undefined colour first, because it is the default of last resort if all rules fail. Must be called whenever the user profile entry for the colour substitution changes. Colouring intersecting layers: Colour blending stuff that used to be in NectarineImpl Data is global Adds a new layer to the set of layers intersecting in a tile. Sets up a blending record for a tile. Must be fast as a bullet. Record this layer as being currently used, for the usage of pre-blended colour from a colour map. IF NOT blendedColourTable.Replace [key, new] THEN ERROR Takes the layers covering a tile and blend an RBG-colour out of them. [key: Key, val: Value] RETURNS [quit: BOOLEAN _ FALSE] If there is more than a layer, I first look the blend up in the colour map if it exists. Otherwise a colour is blended from the layer colours. Sequentially examine all entries of the colour map. If the i-th entry in the colour map is for a different number of layers, then the entry does not apply. We are here either because there is no colour map or because the colour map did not contain a blend for the particular intersection combination. Find exception layers. Cuts always win. Reinitialize mix by yellow and eliminate poly and diff. Since gates are very important, they are given double weight. Handle metal over poly. Wells are now ignored if they are under material. To change them back to being transparent, take out the LOOP statement from the above FOR loop and de-comment the following two lines: mix.R _ mix.R - 5.0/7.0; mix.G _ mix.G - 5.0/7.0; n _ n - 5.0/7.0; mix.B _ mix.B - (3.0/7.0 * 2.0/7.0) -- take out well lightener There are a lot of caches around, and there might be an order problem during laundry. If the following happens, you can probably abort and retry: The logarithm of the number of colours is two, that of the rectangles is six. PROC [key: Key] RETURNS [CARDINAL] PROC [key1, key2: Key] RETURNS [BOOL] Number of different combinations of layers. This is the number of colours that the following procedure would declare in the Interpress master. RETURN [blendedColourTable.GetSize []] Declares colours in the preamble. PerDiscriminableColour: RefTab.EachPairAction ~ BEGIN blendRec: Blend ~ NARROW [val]; IF (blendRec.blend # NIL) AND (blendRec.index >= 0) THEN master.DeclareColor [blendRec.blend]; RETURN [FALSE] END; -- PerDiscriminableColour Returns the i-th color. Lists the statistics on the colour table. We initialize only the area so as to cache colour blendings across sessions. Colouring intersecting layers: Colour blending with the MetaPalette The problem here is that the ChipNDale layers are allocated when a technology is initilized. Therefore, the mapping from a layer key to a layer number is not known a priory. The trick is to keep the last extended color map global and to maintain a symbol table to map a layer into it's most recent number. Color blending must then be performed in two steps: first the last extended color map is re-enumerated with the current layer symbol table, then the old blending algorithm is applied. 1. Writing colour maps Was exported by NectarineBackdoor. Dumps the table of blended colours into an extended color map file. PROC [colour: Color, layers: LIST OF ATOM] PROC [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] 2. Reading colour maps Loads the table of blended colours from an extended color map file. The file must have been written either by this module or by the MetaPalette; there is no consistency check. [tokenKind: firstToken, token: token] _ rec.GetCedarTokenRope [! IO.EndOfStream => {LOOP}]; -- there are empty lines IF ((firstToken = tokenSINGLE) AND (token.Fetch [] = '-)) THEN [firstToken, token] _ rec.GetCedarTokenRope []; IF NOT (firstToken = tokenDECIMAL) THEN LOOP; IF (AlmostZero [rgb.R, -9]) AND (AlmostZero [rgb.G, -9]) AND (AlmostZero [rgb.B, -9]) THEN currentColourMap[i].colour _ [0, 0, 0] ReadMapCommand: Commander.CommandProc ~ BEGIN PROC [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] fn: Args.Arg; name: ROPE _ "Discriminable.ColorMap"; lastWDir _ cmd.command.Substr [0, FS.ExpandName[cmd.command].cp.base.start-1]; IF (Args.NArgs [cmd] # 0) THEN BEGIN [fn] _ Args.ArgsGet [cmd, "-a%s" ! Args.Error => {argError _ reason; GOTO failure}]; IF fn.ok THEN name _ fn.rope END; ReadMap [name]; EXITS failure => RETURN [$Failure, argError] END; -- ReadMapCommand PROC [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] Varia RgbKey: TYPE ~ REF RGB; colourCache: RefTab.Ref _ RefTab.Create [59, SameColour, RgbHash]; RgbHash: PROC [k: RefTab.Key] RETURNS [CARDINAL] ~ BEGIN PROC [Key] RETURNS [CARDINAL] TRUSTED {RETURN [Checksum.ComputeChecksum [0, SIZE [RGB], LOOPHOLE [k]]]} END; -- RgbHash SameColour: PROC [key1, key2: RefTab.Key] RETURNS [BOOL] ~ BEGIN RefTab.EqualProc k1: RgbKey ~ NARROW [key1]; k2: RgbKey = NARROW [key2]; RETURN [(k1^ = k2^)] END; -- SameColour Assume that LayerColour had previously been called. Converts from RGB to CMYK. Writes a message in the ChipNDale terminal viewer and in the Message Window at the top of the LF screen and makes it blink. PROC [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] Explains why a color is selected. PROC [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] Recrerates the colors used in the past. Guarantees that the working directory is not the root. Initial code to tune colours document: TiogaAccess.Writer = TiogaAccess.Create []; vanillaLook: TiogaAccess.Looks = ALL [FALSE]; vanillaChar: TiogaAccess.TiogaChar = [0, 0C, vanillaLook, $lead3, FALSE, FALSE, 0, NIL]; symbolLook, charLook, labelLook: TiogaAccess.Looks _ vanillaLook; InitDocument: PROC ~ BEGIN Causes document to be printed in landscape format. Must hang on root node. rootCharacter: TiogaAccess.TiogaChar _ vanillaChar; -- 1st char written rootCharacter.endOfNode _ TRUE; rootCharacter.deltaLevel _ 1; rootCharacter.propList _ Atom.PutPropOnList [propList: rootCharacter.propList, prop: $Postfix, val: TiogaAccess.GetInternalProp [$Postfix, "11 in pageWidth 8.5 in pageLength"]]; TiogaAccess.Put [document, rootCharacter] END; WriteChar: PROC [c: CHAR, l: TiogaAccess.Looks _ charLook] ~ BEGIN tc: TiogaAccess.TiogaChar _ vanillaChar; tc.char _ c; tc.looks _ l; TiogaAccess.Put [document, tc] END; -- WriteChar WriteTab: PROC [] ~ BEGIN tab: CHAR = 'I - 100B; WriteChar [tab] END; -- WriteTab PutRope: PROC [r: Rope.ROPE, l: TiogaAccess.Looks _ labelLook] ~ BEGIN PutChar: Rope.ActionType ~ {WriteChar [c, l]}; [] _ Rope.Map [base: r, action: PutChar] END; -- PutRope WriteEOL: PROC ~ BEGIN tc: TiogaAccess.TiogaChar _ vanillaChar; tc.endOfNode _ TRUE; TiogaAccess.Put [document, tc] END; -- WriteEOL WriteNewPage: PROC ~ BEGIN tc: TiogaAccess.TiogaChar _ vanillaChar; tc.endOfNode _ TRUE; tc.format _ $pageBreak; TiogaAccess.Put [document, tc] END; -- WriteNewPage WriteBigLead: PROC ~ BEGIN tc: TiogaAccess.TiogaChar _ vanillaChar; tc.endOfNode _ TRUE; tc.format _ $lead3; TiogaAccess.Put [document, tc]; TiogaAccess.Put [document, tc] END; -- WriteBigLead WriteReal: PROC [n: REAL] ~ BEGIN buffer: REF TEXT _ NEW [TEXT]; buffer _ Convert.AppendReal [to: buffer, from: n, precision: 3]; WriteTab []; FOR i: NAT IN [0 .. buffer.length) DO WriteChar [buffer[i]] ENDLOOP END; -- WriteReal FindAllColours: Commander.CommandProc ~ BEGIN Find all currently defined colours and write them into a Tioga document. vt: Terminal.Virtual ~ Terminal.Current []; prevTech: CD.Technology _ NIL; InitDocument []; FOR layer: CD.Layer IN CD.Layer DO tech: CD.Technology ~ CD.LayerTechnology[layer]; key: ATOM _ CD.LayerKey [layer]; rgb: RGB ~ RGBFromColor [LayerColour [layer]]; hsl: HSL ~ HSLFromRGB [rgb]; IF (key # NIL) THEN BEGIN IF (tech # prevTech) THEN BEGIN prevTech _ tech; WriteBigLead []; IF (tech # NIL) THEN PutRope [tech.name] ELSE PutRope ["Unnamed Technology"]; WriteEOL [] END; IF (tech # NIL) THEN {PutRope [tech.name, charLook]; WriteChar ['.]}; PutRope [Atom.GetPName [key]]; WriteTab []; PutRope ["R, G, B: "]; WriteReal [rgb.R]; WriteReal [rgb.G]; WriteReal [rgb.B]; WriteTab []; PutRope ["H, S, L: "]; WriteReal [hsl.H]; WriteReal [hsl.S]; WriteReal [hsl.L]; WriteEOL [] END; ENDLOOP; IF (Terminal.GetColorBitmapState [vt] = displayed) THEN BEGIN ir, ig, ib: Terminal.ColorValue; norm: REAL ~ 1.0 / Float [LAST[Terminal.ColorValue]]; WriteBigLead []; PutRope ["Contents of the ColorMap (r, g, b):"]; WriteEOL []; FOR i: Terminal.ChannelValue IN Terminal.ChannelValue DO [ir, ig, ib] _ Terminal.GetColor [vt, i]; WriteReal [Float[ir] * norm]; WriteReal [Float[ig] * norm]; WriteReal [Float[ib] * norm]; WriteEOL [] ENDLOOP END; TiogaAccess.WriteFile [document, "[]<>Users>Beretta.pa>CD>NectarineTune.tioga"]; TerminalIO.PutRope ["[]<>Users>Beretta.pa>CD>NectarineTune.tioga created.\n"] END; -- FindAllColours symbolLook ['l] _ TRUE; symbolLook ['m] _ TRUE; labelLook ['l] _ TRUE; labelLook ['b] _ TRUE; charLook ['l] _ TRUE; Initialization gbb October 27, 1987 1:19:04 pm PST Clean-up. changes to: OPEN, black, blackBlack, blackRGB, UseSimpleColours, LayerColour, SetLayerColourTable, RGBFromColour, UseSimpleColours, Commander. gbb November 2, 1987 3:46:08 pm PST Changed to start inferring from rule 9 instead of 1. changes to: Five, Eight, Nine, Eleven: new rule of last resort, SetLayerColourTable gbb November 25, 1987 5:12:19 pm PST Merged colour blending from NectarineImpl into NectarineHyperRegistryImpl and renamed it into NectarineColourImpl. changes to: DIRECTORY, NectarineColorsImpl, IMPORTS, EXPORTS, OPEN, DeclareColours, PerColour (local of DeclareColours), EachCTEntry, NumberOfColours, ListColourStatistics, ResetColourStatistics gbb November 27, 1987 5:05:47 pm PST Allow for colours to be read from a colour map. changes to: DIRECTORY, IMPORTS, OPEN, aqua, blackRGB, blackBlack, unColour, Rule, ResetLayerColourTable, blendedColourTable, EachCTEntry, ColourTile, BlendColourForATile, BlendTileColours, NumberOfColours, DeclareColours, ListColourStatistics, ResetColourStatistics, ExpandBlendedColourTable, DoEntry (local of ExpandBlendedColourTable), WriteMap, WriteColor (local of WriteMap), ColourMapEntry, ColourMapRep, currentColourMap, ReadMap, ReadMapCommand, Commander, Commander, Commander gbb November 30, 1987 6:23:16 pm PST Added Rule 12 to look first of all in the colour map. changes to: layerColorTable, layerColorSymTable, Twelve, SetLayerColourTable, BlendColourForATile, ReadMap gbb December 4, 1987 12:23:23 pm PST Wells are now ignored if they are under material. changes to: BlendColourForATile, ListEntry (local of ListColourStatistics) gbb December 5, 1987 10:56:47 am PST The balanced color map is loaded by default. changes to: initialization. gbb December 31, 1987 4:04:39 pm PST New user profile option Nectarine.ContinuousTone: BOOL _ FALSE. Set to TRUE when separations are created by an electronic color scanner or by photographic halftoning. changes to: LayerColour, InferenceResult, BlendColourForATile, ListEntry (local of ListColourStatistics), CMYKFromRGB, ColorFromRGB gbb January 5, 1988 6:18:09 pm PST Introduced line art. changes to: LayerColour, SetLayerColourTable, SubColours, WDir, IF, IF gbb January 9, 1988 4:00:46 pm PST Re-implemented high resolution high speed halftoning. changes to: LayerColour, Twelve, BlendColourForATile, ColourMapEntry, ReadMap. gbb January 28, 1988 3:02:01 pm PST More speed and less space by tuning cache hits. changes to: unColour, cyanCMYK, magentaCMYK, yellowCMYK, blackCMYK, blueCMYK, greenCMYK, greenishBlackCMYK, greyCMYK, UseSimpleColours, UseSqueezedColours, Twelve, SetLayerColourTable, EachCTEntry, colourCacheSize, ColourCacheRep, colourCache, BlendColourForATile, DeclareColours, ColourMapEntry, ReadMap, RGBFromColour, ColorFromRGB gbb February 8, 1988 1:04:22 pm PST Changed UCR algorithm to produce smaller and faster Interpress masters. changes to: DIRECTORY, IMPORTS, OPEN, NumberOfColours, CMYKFromRGB, ColorFromRGB gbb February 10, 1988 9:56:47 pm PST Added user profile option for color palette. changes to: DIRECTORY, IF gbb February 18, 1988 11:18:29 am PST Added user profile option to generate line art to be printed with process colors. changes to: blueCMYK, redCMYK, UseSimpleColours, SetLayerColourTable, UseProcessColors, DoLineArt gbb October 14, 1988 11:45:48 am PDT New color model operator using 8 instead of 10 bits per color. changes to: DIRECTORY, cmyk, RGBFromColour, ColorFromRGB, SampleFromReal, ColorFromCMYK Κ+Π˜codešœ™KšœB™BJšœ4™4K™$K™4—K™Icode2™?šΟbœ“™š™?J™~J™J™JšœlΟkœžœ™xJ™pJšœBžœ:™JšœBžœ:™JšœBžœ;™€Jšœ3žœ8™nJšœCžœžœžœ™qJšœžœ™'JšœYžœ/™‹——šž ˜ Kšœžœ˜(Kšœžœ ˜Kšžœžœ˜Kšœžœ5˜IKšœ žœ˜!Kšœ žœ˜(Kšœ žœ˜!Kšžœžœ<˜DKšœ žœ ˜Kšœžœ˜Kšœ žœhžœ˜ŒKšœžœžœžœ0˜OKšœžœ˜(Kšœžœ˜+Kšžœžœšžœžœ ˜ΠKšœžœ˜+Kšœ žœ ˜Kšœ˜Kšœžœ˜(Kšœžœ˜KšœžœZ˜fKšœžœžœ ˜6Kšœ žœžœ˜Kšœžœ+˜7Kšœ žœ˜!Kšœ žœ˜#Kšœ žœ˜—LšΠlnœžœž˜"Lšžœ žœ4žœWžœs˜˜Lšžœž˜šžœ ˜$Iunitšžœžœžœ˜Kšžœžœžœ˜Kšžœžœžœ˜!LšœO˜OMšœ žœžœžœΟc"˜BKšœžœžœžœ˜+Kšœžœžœ˜Lšœ žœ  ˜&Lšœžœžœ˜Kšœžœžœ ˜'Lšœžœ˜Lšœ˜KšœB˜B—head™ LšœΖ˜ΖKšœVžœ˜ZKšœžœ˜+Kšœ žœžœ˜L™Kšœ7˜7Kšœ:˜:Kšœ9˜9Kšœ8˜8Kšœ7˜7Kšœ6˜6Kšœ8˜8Kšœ@˜@Kšœ7˜7šΟnœž œž˜(K™BKšœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ;˜;Mšœ˜Kšœ˜Kšœ˜Mšœ˜Kšœ˜Kšœ˜KšœB˜BKšœ"˜"Kšœ:˜:KšœK˜KKšœ˜MšœE˜EKšœF˜FKšœH ˜_KšœC˜CKšœF˜FKšœC˜CKšœG˜GKšœC .˜qMšœ2˜2Lšœ˜Kšœ˜Kšžœ ˜—š‘œž œž˜*K™BMšœX™XKšœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ;˜;Mšœ;˜NKšœ(˜(Kšœ9˜MKšœ,˜,Kšœ=˜MMšœ8˜IKšœ-™-Kšœ*˜*Kšœ<˜NKšœ5˜5Kšœ\˜\Kšœ;˜NKšœ3˜3Kšœ@˜@Kšœo˜oMšœE˜EKšœF˜FKšœH ˜_KšœC˜CKšœF˜FKšœC˜CKšœG˜GKšœC .˜qMšœ2˜2Lšœ,˜,Kšœ*˜*Kšœ9˜9Kšžœ ˜——šœ™Lšœžœžœžœ ˜FMšœžœžœ žœ žœžœžœžœ˜iKšœžœ˜Kšœžœ ,˜FKšœžœ *˜Eš ‘ œžœžœžœžœ ž˜>Kšžœ˜Kšžœ ˜—š ‘ œžœžœžœžœž˜Kšœ'˜'—Kšžœžœ˜$—KšœžœΠbk˜Kšžœ˜—šžœžœž˜Kšœ˜Kšœ˜Kš œ žœžœžœžœžœ˜_Kšžœžœ%˜BKšžœžœžœžœ˜š žœžœžœžœž˜2Kšœ˜Kšœžœ*žœ!žœ˜€Kšžœ˜—Kšžœžœžœ˜!Kšœ˜Kšž˜—šžœž˜ Kšžœžœžœžœ˜(Kšœ†žœžœ˜˜Kšžœ$žœJžœ˜…Kšžœžœžœ˜)Kšž˜—Kšž˜—Kšžœ ˜—š ‘œžœžœžœžœžœž˜DJšœS™SKšžœžœ žœ˜)š žœžœžœžœž˜Kšœžœž˜8Kšžœ˜—Kšœ5˜5Kšžœ ˜——šœU™UN™LšœJ˜JKš œ žœžœžœžœžœ˜?Kšœžœ˜ Kš œžœžœžœ žœžœ˜IKšœ žœžœ˜7š ‘ œžœžœžœžœž˜NL™=K™@Kšœžœ˜,Kšœ žœ˜Kšœžœ,˜8šžœžœžœž˜Kšœžœ'˜8Kšœ žœ ˜Kšœžœžœ˜*Kšœ ˜ Kšžœžœ'žœžœ˜8K™aLšœž˜Kšž˜—šžœž˜ Kšœ žœ˜Kšžœžœ'žœž™7Kšž˜—Kšžœ  ˜—š‘œž˜2Kšœ.žœ™EKšœžœžœžœ™6Kšœžœ˜!Kšœžœ˜#Kš œžœžœžœžœžœ˜=Kšœžœ ˜Mš žœžœžœžœžœ ˜Kšžœž˜ Kšœžœ #˜/šœžœžœžœž˜+Kšœžœ ˜Kš žœžœ žœžœžœ˜*Kšœ#˜#Kšžœžœžœžœ˜'Kš’œžœ˜Kšžœ˜—Kšžœžœ ˜#—K™Žšžœžœžœž˜&Kšœ žœ$žœ˜6K™3šžœžœžœž˜2Kšœg™gKšžœ9žœžœ˜EKšœ žœ˜š žœžœžœžœž˜šžœžœž˜Kšœžœžœ˜KšœH˜HKšœ žœžœ˜Kš žœžœžœžœ žœžœ˜AKšž˜—Kšžœ˜—šžœ žœž˜Kšœ-˜-KšœX˜XKš’œžœ˜Kšž˜—Kšžœ˜—šžœžœž˜#Kšœ0˜0š žœžœžœžœž˜Kšžœ žœžœžœ˜BKšžœ˜—Kšœ˜Kšž˜—Kšžœ˜—K™šž˜Kšœ(žœ ˜5šžœžœž˜Kšœžœ ˜Kš žœžœ žœžœžœ˜*Kšœ#˜#Kšžœžœžœžœ˜'Kš’œžœ˜Kšžœ˜—K™š žœžœžœžœž˜š žœ žœžœžœž˜+Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšžœž˜—Kšžœ˜—K™Kšžœ žœ%˜6šžœžœ 2˜=š žœ žœ žœžœ ˜8Kšœu™uKšœ˜Kšœž˜Kšžœ˜—š žœ žœ žœ žœž˜5Kšœ™Kšœ˜Kšœž˜Kšžœ˜—š žœžœžœžœžœ ˜6šžœ žœž˜Kš žœžœžœžœ ˜CKšœ'˜'Kšœ=˜=Kšž˜—Kšžœ˜—šžœ žœžœ ˜2Kšœ ˜ K™·KšœB™BKšœ$ ™>Kšžœ˜—š žœ žœ žœ žœžœ ˜OKšœA˜AKšžœ˜—Kšœ8˜8Kšœ)˜)Kšœ(ž˜,Kšžœ ˜—K™‘Kšžœžœžœ˜'Kšžœ˜—Kšžœžœ˜Kšžœ ˜—š‘œžœžœž˜%KšœM™MKšœ4˜4Kšžœ ˜—š‘œž˜Kšžœ žœžœ™"šžœž˜ Kšžœžœ žœ˜FKšž˜—Kšžœ ˜ —š‘œž˜Lšžœžœžœ™%Kšœžœžœ˜;Kšžœ˜Kšžœ ˜ —š ‘œž œžœžœž˜2L™ŽKšœžœ˜ Kšžœ žœžœ˜šžœžœž˜šžœžœžœž˜0Kšžœžœžœž˜-Kšžœ˜—Kšžœ˜ Kšž˜—šžœž˜ š žœžœžœžœž˜Kšžœžœžœžœ˜.Kšžœ˜—Kšžœ˜ Kšž˜—Kšžœ ™&Lšžœ ˜—š‘œžœžœ"ž˜BL™!š‘œž™5Kšœžœ™šžœžœžœž™8Kšœ%™%—Kšžœžœ™Kšžœ ™—Mšœ ˜ šžœ žœž˜KšœB˜BKšœ ˜ Kšžœžœ˜8šžœž˜ KšœI˜IKšžœ˜—Kš’˜Kšžœ˜—š žœžœžœžœžœž˜EKšžœžœžœ)˜KKšž˜—š žœžœžœžœžœž˜#Kšžœžœžœ)˜KKšž˜—Lšžœ ˜—š ‘ œž œžœžœ ž˜7K™Kšžœžœ˜Kšžœ  ˜—š ‘œžœžœžœž˜?K™)Kšœ žœ 6˜Mš‘ œž˜*Kšœžœ˜Kšœ)˜)Kšžœ ˜—š‘ œž˜(Kšœžœ˜Kšœžœ,˜6Kšžœžœ žœžœ˜Kšžœžœ˜(Kš œ-žœžœžœžœžœ&˜š žœžœžœžœž˜Kšžœžœžœžœ˜KKšžœ˜—Kšœ!žœ˜BKšžœ  ˜—Mšœ˜žœ%žœ˜ΧMšœ,˜,šžœžœž˜Kšœ*˜*KšœA˜AKšž˜—Kšžœ ˜—š‘œžœžœž˜*K™LLš‘ œ(žœ˜MKšœ)˜)Kšžœ ˜——šœC™CL™ιN™š‘œžœž˜Kšœ/™/—Kšžœžœžœžœ™-—Kšœd˜dKšžœžœžœžœ'™Kšœ!˜!Kšžœ!žœ0žœ4˜ŽKšœ/˜/šžœ /˜2šžœ žœž˜,Kšœžœ˜KšœN˜NKšž˜—Kšžœž˜ Kšžœ˜—Kšžœžœžœ˜Kšœžœžœ žœ˜$Kšžœ˜—Kšœ˜Kšœ0˜0Kšœ/˜/šž˜KšœN˜N—Kšžœ  ˜—š‘œž™-Kš žœžœ žœžœžœžœ™?Kšœžœ™4Mšœ"žœ*™Nšžœžœž™$KšœEžœ ™TKšžœžœ™Kšžœ™—Kšœ™šž™Kšœ ’œ™&—Kšžœ ™—š‘œž˜-Kš žœžœ žœžœžœžœ™?Kšœžœ"˜,Mšœ"žœ*˜NKšžœ žœ8˜LKšœ˜Kšžœ ˜——™Lšœžœžœžœ™KšœB™Bš ‘œžœžœžœž™8Kšžœžœžœ™Kš žœžœžœžœžœ™IKšžœ ™—š ‘ œžœžœžœž™@Lšœ™Kšœ žœžœ™7Kšžœ™Kšžœ  ™—š ‘ œžœ žœžœž˜9Kšœ Οe œ™3šžœž ˜KšœX˜XKšžœ˜—Kšžœ˜ Kšžœ ˜—š ‘ œžœžœžœžœž˜3Kšœžœžœ™Kš žœžœžœžœ’œ˜xšžœž˜ Kšœžœ#˜:Kšœžœžœ˜&Kš’œ/˜5Kšž˜—Kšžœ ˜—š ‘ œžœžœžœžœ ž˜HKšœžœ˜Kšžœ žœžœžœ˜PKšžœ žœžœ’œ ˜'šžœ@žœž˜MKšœ'˜'—Kš žœ žœžœžœžœ žœ#˜šKšžœ žœžœžœ ˜PKš’œ ˜Kšžœ ˜—š ‘œžœžœžœžœž˜9Kšžœžœžœ˜4Kšžœ ˜—š ‘ œžœžœžœ!ž˜NKšœ&žœ'˜PKšœ˜Kšœ*˜*Kšœ*˜*Kšœ*˜*Kšœ*˜*Kšžœ ˜Kšžœ ˜—š‘œžœžœž˜*Kšœ^žœ™{Kšœ4˜4KšœJ˜JKšžœ ˜—Lšœžœh˜qš‘ œž˜(Kš žœžœ žœžœžœžœ™?Lšœ!™!Kšœžœ"˜-Kšœ žœ˜$Kšœžœ˜-Mšœ"žœ*˜NMšžœžœžœž˜5Kš žœžœ žœžœžœ#žœ˜vKšžœžœžœ˜#Kšœ*˜*Kšœžœ˜Kšžœžœžœ+žœ˜HKš žœžœžœžœžœžœ˜mKšœ)˜)Kšœ&˜&Kšžœ  ˜—š‘ œž˜,Kš žœžœ žœžœžœžœ™?Lšœ'™'Kšœžœ˜"Kšœ žœ3˜@Mšœ"žœ*˜Nšžœžœž˜$KšœKžœ ˜ZKšžœžœžœžœ˜8Kšžœ˜—Kšœžœ˜*šžœž˜Kšœ˜Kšœžœ˜Kšœžœ˜ Kšœ˜Kšžœžœ˜—šžœ žœž˜Kšœžœžœ˜;Kšœ˜Kšžœ˜—šž˜Kšœ ’œ˜&—Kšžœ ˜—š ‘œžœžœžœžœž˜4Kšžœ@žœ˜LKšžœ ˜—š ‘ œžœžœžœžœž˜-Kšžœ:žœ˜GKšžœ  ˜—š ‘ œžœžœžœžœž˜.KšžœN˜TKšžœ  ˜—š ‘œžœžœžœž˜'K™6Kšœ˜Kšžœžœžœžœ˜GKšžœžœ˜5Kšžœ ˜ ——™Kšœ5™5Kšœ!žœžœ™-KšœBžœžœžœ™XKšœA™Aš‘ œžœž™K™JKšœ4 ™GKšœžœ™Kšœ™Kšœ±™±Kšœ)™)Kšžœ™—š‘ œžœžœ%ž™BKšœ(™(Kšœ9™9Kšžœ  ™—š‘œžœž™Kšœžœ ™Kšœ™Kšžœ  ™—š‘œžœ žœ&ž™FKš‘œ'™.K™(Kšžœ ™—š‘œžœž™Kšœ(™(Kšœžœ ™3Kšžœ ™—š‘ œžœž™Kšœ(™(Kšœžœ™,Kšœ™Kšžœ ™—š‘ œžœž™Kšœ(™(Kšœžœ™(Kšœ>™>Kšžœ ™—š‘ œžœžœž™!Kš œžœžœžœžœ™Mšœ@™@Kšœ ™ Kš žœžœžœžœž™CKšžœ  ™—š‘œ žœž™-K™HKšœ+™+Kšœ žœžœ™M™š žœžœžœžœž™"Kšœžœžœ™0Kšœžœžœ™ Kšœžœ&™.Kšœžœ™šžœžœžœž™šžœžœž™Kšœ!™!Kšžœ žœžœ™(Kšžœ ™$Kšœ ™ Kšžœ™—Kšžœ žœžœ1™EKšœ,™,Kšœ™Kšœ8™8Kšœ#™#Kšœ8™8Kšœ ™ Kšžœ™—Kšžœ™—šžœ1žœž™=Kšœ ™ Kšœžœžœ™5Kšœ™Kšœ=™=šžœžœž™8Kšœ)™)KšœY™YKšœ ™ Kšž™—Kšžœ™—MšœP™PLšœM™MKšžœ ™—Lšœžœžœ™/Kšœžœžœ™-Kšœžœ™—™Kšžœžœ žœ˜)Kšžœžœd˜yLšœ>˜>Lšœ±˜±LšœŸ˜ŸLšœœ˜œ—Lšžœ˜™#K™ Kšœ Οrœ™Ž—™#K™4Kšœ €œ€™S—™$Kšœr™rKšœ €Qœ€K™Β—™$K™/Kšœ € œ$€œ€j™δ—™$K™5Kšœ €^™j—™$K™1Kšœ €œ ™J—™$K™,Kšœ €™—™$Kšœ2žœžœh™¦Kšœ €<œ €™ƒ—™"K™Kšœ €:™F—™"K™5Kšœ €Aœ™N—™#K™/Kšœ €Α™Ν—™#K™GKšœ €D™P—™$K™,Kšœ € ™—™%K™QKšœ €U™a—™$K™>Kšœ €K™W—K™—…—zŠδ$