DIRECTORY CGColorWithCIE USING [Color, GetStipple, undefined, PhosphorType], Basics USING[BITSHIFT, BITAND], Real USING [FixI, RoundC], ImagerColor USING [RGB, HSV, HSL, YIQ, HSVFromRGB, RGBFromHSV, HSLFromRGB, RGBFromHSL, YIQFromRGB, RGBFromYIQ], Matrix, RuntimeError USING [BoundsFault]; CGColorWithCIEImpl: CEDAR PROGRAM IMPORTS CGColorWithCIE, Basics, Real, RuntimeError, Matrix, ImagerColor EXPORTS CGColorWithCIE = { Color: TYPE = CGColorWithCIE.Color; Byte: TYPE = [0..256); undefined: REAL= CGColorWithCIE.undefined; InvalidColor: PUBLIC SIGNAL=CODE; Uninitialized: PUBLIC SIGNAL=CODE; ToRange: PROC[v: REAL] RETURNS[REAL] = INLINE { IF v IN[0..1] THEN RETURN[v] ELSE ERROR RuntimeError.BoundsFault }; -- ensures that v is in [0..1]; raises BoundsFault if not ToByte: PROC[v: REAL] RETURNS[Byte] = INLINE { RETURN[Real.RoundC[ToRange[v]*255]] }; -- assumes v IN[0..1] MakeRGB: PROC[r, g, b: Byte] RETURNS[Color] = INLINE { RETURN[[tag: rgb, r: r, g: g, b: b]] }; IntensityToColor: PUBLIC PROC[intensity: REAL] RETURNS[Color] = { i: Byte _ ToByte[ToRange[intensity]]; RETURN[MakeRGB[i, i, i]] }; RGBToColor: PUBLIC PROC[r,g,b: REAL] RETURNS[Color] = { red: Byte _ ToByte[ToRange[r]]; grn: Byte _ ToByte[ToRange[g]]; blu: Byte _ ToByte[ToRange[b]]; RETURN[MakeRGB[red, grn, blu]] }; HSVToColor: PUBLIC PROC[h,s,v: REAL] RETURNS[Color] = { r,g,b: REAL; [r,g,b] _ HSVToRGB[h, s, v]; RETURN[MakeRGB[ToByte[r],ToByte[g],ToByte[b]]] }; ColorToIntensity: PUBLIC PROC[color: Color] RETURNS[intensity: REAL] = { SELECT color.tag FROM rgb => { i: REAL; IF color.b=color.r AND color.g=color.r THEN i _ color.r ELSE i _ 0.30*color.r+0.11*color.b+0.59*color.g; intensity _ i/255.0 }; stipple => intensity _ StippleToIntensity[color]; ENDCASE => intensity _ 0; RETURN[intensity]; }; ColorToHSV: PUBLIC PROC[color: Color] RETURNS[h, s, v: REAL] = { SELECT color.tag FROM rgb => [h,s,v] _ RGBToHSV[color.r/255.0, color.g/255.0, color.b/255.0]; stipple => { h _ s _ 0; v _ StippleToIntensity[color] }; ENDCASE => h _ s _ v _ 0; RETURN[h,s,v]; }; ColorToRGB: PUBLIC PROC[color: Color] RETURNS[r, g, b: REAL] = { SELECT color.tag FROM rgb => RETURN[r: color.r/255.0, g: color.g/255.0, b: color.b/255.0]; stipple => { i: REAL _ StippleToIntensity[color]; RETURN[i, i, i] }; ENDCASE => RETURN[0, 0, 0]; }; StippleToIntensity: PROC[color: Color] RETURNS[intensity: REAL] = { -- assumes color.tag = stipple bits: CARDINAL _ CGColorWithCIE.GetStipple[color]; count: NAT _ 0; FOR i: CARDINAL IN[0..16) DO TRUSTED { IF Basics.BITAND[bits,1]=0 THEN count _ count+1; -- count "white" bits bits _ Basics.BITSHIFT[bits,-1] }; ENDLOOP; intensity _ count/16.0; }; HSVToRGB: PUBLIC PROC[h,s,v: REAL] RETURNS[r,g,b: REAL] = { hue: REAL; saturation: REAL _ ToRange[s]; value: REAL _ ToRange[v]; ihue: INTEGER; fhue,m,n,k: REAL; IF h=undefined THEN IF saturation=0 THEN {r _ g _ b _ value; RETURN} ELSE SIGNAL InvalidColor ELSE hue _ ToRange[h]; hue _ hue*6; ihue _ Real.FixI[hue]; --integer hue fhue _ hue-ihue; --fractional hue IF ihue=6 THEN ihue _ 0; m _ value*(1-saturation); n _ value*(1-(saturation*fhue)); k _ value*(1-(saturation*(1-fhue))); SELECT ihue FROM 0 => RETURN[value,k,m]; 1 => RETURN[n,value,m]; 2 => RETURN[m,value,k]; 3 => RETURN[m,n,value]; 4 => RETURN[k,m,value]; 5 => RETURN[value,m,n]; ENDCASE => RETURN[0,0,0]; }; RGBToHSV: PUBLIC PROC[r,g,b: REAL] RETURNS[h,s,v: REAL] = { max,min,rc,gc,bc: REAL; r _ ToRange[r]; g _ ToRange[g]; b _ ToRange[b]; min _ MIN[MIN[r,g],b]; --amount of white v _ max _ MAX[MAX[r,g],b];--maximum "brightness" IF max#0 THEN s _ (max-min)/max ELSE s _ 0; IF s=0 THEN RETURN[undefined,0,v]; --gray rc _ (max - r)/(max - min); gc _ (max - g)/(max - min); bc _ (max - b)/(max - min); IF r=max THEN h_bc-gc ELSE IF g=max THEN h_2+rc-bc ELSE IF b=max THEN h_4+gc-rc; h _ h / 6.0; IF h<0 THEN h_h+1; RETURN[h, s, v]; }; HSLToRGB: PUBLIC PROC[h, s, l: REAL] RETURNS[r, g, b: REAL] = { m1,m2,hue,saturation, lightness: REAL; Value: PROC[n1,n2,h1: REAL] RETURNS[v: REAL] = { IF h1 > 360 THEN h1 _ h1-360; IF h1 < 0 THEN h1 _ h1+360; v _ SELECT TRUE FROM h1 IN [0..60) => n1+(n2-n1)*h1/60, h1 IN [60..180) => n2, h1 IN [180..240) => n1+(n2-n1)*(240-h1)/60, ENDCASE => n1; }; saturation _ ToRange[s]; lightness _ ToRange[l]; IF h=undefined THEN IF saturation=0 THEN {r _ g _ b _ lightness} ELSE SIGNAL InvalidColor ELSE hue _ 360*ToRange[h]; m2 _ IF lightness <= 0.5 THEN lightness*(1+saturation) ELSE lightness+saturation-lightness*saturation; m1 _ 2*lightness-m2; r _ Value[m1,m2,hue+120]; g _ Value[m1,m2,hue]; b _ Value[m1,m2,hue-120]; }; RGBToHSL: PUBLIC PROC[r, g, b: REAL] RETURNS[h, s, l: REAL] = { max,min,rc,gc,bc,del: REAL; red: REAL _ ToRange[r]; green: REAL _ ToRange[g]; blue: REAL _ ToRange[b]; max _ MAX[red,MAX[green,blue]]; min _ MIN[red,MIN[green,blue]]; l _ (max+min)/2; IF max=min THEN RETURN[undefined,0,l]; --gray del _ max-min; s _ IF l <= 0.5 THEN del/(max+min) ELSE del/(2-max-min); rc _ (max-red)/del; gc _ (max-green)/del; bc _ (max-blue)/del; IF max = red THEN h _ bc-gc --between yellow and magenta ELSE IF max = green THEN h _ 2+rc-bc --between cyan and yellow ELSE IF max = blue THEN h _ 4+gc-rc --between magenta and cyan ELSE SIGNAL InvalidColor; h _ h/6.0; IF h < 0 THEN h _ h+1; }; rgbToYiqMatrix: Matrix.MatrixN _ Matrix.Create[3,3]; yiqToRgbMatrix: Matrix.MatrixN _ Matrix.Create[3,3]; YIQToRGB: PUBLIC PROC[y, i, q: REAL] RETURNS[r, g, b: REAL] = { rgbMatrix, yiqMatrix: Matrix.MatrixN; rgbMatrix _ Matrix.Create[3,1]; yiqMatrix _ Matrix.Create[3,1]; yiqMatrix[0][0] _ y; yiqMatrix[1][0] _ i * 1.2 - 0.6; yiqMatrix[2][0] _ q * 1.04 - 0.52; rgbMatrix _ Matrix.Multiply[yiqToRgbMatrix, yiqMatrix]; r _ rgbMatrix[0][0]; g _ rgbMatrix[1][0]; b _ rgbMatrix[2][0]; r _ MIN[r,1]; g _ MIN[g,1]; b _ MIN[b,1]; --control precision problems r _ MAX[r,0]; g _ MAX[g,0]; b _ MAX[b,0]; }; RGBToYIQ: PUBLIC PROC[r, g, b: REAL] RETURNS[y, i, q: REAL] = { rgbMatrix, yiqMatrix: Matrix.MatrixN; rgbMatrix _ Matrix.Create[3,1]; yiqMatrix _ Matrix.Create[3,1]; rgbMatrix[0][0] _ r; rgbMatrix[1][0] _ g; rgbMatrix[2][0] _ b; yiqMatrix _ Matrix.Multiply[rgbToYiqMatrix, rgbMatrix]; y _ yiqMatrix[0][0]; i _ (yiqMatrix[1][0] + 0.6) / 1.2; q _ (yiqMatrix[2][0] + 0.52) / 1.04; y _ MIN[y,1]; i _ MIN[i,1]; q _ MIN[q,1]; --control precision problems y _ MAX[y,0]; i _ MAX[i,0]; q _ MAX[q,0]; }; rgbToArgybMatrix: Matrix.MatrixN _ Matrix.Create[3,3]; argybToRgbMatrix: Matrix.MatrixN _ Matrix.Create[3,3]; ARgYbToRGB: PUBLIC PROC[a, rg, yb: REAL] RETURNS[r, g, b: REAL] = { rgbMatrix, argybMatrix: Matrix.MatrixN; rgbMatrix _ Matrix.Create[3,1]; argybMatrix _ Matrix.Create[3,1]; argybMatrix[0][0] _ a; argybMatrix[1][0] _ rg - 0.5; argybMatrix[2][0] _ yb - 0.5; rgbMatrix _ Matrix.Multiply[argybToRgbMatrix, argybMatrix]; r _ rgbMatrix[0][0]; g _ rgbMatrix[1][0]; b _ rgbMatrix[2][0]; r _ MIN[r,1]; g _ MIN[g,1]; b _ MIN[b,1]; --control precision problems r _ MAX[r,0]; g _ MAX[g,0]; b _ MAX[b,0]; }; RGBToARgYb: PUBLIC PROC[r, g, b: REAL] RETURNS[a, rg, yb: REAL] = { rgbMatrix, argybMatrix: Matrix.MatrixN; rgbMatrix _ Matrix.Create[3,1]; argybMatrix _ Matrix.Create[3,1]; rgbMatrix[0][0] _ r; rgbMatrix[1][0] _ g; rgbMatrix[2][0] _ b; argybMatrix _ Matrix.Multiply[rgbToArgybMatrix, rgbMatrix]; a _ argybMatrix[0][0]; rg _ argybMatrix[1][0] + 0.5; yb _ argybMatrix[2][0] + 0.5; a _ MIN[a,1]; rg _ MIN[rg,1]; yb _ MIN[yb,1]; --control precision problems a _ MAX[a,0]; rg _ MAX[rg,0]; yb _ MAX[yb,0]; }; Real0: TYPE = REAL _ 0; Matrix3: TYPE = ARRAY [0..3) OF Row3; Row3: TYPE = ARRAY [0..3) OF Real0; Column3: TYPE = ARRAY [0..3) OF Real0; ToCIE: Matrix3; ToRGB: Matrix3; yScale: REAL _ 1; Initialized: BOOLEAN _ FALSE; InitCIE: PUBLIC PROC[xr,yr,xg,yg,xb,yb: REAL, whiteY: REAL _ 1] = { matrix: Matrix.MatrixN; ToCIE[0][0] _xr; ToCIE[1][0] _yr; ToCIE[2][0] _1-(xr+yr); ToCIE[0][1] _xg; ToCIE[1][1] _yg; ToCIE[2][1] _1-(xg+yg); ToCIE[0][2] _xb; ToCIE[1][2] _yb; ToCIE[2][2] _1-(xb+yb); Initialized _ TRUE; yScale _ whiteY/(yr+yg+yb); matrix _ Matrix.Create[3,3]; FOR i: INTEGER IN [0..3) DO FOR j: INTEGER IN [0..3) DO matrix[i][j] _ ToCIE[i][j]; ENDLOOP; ENDLOOP; matrix _ Matrix.Invert[matrix]; FOR i: INTEGER IN [0..3) DO FOR j: INTEGER IN [0..3) DO ToRGB[i][j] _ matrix[i][j]; ENDLOOP; ENDLOOP; }; longXR: REAL _ 0.6; longYR: REAL _ 0.325; longXG: REAL _ 0.22; longYG: REAL _ 0.62; longXB: REAL _ 0.23; longYB: REAL _ 0.2; normalXR: REAL _ 0.615; normalYR: REAL _ 0.34; normalXG: REAL _ 0.3; normalYG: REAL _ 0.59; normalXB: REAL _ 0.15; normalYB: REAL _ 0.065; InitDefaultCIE: PUBLIC PROC[type: CGColorWithCIE.PhosphorType _ long] = { SELECT type FROM long => InitCIE[longXR,longYR,longXG,longYG,longXB,longYB]; normal => InitCIE[normalXR,normalYR,normalXG,normalYG,normalXB,normalYB]; ENDCASE => ERROR; }; GetDefaultValues: PUBLIC PROC[type: CGColorWithCIE.PhosphorType] RETURNS[xr,yr,xg,yg,xb,yb: REAL] = { SELECT type FROM long => RETURN[xr: longXR, yr: longYR, xg: longXG, yg: longYG, xb: longXB, yb: longYB]; normal => RETURN[xr: normalXR, yr: normalYR, xg: normalXG, yg: normalYG, xb: normalXB, yb: normalYB]; ENDCASE => ERROR; }; SetDefaultValues: PUBLIC PROC[xr,yr,xg,yg,xb,yb: REAL, type: CGColorWithCIE.PhosphorType] = { SELECT type FROM long => { longXR _ xr; longYR _ yr; longXG _ xg; longYG _ yg; longXB _ xb; longYB _ yb; }; normal => { normalXR _ xr; normalYR _ yr; normalXG _ xg; normalYG _ yg; normalXB _ xb; normalYB _ yb; }; ENDCASE => ERROR; }; CIEToRGB: PUBLIC PROC[x,y, Y: REAL] RETURNS[r, g, b: REAL] = { rgb,cie: Column3; s: REAL; IF ~Initialized THEN SIGNAL Uninitialized; s _ Y/(yScale*y); --now a real Y cie[0] _ x*s; cie[1] _ y*s; cie[2] _ s-(x+y)*s; rgb _ MultiplyVec[ToRGB,cie]; r _ rgb[0]; g _rgb[1]; b _ rgb[2]; }; RGBToCIE: PUBLIC PROC[r, g, b: REAL] RETURNS [x,y, Y: REAL] = { cie,rgb: Column3; s: REAL; IF ~Initialized THEN SIGNAL Uninitialized; rgb _ [r,g,b]; cie _ MultiplyVec[ToCIE,rgb]; s _ cie[0]+cie[1]+cie[2]; --cie must be positive IF s=0 THEN RETURN[0,0,0]; --r, g, b =0 means color is black x _ cie[0]/s; y _ cie[1]/s; Y _ cie[1]*yScale; }; GetMaxY: PUBLIC PROC[x,y: REAL] RETURNS[Y: REAL] = { cie,ymax: Column3; cie _ [x/y,1,(1-(x+y))/y]; ymax _ MultiplyVec[ToRGB,cie]; --actually the inverses Y _ MAX[MAX[ymax[0],ymax[1]],ymax[2]]; Y _ yScale/Y; }; MultiplyVec: PROC[a: Matrix3, v: Column3] RETURNS [c: Column3] = { FOR i: INTEGER IN [0..3) DO c[i] _ 0; FOR j: INTEGER IN [0..3) DO c[i] _ c[i]+a[i][j]*v[j]; ENDLOOP; ENDLOOP; }; ContrastInRGB: PUBLIC PROC[rgb: ImagerColor.RGB] RETURNS[rgbContrast: ImagerColor.RGB] = { IF rgb.R < 0.5 THEN rgbContrast.R _ 1.0 ELSE rgbContrast.R _ 0.0; IF rgb.G < 0.5 THEN rgbContrast.G _ 1.0 ELSE rgbContrast.G _ 0.0; IF rgb.B < 0.5 THEN rgbContrast.B _ 1.0 ELSE rgbContrast.B _ 0.0; }; ContrastInHSV: PUBLIC PROC[rgb: ImagerColor.RGB] RETURNS[hsvContrast: ImagerColor.RGB] = { hsvContrastInHSV: ImagerColor.HSV; hsv: ImagerColor.HSV _ ImagerColor.HSVFromRGB[rgb]; hsvContrastInHSV.H _ hsv.H + 0.5; IF hsvContrastInHSV.H > 1.0 THEN hsvContrastInHSV.H _ hsvContrastInHSV.H - 1.0; IF hsv.S < 0.5 THEN hsvContrastInHSV.S _ 1.0 ELSE hsvContrastInHSV.S _ 0.0; IF hsv.V < 0.5 THEN hsvContrastInHSV.V _ 1.0 ELSE hsvContrastInHSV.V _ 0.0; hsvContrast _ ImagerColor.RGBFromHSV[hsvContrastInHSV]; }; ContrastInHSL: PUBLIC PROC[rgb: ImagerColor.RGB] RETURNS[hslContrast: ImagerColor.RGB] = { hslContrastInHSL: ImagerColor.HSL; hsl: ImagerColor.HSL _ ImagerColor.HSLFromRGB[rgb]; hslContrastInHSL.H _ hsl.H + 0.5; IF hslContrastInHSL.H > 1.0 THEN hslContrastInHSL.H _ hslContrastInHSL.H - 1.0; IF hsl.S < 0.5 THEN hslContrastInHSL.S _ 1.0 ELSE hslContrastInHSL.S _ 0.0; IF hsl.L < 0.5 THEN hslContrastInHSL.L _ 1.0 ELSE hslContrastInHSL.L _ 0.0; hslContrast _ ImagerColor.RGBFromHSL[hslContrastInHSL]; }; ContrastInYIQ: PUBLIC PROC[rgb: ImagerColor.RGB] RETURNS[yiqContrast: ImagerColor.RGB] = { yiqContrastInYIQ: ImagerColor.YIQ; yiq: ImagerColor.YIQ _ ImagerColor.YIQFromRGB[rgb]; yiq.I _ (yiq.I + 0.6) / 1.2; yiq.Q _ (yiq.Q + 0.52) / 1.04; IF yiq.Y < 0.5 THEN yiqContrastInYIQ.Y _ 1.0 ELSE yiqContrastInYIQ.Y _ 0.0; IF yiq.I < 0.5 THEN yiqContrastInYIQ.I _ 1.0 ELSE yiqContrastInYIQ.I _ 0.0; IF yiq.Q < 0.5 THEN yiqContrastInYIQ.Q _ 1.0 ELSE yiqContrastInYIQ.Q _ 0.0; yiqContrastInYIQ.I _ yiqContrastInYIQ.I * 1.2 - 0.6; yiqContrastInYIQ.Q _ yiqContrastInYIQ.Q * 1.04 - 0.52; yiqContrast _ ImagerColor.RGBFromYIQ[yiqContrastInYIQ]; yiqContrast.R _ MIN[yiqContrast.R,1]; yiqContrast.G _ MIN[yiqContrast.G,1]; yiqContrast.B _ MIN[yiqContrast.B,1]; yiqContrast.R _ MAX[yiqContrast.R,0]; yiqContrast.G _ MAX[yiqContrast.G,0]; yiqContrast.B _ MAX[yiqContrast.B,0]; }; ContrastInARgYb: PUBLIC PROC[rgb: ImagerColor.RGB] RETURNS[argybContrast: ImagerColor.RGB] = { a, rg, yb: REAL; aContrastInARgYb, rgContrastInARgYb, ybContrastInARgYb: REAL; [a, rg, yb] _ RGBToARgYb[rgb.R, rgb.G, rgb.B]; IF a < 0.5 THEN aContrastInARgYb _ 1.0 ELSE aContrastInARgYb _ 0.0; IF rg < 0.5 THEN rgContrastInARgYb _ 1.0 ELSE rgContrastInARgYb _ 0.0; IF yb < 0.5 THEN ybContrastInARgYb _ 1.0 ELSE ybContrastInARgYb _ 0.0; [argybContrast.R, argybContrast.G, argybContrast.B] _ ARgYbToRGB[aContrastInARgYb, rgContrastInARgYb, ybContrastInARgYb]; argybContrast.R _ MIN[argybContrast.R,1]; argybContrast.G _ MIN[argybContrast.G,1]; argybContrast.B _ MIN[argybContrast.B,1]; argybContrast.R _ MAX[argybContrast.R,0]; argybContrast.G _ MAX[argybContrast.G,0]; argybContrast.B _ MAX[argybContrast.B,0]; }; rgbToYiqMatrix[0][0] _ 0.3; rgbToYiqMatrix[0][1] _ 0.59; rgbToYiqMatrix[0][2] _ 0.11; rgbToYiqMatrix[1][0] _ 0.6; rgbToYiqMatrix[1][1] _ -0.28; rgbToYiqMatrix[1][2] _ -0.32; rgbToYiqMatrix[2][0] _ 0.21; rgbToYiqMatrix[2][1] _ -0.52; rgbToYiqMatrix[2][2] _ 0.31; yiqToRgbMatrix _ Matrix.Invert[rgbToYiqMatrix]; rgbToArgybMatrix[0][0] _ 0.3; rgbToArgybMatrix[0][1] _ 0.59; rgbToArgybMatrix[0][2] _ 0.11; rgbToArgybMatrix[1][0] _ 0.5; rgbToArgybMatrix[1][1] _ -0.5; rgbToArgybMatrix[1][2] _ 0.0; rgbToArgybMatrix[2][0] _ 0.25; rgbToArgybMatrix[2][1] _ 0.25; rgbToArgybMatrix[2][2] _ -0.5; argybToRgbMatrix _ Matrix.Invert[rgbToArgybMatrix]; }. CGColorWithCIEImpl.mesa Last edited by Maureen Stone, June 21, 1985 1:52:14 pm PDT Last edited by Doug Wyatt, November 12, 1982 1:30 pm Last Edited by: Beach, February 13, 1984 2:23:14 pm PST Last Edited by: Naiman, July 8, 1985 6:32:29 pm PDT These algorithms use the hexacone model described in "Color Gamut Transform Pairs" by Alvy Ray Smith Siggraph 1978, p. 12. Algorithms from Foley and van Dam may return values outside the range [0..1] work this out by algebra, find we can use ToRGB to solve it Initialization Κw– "cedar" style˜procšœ™Kšœ:™:Kšœ4™4J™7J™3J™—šΟk ˜ Kšœœ.˜BKšœœœœ˜Kšœœ˜Jš œ œœœ œH˜oKšœ˜Kšœ œ˜"—Kšœœœ˜"Kšœ@˜GKšœ˜Kšœœ˜#Kšœœ ˜Kšœ œ˜*Kšœœœœ˜!Kšœœœœ˜"K˜KšΟnœœœœœœœœœœ˜LKšœœœ˜)KšΟc'Οi Ÿ˜:Kš žœœœœ œœ ˜UKšŸ˜Kš žœœœ œœ"˜_š žœœœ œœ ˜AKšœ%˜%Kšœ˜—š ž œœœœœ ˜7Kšœ˜Kšœ˜Kšœ˜Kšœ˜!—š œž œœœœœ ˜8Kšœœ˜)Kšœ+˜1—š œžœœœœ œ˜Išœ ˜šœ œ˜Kšœœœ ˜7Kšœ,˜0Kšœ˜—Kšœ1˜1Kšœ˜—Kšœ ˜Kšœ˜—Kšœ˜š ž œœœœ œ˜@šœ ˜KšœG˜GKšœ8˜8Kšœ˜—Kšœ˜Kšœ˜—š œž œœœœ œ˜Ašœ ˜Kšœœ7˜DKšœœœ ˜DKšœœ ˜—Kšœ˜—š œžœœœ œŸ˜cKšœœ$˜2Kšœœ˜š œœœœœ˜&Kšœœ œŸ˜FKšœœ ˜"Kšœ˜—Kšœ˜Kšœ˜—Kšœ4™4Kšœ/™/Kšœ™Kšœ!™!Kšœ˜š žœœœœœœ˜;Kšœœ˜ Kšœ œ˜Kšœœ˜Kšœœ˜Kšœ œ˜šœ œ˜Kšœœœ˜0Kšœœ ˜—Kšœ˜Kšœ ˜ KšœŸ ˜$KšœŸ˜!Kšœœ ˜Kšœ˜Kšœ ˜ Kšœ$˜$šœ˜Kšœœ ˜Kšœœ ˜Kšœœ ˜Kšœœ ˜Kšœœ ˜Kšœœ ˜Kšœœ˜—Kšœ˜—š œžœœœœœœ˜Kšœœ œ Ÿ˜>Kšœœ˜K˜ Kšœœ ˜K˜—K˜K˜4K˜4K˜š žœœœ œœ œ˜?J˜%K˜K˜K˜XKšœ7˜7Kšœ>˜>Jšœœ œ œŸ˜FJšœœ œ œ˜)K˜—š žœœœ œœ œ˜?J˜%K˜K˜K˜>Kšœ7˜7Kšœ\˜\Jšœœ œ œŸ˜FJšœœ œ œ˜)K˜—J˜J˜K˜6K˜6K˜š ž œœœ œœ œ˜CJ˜'K˜K˜!K˜RKšœ;˜;Kšœ>˜>Jšœœ œ œŸ˜FJšœœ œ œ˜)K˜—š ž œœœ œœ œ˜CJ˜'K˜K˜!K˜>Kšœ;˜;KšœR˜RJšœœ œ œŸ˜JJšœœ œ œ˜-K˜—J˜J˜Jšœœœ˜Jšœ œœœ˜%Jšœœœœ˜#Jšœ œœœ˜&K˜K˜Kšœœ˜Kšœ œœ˜š žœœœœ œ ˜CK˜Kšœ9˜9Kšœ9˜9Kšœ9˜9Kšœœ˜K˜K˜šœœœ˜šœœœ˜K˜Kšœ˜—Kšœ˜—K˜šœœœ˜šœœœ˜K˜Kšœ˜—Kšœ˜—K˜—Kšœœ˜Kšœœ ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœ œ ˜Kšœ œ˜Kšœ œ˜Kšœ œ˜Kšœ œ˜Kšœ œ ˜šžœ œ.˜Išœ˜Kšœ;˜;KšœI˜IKšœœ˜—K˜—šžœ œ#œœ˜ešœ˜KšœœI˜WKšœ œU˜eKšœœ˜—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šœŸ˜0Kšœœœ Ÿ!˜