DIRECTORY Basics, AIS, Real, RealFns, Random, Rope, Process, CedarProcess, Texture2D; Texture2DImpl: CEDAR PROGRAM IMPORTS Basics, AIS, Real, RealFns, Random, Process, CedarProcess EXPORTS Texture2D ~ BEGIN christmas: BOOL _ TRUE; ROPE: TYPE ~ Rope.ROPE; XF: PROC[x, x0, x1: REAL] RETURNS [REAL] ~ { RETURN [x0 + x * x1] }; epsilon: REAL _ 0.002; -- small differential amount for simulating gradients res: INT _ 100; -- image resolution (square) n: INT _ 6; f0: REAL _ 0.5; Surface: TYPE = {noise, bumps, rock, bark, elevation, elevationGrad, drops, sine, dots, swirl1, marble1, swirl, marble, chmarble, dotRoil, smoke, tree}; type: Surface _ noise; x0: REAL _ 10; x1: REAL _ 8; y0: REAL _ -2.2; y1: REAL _ 8; z0: REAL _ -0.1; z1: REAL _ 1; zlo: REAL _ 0.07; zhi: REAL _ 1; evScale: REAL _ 1.0; Sqr: PROC[x: REAL] RETURNS [REAL] ~ {RETURN [x*x]}; fudgeCone: REAL _ 0.02; zTreeMean: REAL _ 0; zTreeSum: REAL _ 0; zTreeN: INT _ 0; waveNumber: REAL _ 10.0; Cone: PROC [x, y: REAL] RETURNS [REAL] ~ { IF y < 0.95 THEN { t: REAL _ 4*(x-0.5)*(x-0.5)/((0.95-y)*(0.95-y)); v: REAL _ 1-2*t; k: REAL _ y - (ABS[x-0.5]*0.2+0.1); wave: REAL _ 0.5+0.4*RealFns.CosDeg[y*waveNumber*360]; IF k < 0 THEN v _ v - 100*k*k; v _ v * wave; RETURN [MAX[v, 0.0]]; }; RETURN [0.0]; }; NoiseTest: PROC[x, y: REAL] RETURNS [REAL] ~ { x01: REAL ~ x; y01: REAL ~ y; x _ XF[x, x0, x1]; y _ XF[y, y0, y1]; SELECT type FROM noise => RETURN [Noise01[x * y, y]]; -- noise: [x0, x1, y0, y1] _ [10, 8, -2.2, 8] bumps => { -- bumps: [x0, x1, y0, y1] _ [10, 8, -2.2, 8] freq: REAL _ f0; dz: REAL _ 0; FOR i: INT IN [0..1) DO FNoise: PROC[x, y: REAL] RETURNS [REAL] ~ { RETURN [Noise01[x * freq, y * freq] / freq]; }; dz _ dz + (FNoise[x + epsilon, y] - FNoise[x, y]) / epsilon; freq _ freq * 2; ENDLOOP; dz _ (1 + dz)/2; IF dz < 0 THEN RETURN [0] ELSE IF dz > 1 THEN RETURN [1] ELSE RETURN [dz] }; bark, -- bark: [x0, x1, y0, y1] _ [10, 8, -2.2, 4] rock => { -- rock: [x0, x1, y0, y1] _ [10, 4, -2.2, 4] freq: REAL _ f0; dz: REAL _ 0; FOR i: INT IN [0..n) DO FNoise: PROC[x, y: REAL] RETURNS [REAL] ~ { RETURN [Noise01[x * freq, y * freq] / freq]; }; dz _ dz + (FNoise[x + epsilon, y] - FNoise[x, y]) / epsilon; freq _ freq * 2; ENDLOOP; dz _ dz / n * 2; dz _ (1 + dz)/2; IF dz < 0 THEN RETURN [0] ELSE IF dz > 1 THEN RETURN [1] ELSE RETURN [dz] }; elevation => { -- elevation: [x0, x1, y0, y1] _ [10, 4, -2.2, 4] freq: REAL _ f0; dz: REAL _ 0; FOR i: INT IN [0..n) DO dz _ dz + Noise3[x * freq, y * freq, 0.5] / freq; freq _ freq * 2; ENDLOOP; dz _ dz / n * evScale; dz _ (1 + dz)/2; RETURN [dz] }; elevationGrad => { -- elevationGrad: [x0, x1, y0, y1] _ [10, 4, -2.2, 4] freq: REAL _ f0; dz: REAL _ 0; FOR i: INT IN [0..n) DO z0: REAL _ Noise3[x * freq, y * freq, 0.5]; z1: REAL _ Noise3[(x+epsilon) * freq, (y-epsilon) * freq, 0.5]; dz _ dz + (z1-z0)/(epsilon * freq); freq _ freq * 2; ENDLOOP; dz _ (1 + dz*evScale)/2; RETURN [MIN[MAX[dz, 0], 1]] }; drops => { -- drops: [x0, x1, y0, y1] _ [10, 4, -2.2, 4] za, zb, z, dz: REAL; za _ Noise3[x, y, 0]; zb _ Noise3[x+epsilon, y, 0]; z_ XF[za, z0, z1]; dz_ XF[(zb-za)/epsilon, 0, z1]; IF z < zlo THEN RETURN [0] ELSE IF dz < -1 THEN RETURN [0] ELSE IF dz > 1 THEN RETURN [1] ELSE RETURN [(1 + dz)/2] }; sine => { -- sine: [x0, x1, y0, y1] _ [10, 8, -2.2, 8] RETURN [Wave[x]] }; dots => { -- dots: [x0, x1, y0, y1] _ [10, 8, -2.2, 8] RETURN [DotGrid[x, y]] }; swirl1 => { -- swirl1: [x0, x1, y0, y1] _ [10, 8, -2.2, 8] freq: REAL _ f0; z: REAL _ 0; FOR i:INT IN [0..1) DO FNoise: PROC[x, y: REAL] RETURNS [REAL] ~ { RETURN [Noise3[x * freq, y * freq, 0] / freq]; }; zz: REAL _ FNoise[x, y]; z _ z + zz * zz * freq; freq _ freq * 2; ENDLOOP; z _ z * 6; RETURN [Wave[x + z]] }; marble1 => { -- marble1: [x0, x1, y0, y1] _ [10, 8, -2.2, 8] freq: REAL _ f0; z: REAL _ 0; FOR i:INT IN [0..1) DO FNoise: PROC[x, y: REAL] RETURNS [REAL] ~ { RETURN [Noise3[x * freq, y * freq, 0] / freq]; }; z _ z + ABS[FNoise[x, y]]; freq _ freq * 2; ENDLOOP; z _ z * 3; RETURN [Wave[x + z]] }; tree => { freq: REAL _ f0 / 2; famp: REAL _ 1.0; z: REAL _ 0; IF 2*ABS[x01-0.5] > 1-y01 THEN RETURN [0]; FOR i:INT IN [0..n) DO FNoise: PROC[x, y: REAL] RETURNS [REAL] ~ { RETURN [Noise3[x * freq, y * freq, 0] * famp]; }; z _ z + ABS[FNoise[x, y]]; freq _ freq * 2; famp _ famp * 0.7; ENDLOOP; z _ z / n * 24; zTreeSum _ zTreeSum + z; zTreeN _ zTreeN + 1; z _ (z-zTreeMean) * fudgeCone; RETURN [Cone[x01 + z, y01 + z]] }; swirl => { -- swirl: [x0, x1, y0, y1] _ [10, 8, -2.2, 8] freq: REAL _ f0 / 2; z: REAL _ 0; FOR i:INT IN [0..n) DO FNoise: PROC[x, y: REAL] RETURNS [REAL] ~ { RETURN [Noise3[x * freq, y * freq, 0] / freq]; }; zz: REAL _ FNoise[x, y]; z _ z + zz * zz * freq; freq _ freq * 2; ENDLOOP; z _ z / n * 16; RETURN [Wave[x + z] ] }; marble => { -- marble: [x0, x1, y0, y1] _ [10, 8, -2.2, 8] freq: REAL _ f0 / 2; z: REAL _ 0; FOR i:INT IN [0..n) DO FNoise: PROC[x, y: REAL] RETURNS [REAL] ~ { RETURN [Noise3[x * freq, y * freq, 0] / freq]; }; z _ z + ABS[FNoise[x, y]]; freq _ freq * 2; ENDLOOP; z _ z / n * 8; RETURN [Wave[x + z] ] }; chmarble => { -- chmarble: [x0, x1, y0, y1] _ [10, 8, -2.2, 8] freq: REAL _ f0 / 2; z: REAL _ 0; FOR i:INT IN [0..n) DO FNoise: PROC[x, y: REAL] RETURNS [REAL] ~ { RETURN [Noise3[x * freq, y * freq, 0] / freq]; }; z _ z + ABS[FNoise[x, y]]; freq _ freq * 2; ENDLOOP; z _ z / n * 8; RETURN [Wave[x + z] * Wave[y + z]] }; dotRoil => { -- dotRoil: [x0, x1, y0, y1] _ [10, 8, -2.2, 8] freq: REAL _ f0 / 2; z: REAL _ 0; FOR i:INT IN [0..n) DO FNoise: PROC[x, y: REAL] RETURNS [REAL] ~ { RETURN [Noise3[x * freq, y * freq, 0] / freq]; }; z _ z + ABS[FNoise[x, y]]; freq _ freq * 2; ENDLOOP; z _ z / n * 24; RETURN [DotGrid[x + z, y]] }; smoke => { -- smoke: [x0, x1, y0, y1] _ [10, 8, -2.2, 8] freq: REAL _ f0; z: REAL _ 0; FOR i:INT IN [0..n) DO FNoise: PROC[x, y: REAL] RETURNS [REAL] ~ { RETURN [Noise3[x * freq, y * freq, 0] / freq]; }; z _ z + ABS[FNoise[x, y]]; freq _ freq * 2; ENDLOOP; z _ z / n * 8; z _ Wave[x + z]; IF z < 0 THEN RETURN [0] ELSE IF z > 1 THEN RETURN [1] ELSE RETURN [z] }; ENDCASE => RETURN [0]; }; Wave: PROC[x: REAL] RETURNS [REAL] ~ { z: REAL _ RealFns.Sin[x]; z _ z * z; RETURN [1 - z * z]; }; DotGrid: PROC[x, y: REAL] RETURNS [REAL] ~ { zx: REAL _ RealFns.Sin[x]; zy: REAL _ RealFns.Sin[y]; z:REAL _ zx * zy; z _ z * z; RETURN [1 - z * z]; }; Noise01: PROC[x, y: REAL] RETURNS [REAL] ~ { s: REAL; s _ Noise3[x, y, 0]; RETURN [(s + 1)/2] }; Permutation: TYPE ~ REF PermutationRecord; PermutationRecord: TYPE ~ RECORD[SEQUENCE length: CARDINAL OF CARDINAL]; randomSeed: INT _ 0; NewSeed: PROC [seed: INT] ~ { randomSeed _ seed; pp _ NIL }; RandomPermutation: PROC[n: INT] RETURNS [Permutation] ~ { p: Permutation _ NEW[PermutationRecord[2 * n]]; rs: Random.RandomStream _ Random.Create[seed: randomSeed]; FOR i: INT IN [0..n) DO p[i] _ i; ENDLOOP; FOR i: INT IN [0..n-1) DO j: INT _ Random.ChooseInt[rs: rs, min: i+1, max: n-1]; k: INT _ p[i]; p[i] _ p[j]; p[j] _ k; p[n + i] _ p[i]; ENDLOOP; RETURN [p]; }; pp: Permutation _ NIL; np: INT _ 2048; TripleSeq: TYPE ~ REF TripleSeqRecord; TripleSeqRecord: TYPE ~ RECORD[SEQUENCE length: CARDINAL OF Triple]; Triple: TYPE ~ RECORD [ x, y, z: REAL]; grad: TripleSeq _ NIL; Noise3: PUBLIC PROC[x, y, z: REAL] RETURNS [REAL] ~ { -- band limited noise over R3. jx, jy, jz: INT; sx, sy, sz, s, f: REAL; IF pp = NIL THEN { pp _ RandomPermutation[np]; grad _ NEW[TripleSeqRecord[np]]; FOR i:INT IN [0..np) DO Random: PROC[i: INT] RETURNS [REAL] ~ {RETURN [3.2*pp[i MOD np]/np-1.6];}; Normalize: PROC[v: Triple] RETURNS[Triple] ~ { mag: REAL _ RealFns.SqRt[v.x * v.x + v.y * v.y + v.z * v.z]; IF mag <= 0. THEN mag _ 1.; RETURN [ [v.x/mag, v.y/mag, v.z/mag] ]; }; grad[i] _ Normalize[[Random[i+7], Random[i+13], Random[i+29]]]; ENDLOOP; }; BEGIN WrapAround: PROC[x: REAL, n: INT] RETURNS [REAL] ~ { x _ x - Real.Fix[x/n]*n; IF x < 0 THEN RETURN [x + n] ELSE RETURN [x]; }; x _ WrapAround[x, np]; y _ WrapAround[y, np]; z _ WrapAround[z, np]; END; jx _ Real.Fix[x]; jy _ Real.Fix[y]; jz _ Real.Fix[z]; BEGIN SCurve: PROC[x: REAL] RETURNS [REAL] ~ { RETURN [x * x * (3 - 2 * x)]; }; sx _ SCurve[x - jx]; sy _ SCurve[y - jy]; sz _ SCurve[z - jz]; END; f _ 0.; -- initialize sum to zero. FOR n: INT IN [0..8) DO -- sum together 8 local fields from the surrounding lattice pts. DotProd: PROC[v1, v2: Triple] RETURNS [REAL] ~ { RETURN [v1.x * v2.x + v1.y * v2.y + v1.z * v2.z]; }; SELECT n FROM -- visit each of the 8 corners of the surrounding unit cube. 0 => { s _ (1.-sx) * (1.-sy) * (1.-sz) }; 1 => {jx _ jx+1 ; s _ sx * (1.-sy) * (1.-sz) }; 2 => {jx _ jx-1 ; jy _ jy+1 ; s _ (1.-sx) * sy * (1.-sz) }; 3 => {jx _ jx+1 ; s _ sx * sy * (1.-sz) }; 4 => {jx _ jx-1 ; jy _ jy-1 ; jz _ jz+1 ; s _ (1.-sx) * (1.-sy) * sz }; 5 => {jx _ jx+1 ; s _ sx * (1.-sy) * sz }; 6 => {jx _ jx-1 ; jy _ jy+1 ; s _ (1.-sx) * sy * sz }; 7 => {jx _ jx+1 ; s _ sx * sy * sz }; ENDCASE; f _ f + s * DotProd [grad[ pp[jx + pp[jy + pp[jz]]] ], [x - jx, y - jy, z - jz] ]; ENDLOOP; RETURN [f]; }; autoRange: INT _ 50; confidence: REAL _ 0.9; FunctionAIS: PUBLIC PROC [outputName: ROPE, width, height: NAT, f: PROC [x, y: REAL] RETURNS [REAL], bitsPerPixel: NAT _ 8] ~ TRUSTED { raster: AIS.Raster _ NEW[AIS.RasterPart _ [ scanCount: height, scanLength: width, scanMode: rd, bitsPerPixel: bitsPerPixel, linesPerBlock: -1, paddingPerBlock: 177777B ]]; maxPixelValue: NAT _ Real.Round[RealFns.Exp[bitsPerPixel*RealFns.Ln[2]]]-1; output: AIS.FRef _ AIS.CreateFile[name: outputName, raster: raster]; outputWindow: AIS.WRef _ AIS.OpenWindow[output]; BufferRep8: TYPE ~ PACKED ARRAY [0..3000) OF [0..256); lineBuffer: REF BufferRep8 _ NEW[BufferRep8]; lineBufferDesc: AIS.Buffer _ [length: SIZE[BufferRep8], addr: BASE[lineBuffer^]]; min: REAL _ 0.0; max: REAL _ 1.0; inner: SAFE PROC ~ TRUSTED { scale: REAL ~ maxPixelValue/(max-min); FOR i: NAT IN [0..outputWindow.GetWindowParams.lastScan] DO y: REAL _ (height-0.5-i)/height; Process.CheckForAbort[]; lineBuffer^ _ ALL[0]; FOR j: NAT IN [0..width) DO x: REAL _ (0.5+j)/width; pixel: [0..256) _ MIN[MAX[Real.RoundLI[(f[x,y]-min)*scale], 0], maxPixelValue]; IF pixel>0 THEN { bitIndex: INT = LONG[j]*bitsPerPixel; bufIndex: NAT = bitIndex/8; lineBuffer[bufIndex] _ lineBuffer[bufIndex]+ Basics.BITSHIFT[pixel, 8-bitsPerPixel-(bitIndex MOD 8)]; }; ENDLOOP; AIS.UnsafeWriteLine[outputWindow, lineBufferDesc, i]; ENDLOOP; }; IF autoRange > 0 THEN { random: Random.RandomStream _ Random.Create[]; m: REAL _ 0; min _ 99999999.0; max _ -99999999.0; FOR i: INT IN [0..autoRange) DO x: REAL _ Real.FScale[Random.ChooseInt[random, 0, LONG[256]*256*256], -24]; y: REAL _ Real.FScale[Random.ChooseInt[random, 0, LONG[256]*256*256], -24]; z: REAL _ f[x,y]; m _ m + z; min _ MIN[min, z]; max _ MAX[max, z]; ENDLOOP; IF max = min THEN max _ max + 3.90625e-3; m _ (max+min)/2; max _ m + (max-m)/confidence; min _ m - (m-min)/confidence; }; CedarProcess.DoWithPriority[background, inner]; AIS.CloseFile[output]; }; ValueRange: PROC [inputName: ROPE] RETURNS [minvalue, maxvalue: REAL] ~ TRUSTED { ais: AIS.FRef _ AIS.OpenFile[name: inputName]; window: AIS.WRef _ AIS.OpenWindow[ais]; BufferRep: TYPE ~ PACKED ARRAY [0..3000) OF [0..256); nPerLine: NAT _ window.GetWindowParams.lastPixel+1-window.GetWindowParams.firstPixel; lineBuffer1: REF BufferRep _ NEW[BufferRep]; lineBuffer1Desc: AIS.Buffer _ [length: SIZE[BufferRep], addr: BASE[lineBuffer1^]]; minvalue _ 1.0; maxvalue _ 0.0; FOR i: NAT IN [0..window.GetWindowParams.lastScan] DO AIS.UnsafeReadLine[window, lineBuffer1Desc, i]; FOR j: NAT IN [0..nPerLine) DO pix: REAL _ lineBuffer1[j]/255.0; minvalue _ MIN[pix, minvalue]; maxvalue _ MAX[pix, maxvalue]; ENDLOOP; ENDLOOP; AIS.CloseFile[ais]; }; ChangeContrast: PROC [inputName, outputName: ROPE, oldminvalue, oldmaxvalue, newminvalue, newmaxvalue: REAL] ~ TRUSTED { ais: AIS.FRef _ AIS.OpenFile[name: inputName]; raster: AIS.Raster _ AIS.ReadRaster[ais]; output: AIS.FRef _ AIS.CreateFile[name: outputName, raster: raster]; window: AIS.WRef _ AIS.OpenWindow[ais]; outputWindow: AIS.WRef _ AIS.OpenWindow[output]; BufferRep: TYPE ~ PACKED ARRAY [0..3000) OF [0..256); nPerLine: NAT _ window.GetWindowParams.lastPixel+1-window.GetWindowParams.firstPixel; outBuf: REF BufferRep _ NEW[BufferRep]; lineBuffer1: REF BufferRep _ NEW[BufferRep]; lineBuffer1Desc: AIS.Buffer _ [length: SIZE[BufferRep], addr: BASE[lineBuffer1^]]; outBufferDesc: AIS.Buffer _ [length: SIZE[BufferRep], addr: BASE[outBuf^]]; m: REAL _ (newmaxvalue-newminvalue)/(oldmaxvalue-oldminvalue); FOR i: NAT IN [0..outputWindow.GetWindowParams.lastScan] DO AIS.UnsafeReadLine[window, lineBuffer1Desc, i]; FOR j: NAT IN [0..nPerLine) DO pix: REAL _ lineBuffer1[j]/255.0; out: REAL _ (pix-oldminvalue)*m+newminvalue; outBuf[j] _ MIN[MAX[Real.RoundLI[out*255], 0], 255]; ENDLOOP; AIS.UnsafeWriteLine[outputWindow, outBufferDesc, i]; ENDLOOP; AIS.CloseFile[ais]; AIS.CloseFile[output]; }; END. Texture2DImpl.mesa Copyright (C) 1985, 1986, Xerox Corporation. All rights reserved. Michael Plass, January 17, 1986 9:37:03 am PST Perlin, September 13, 1985 5:53:07 pm PDT McCreight, December 20, 1985 12:39:50 pm PST Noise routines IF christmas THEN { t: REAL ~ 4*(x01-0.5)*(x01-0.5)/((1.001-y01)*(1.001-y01)); dz _ dz / (1-t); dz _ dz + 0.5-t; RETURN [0.5-t]; }; z _ z + FNoise[x, y]; Static data needed by Noise: declare local variables. initialize random permutation table Map all points into the [0..np-1]3 cube by wrapping around in each dimension. jxyz _ the integer lattice point "just below" the point (identifies the surrounding unit cube). sxyz _ the vector difference (point - jxyz) biased with an S-Curve in each dimension. Compute and add in weighted gradient at each corner Κζ˜codešœ™K™AK™.K™)™,K˜—KšΟk œ œ@˜UK˜—KšΠln œ ˜Kšœ œ.˜AKšœ ˜Kšœ˜K™šœ™K˜šœ œœ˜K˜—šœœœ˜K˜—š œœ œœœ˜,Kšœ˜K˜—Kšœ œΟc5˜PK˜KšœœŸ˜2Kšœœ˜ Kšœœ˜Kšœ œ‹˜˜K˜K˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜ K˜Kšœœ˜Kšœœ˜šœ œ˜K˜—š Οnœœœœœœ˜3K˜—Kšœ œ˜Kšœ œ˜Kšœ œ˜Kšœœ˜Kšœ œ˜š  œœœœœ˜*šœ œ˜Kšœœ)˜0Kšœœ ˜Kšœœœ˜#Kšœœ,˜6Kšœœ˜Kšœ ˜ Kšœœ ˜Kšœ˜—Kšœ˜ Kšœ˜K˜—š   œœœœœ˜.Kšœœ˜Kšœœ˜Kšœœ ˜Kšœœ ˜Kšœ˜šœ œŸ-˜RK˜—šœ Ÿ-˜:Kšœœ˜Kšœœ˜ šœœœ˜š  œœœœœ˜+Kšœ&˜,Kšœ˜—Kšœ<˜Kšœœ ˜Kšœœ˜ šœœœ˜š  œœœœœ˜+Kšœ(˜.Kšœ˜—Kšœœ˜K˜Kšœ˜—K˜Kšœ˜Kšœ˜—šœ Ÿ-˜:Kšœœ˜Kšœœ˜ šœœœ˜š  œœœœœ˜+Kšœ(˜.Kšœ˜—Kšœœ˜K˜Kšœ˜—K˜Kšœ˜Kšœœœ˜Kšœœœœ˜Kšœœ˜Kšœ˜—Kšœœ˜Kšœ˜K˜—š  œœœœœ˜&Kšœœ˜K˜ Kšœ ˜K˜—š  œœœœœ˜,Kšœœ˜Kšœœ˜Kšœœ ˜K˜ Kšœ ˜K˜—š  œœœœœ˜,Kšœœ˜Kšœ˜Kšœ ˜Kšœ˜K˜—šœ œœ˜*Kš œœœœ œœœ˜H—Kšœ œ˜Kš œœœœ˜<š œœœœ˜9Kšœœ˜/Kšœ:˜:šœœœ˜K˜ Kšœ˜—šœœœ ˜K•StartOfExpansion=[rs: Random.RandomStream _ NIL, min: INT _ 0, max: INT]šœœ0˜6Kšœœ˜K˜ K˜ K˜Kšœ˜—Kšœ˜ ˜K˜——šœ™Kšœœ˜Kšœœ˜Kšœ œœ˜&Kš œœœœ œœ ˜DKšœœœ œ˜'Kšœœ˜—š œΟsœ œœœŸΠcmΠcuŸ˜Tšœ™Kšœ œ˜Kšœœ˜—šœ#™#šœœœ˜Kšœ˜Kšœœ˜ šœœœ ˜Kš œœœœœœ œ˜Jš  œœ œ˜0Kšœœ5˜>Kšœ œ ˜Kšœ!˜'Kšœ˜—Kšœ?˜?Kšœ˜—K˜——šœ!Οuœ+™Mš˜š   œœœœœœ˜4Kšœ˜Kš œœœ œœ˜0—K˜K˜K˜—Kšœ˜—šœΟdœ[™_Kšœ˜Kšœ˜Kšœ˜—šœ₯œΟiœ₯œ+™Uš˜Kš  œœœœœœ˜IK˜K˜K˜—Kšœ˜—KšœŸ˜"š œœœœŸ@˜Xš œœœœ˜2Kšœ,˜2Kšœ˜—šœœŸ<˜JKšœ6˜6Kšœ9˜9KšœA˜AKšœ5˜5KšœH˜HKšœ5˜5Kšœ<˜šœœœ,˜;Kšœ,˜/šœœœ˜Kšœœ˜!Kšœœ#˜,Kšœ œœ!˜4Kšœ˜—Kšœ1˜4Kš˜—Kšœ˜Kšœ˜Kšœ˜K˜—K˜—šœ˜K˜—K˜—…—2ΰJδ