DIRECTORY CedarProcess, CommanderOps, Controls, CtMap, CtViewer, FS, G3dBasic, G3dLight, G3dMatrix, G3dRender, G3dShape, G3dTool, G3dVector, G3dView, Imager, ImagerColor, ImagerPixel, ImagerPixelArray, ImagerSample, IO, MessageWindow, Real, RefText, Rope, SF, UnixSpawnTCP, UnixSysCalls, UnixTypes, UXStrings, ViewerClasses; G3dToolRIBImpl: CEDAR PROGRAM IMPORTS CedarProcess, CommanderOps, Controls, CtMap, CtViewer, FS, G3dMatrix, G3dRender, G3dTool, G3dVector, G3dView, Imager, ImagerColor, ImagerPixel, ImagerPixelArray, ImagerSample, IO, MessageWindow, Real, RefText, Rope, SF, UnixSpawnTCP, UnixSysCalls, UXStrings EXPORTS G3dTool ~ BEGIN Triple: TYPE ~ G3dBasic.Triple; SpawnData: TYPE ~ G3dTool.SpawnData; Tool: TYPE ~ G3dTool.Tool; WriteProc: TYPE ~ G3dTool.WriteProc; SampleMap: TYPE ~ ImagerSample.SampleMap; SampleBuffer: TYPE ~ ImagerSample.SampleBuffer; FD: TYPE ~ UnixTypes.FileDescriptor; CHARPtr: TYPE ~ UnixTypes.CHARPtr; ROPE: TYPE ~ Rope.ROPE; Render: PUBLIC PROC [tool: Tool, fork: BOOL ¬ TRUE] ~ { IF tool.shapes = NIL OR tool.shapes.length = 0 THEN Blink["no shapes to render!"] ELSE [] ¬ CedarProcess.Fork[ForkRender, tool, [normal, TRUE]]; }; WriteRIBtoFile: PUBLIC PROC [tool: Tool, fileName: ROPE] ~ { IF fileName # NIL THEN WriteRIBtoStream[tool, FS.StreamOpen[fileName, $create]]; }; WriteRIBtoStream: PUBLIC PROC [tool: Tool, out: IO.STREAM] ~ { IF out = NIL THEN Blink["can't create file"] ELSE { Write: WriteProc ~ {IO.PutRope[out, rope]}; ToolToRIB[tool, Write]; IO.Close[out]; }; }; ToolToRIB: PROC [t: Tool, write: WriteProc] ~ { moves: Triple ¬ [t.camera.par.xMov.value, t.camera.par.yMov.value, t.camera.par.zMov.value]; rots: Triple ¬ [t.camera.par.xRot.value, t.camera.par.yRot.value, t.camera.par.zRot.value]; scale: REAL ¬ t.camera.scale.value; fov: REAL ¬ t.camera.fieldOfView.value; lights: G3dLight.LightSequence ¬ t.lights; comment: ROPE ¬ IO.PutFR1["(from %g)", IO.rope[t.name]]; imageName: ROPE ¬ IF t.ribMode = file THEN Rope.Concat[t.directory, "Temp.tiff"] ELSE NIL; ToRIB[imageName, t.frameSize, t.color, scale, fov, moves, rots, t.shapes, lights, write, comment]; }; DoCommand: PROC [t: Tool, command, status: ROPE] ~ { Controls.TypescriptWrite[t.typescript, status]; [] ¬ CommanderOps.DoCommand[command, t.cmd]; }; RenderOpsButton: PUBLIC ViewerClasses.ClickProc ~ { t: Tool ¬ NARROW[clientData]; IF mouseButton = red THEN Render[t] ELSE { choice: INT ¬ Controls.PopUpRequest[["Render Ops"], LIST[ -- 1 -- ["Size", IO.PutFR["now %g by %g", IO.int[t.frameSize.x],IO.int[t.frameSize.y]]], -- 2 -- IF t.color THEN ["Color", "change to BW"] ELSE ["BW", "change to color"], -- 3 -- IF t.ribMode = file THEN ["FS", "change to Spawn"] ELSE ["Spawn", "change to File System"]]]; G3dTool.SetCursor[t, TRUE]; SELECT choice FROM 1 => t.frameSize ¬ Controls.GetIntegerPair[t.typescript, "frame size", t.frameSize]; 2 => t.color ¬ NOT t.color; 3 => t.ribMode ¬ IF t.ribMode = file THEN spawn ELSE file; ENDCASE; G3dTool.SetCursor[t, FALSE]; }; }; ForkRender: CedarProcess.ForkableProc ~ { t: Tool ¬ NARROW[data]; G3dTool.StartTimer[t]; IF t.ribMode = spawn THEN RenderViaUnixSpawn[t] ELSE RenderViaFileSystem[t]; }; RenderViaFileSystem: PROC [t: Tool] ~ { command: ROPE ¬ IO.PutFR1["render %gTemp.rib", IO.rope[t.directory]]; Controls.TypescriptWrite[t.typescript, "writing RIB... "]; WriteRIBtoFile[t, IO.PutFR1["%gTemp.rib", IO.rope[t.directory]]]; t.unixSpawn ¬ UnixSpawnTCP.Spawn[command, t.cmd.out, t.cmd.out, Done, ReadOut, t]; Controls.TypescriptWrite[t.typescript, "rendering... "]; }; RenderViaUnixSpawn: PROC [t: Tool] ~ { Write: WriteProc ~ { IF t.unixSpawn # NIL THEN UnixSpawnTCP.Write[t.unixSpawn, rope] ELSE RETURN[FALSE]; }; Controls.TypescriptWrite[t.typescript, "sending RIB... "]; IF (t.unixSpawn ¬ UnixSpawnTCP.Spawn["render", t.cmd.out, t.cmd.out, Done, ReadOut, t])=NIL THEN Blink["can't spawn!"] ELSE ToolToRIB[t, Write]; Controls.TypescriptWrite[t.typescript, "done!"]; }; ViewerData: TYPE ~ RECORD [x, y, w, h: INTEGER, bwMap: SampleMap, size: SF.Vec, t: Tool]; Update: CtViewer.ViewerProc ~ { -- can not be nested u: REF ViewerData ¬ NARROW[clientData]; ImagerSample.BasicTransfer[maps[0].map, u.bwMap, [u.y, u.x], [0, 0], [u.h, u.w]]; affectedRegion ¬ [[u.y, u.x], [u.y+u.h, u.x+u.w]]; }; ShowColor: CtViewer.ViewerProc ~ { -- can not be nested u: REF ViewerData ¬ NARROW[clientData]; pm: ImagerPixel.PixelMap ¬ ImagerPixel.MakePixelMap[u.t.rMap, u.t.gMap, u.t.bMap]; pa: ImagerPixelArray.PixelArray ¬ ImagerPixelArray.FromPixelMap[pm, [[0, 0], u.size], [down, right]]; op: ImagerColor.ColorOperator ¬ ImagerColor.NewColorOperatorRGB[255]; Imager.DrawSampledColor[context, pa, op]; affectedRegion.max ¬ u.size; }; ReadOut: CedarProcess.ForkableProc ~ { Done: ERROR = CODE; CheckMap: PROC [map: SampleMap] RETURNS [ret: SampleMap] ~ { IF (ret ¬ map) = NIL OR ImagerSample.GetSize[ret] # u.size THEN { IF map # NIL THEN ImagerSample.ReleaseScratchMap[map]; ret ¬ ImagerSample.ObtainScratchMap[[[0, 0], u.size], 8]; }; }; windowS: IO.STREAM; u: REF ViewerData ¬ NEW[ViewerData]; s: REF SpawnData ¬ NARROW[data]; t: Tool ¬ u.t ¬ NARROW[s.clientData]; x, y, w, h, nBytes, charsIndex: INTEGER ¬ 0; v: ViewerClasses.Viewer ¬ CtViewer.currentViewer ¬ CtViewer.GetViewer[Rope.Concat[t.name, ": Image"], right, t.frameSize.y, TRUE]; window: REF TEXT ¬ RefText.ObtainScratch[100]; chars: CHARPtr ¬ UXStrings.ObtainScratch[1024]; rLine, gLine, bLine, bwLine: SampleBuffer; u.size ¬ SF.Min[[v.ch, v.cw], [t.frameSize.y, t.frameSize.x]]; u.bwMap ¬ ImagerSample.ObtainScratchMap[[[0, 0], [100, 100]], 8]; bwLine ¬ ImagerSample.ObtainScratchSamples[100]; IF t.color THEN { rLine ¬ ImagerSample.ObtainScratchSamples[100]; gLine ¬ ImagerSample.ObtainScratchSamples[100]; bLine ¬ ImagerSample.ObtainScratchSamples[100]; t.rMap ¬ CheckMap[t.rMap]; t.gMap ¬ CheckMap[t.gMap]; t.bMap ¬ CheckMap[t.bMap]; }; CtMap.Gamma[]; DO TRUSTED { ENABLE Done => EXIT; Next: UNSAFE PROC RETURNS [char: CHAR] ~ UNCHECKED { IF charsIndex >= nBytes THEN { IF (nBytes ¬ UnixSysCalls.Read[s.fdOut, chars, 1023]) <= 0 THEN ERROR Done; charsIndex ¬ 0; }; char ¬ chars[charsIndex]; charsIndex ¬ charsIndex+1; }; ch: CHAR ¬ 0c; window.length ¬ 0; WHILE (ch ¬ Next[]) # '\n DO window ¬ RefText.AppendChar[window, ch]; ENDLOOP; windowS ¬ IO.TIS[window]; x ¬ u.x ¬ IO.GetInt[windowS]; y ¬ u.y ¬ IO.GetInt[windowS]; IF (w ¬ IO.GetInt[windowS])+x > v.cw THEN w ¬ v.cw-x; IF (h ¬ IO.GetInt[windowS])+y > v.ch THEN h ¬ v.ch-y; IF x >= v.cw THEN LOOP; IF y >= v.ch THEN EXIT; IF w+x > v.cw THEN w ¬ v.cw-x; IF h+y > v.ch THEN h ¬ v.ch-y; u.w ¬ w; u.h ¬ h; FOR j: INT IN [0..h) DO FOR i: INT IN [0..w) DO r: BYTE ~ ORD[Next[]]; g: BYTE ~ ORD[Next[]]; b: BYTE ~ ORD[Next[]]; IF t.color THEN {rLine[i] ¬ r; gLine[i] ¬ g; bLine[i] ¬ b}; bwLine[i] ¬ MIN[255, MAX[0, Real.Round[.3*REAL[r]+.59*REAL[g]+.11*REAL[b]]]]; ENDLOOP; ImagerSample.PutSamples[u.bwMap, [j, 0],, bwLine, 0, w]; IF t.color THEN { ImagerSample.PutSamples[t.rMap, [y+j, x],, rLine, 0, w]; ImagerSample.PutSamples[t.gMap, [y+j, x],, gLine, 0, w]; ImagerSample.PutSamples[t.bMap, [y+j, x],, bLine, 0, w]; }; ENDLOOP; CtViewer.DoWithViewer[v, Update, u]; CedarProcess.CheckAbort[]; }; ENDLOOP; IF t.color THEN {CtMap.Dither[]; CtViewer.DoWithViewer[v, ShowColor, t]}; RefText.ReleaseScratch[window]; UXStrings.ReleaseScratch[chars]; FOR l: LIST OF SampleBuffer ¬ LIST[rLine, gLine, bLine, bwLine], l.rest WHILE l # NIL DO IF l.first # NIL THEN ImagerSample.ReleaseScratchSamples[l.first]; ENDLOOP; ImagerSample.ReleaseScratchMap[u.bwMap]; IF t.ribMode = file THEN { DoCommand[t, IO.PutFR["! tiffcopy -none -noalpha %gTemp.tiff %gTemp.dump", IO.rope[t.directory], IO.rope[t.directory]], "tiffcopy... "]; DoCommand[t, IO.PutFLR["Ct DumpToAIS %gTemp.dump %gTemp -gbr -size %g %g", LIST[IO.rope[t.directory], IO.rope[t.directory], IO.int[t.frameSize.x], IO.int[t.frameSize.y]]], "to AIS... "]; DoCommand[t, IO.PutFR["Ct View %gTemp%g -right", IO.rope[t.directory], IO.rope[IF t.color THEN NIL ELSE "-red.ais"]], "display "]; }; }; Done: UnixSpawnTCP.FinishProc ~ { t: Tool ¬ NARROW[clientData]; G3dTool.TSWrite[t, IO.PutFR1["(%g secs)", IO.real[G3dTool.ElapsedTime[t]]]]; UnixSpawnTCP.Close[t.unixSpawn]; t.unixSpawn ¬ NIL; IF status = $NotFound THEN Blink["can't render (Renderman unavailable on this machine?)"] }; MatrixFromCamera: PUBLIC PROC [scale: REAL, moves, rotates: Triple, leftHanded: BOOL] RETURNS [m: G3dMatrix.Matrix] ~ { -- camera transformation for Renderman renderer, courtesy Dan McCoy, PIXAR from, at, up, camx, camy, camz: Triple; m ¬ G3dMatrix.Identity[]; [from, at, up] ¬ G3dView.FromScaleMovesRots[scale, moves, rotates]; camz ¬ G3dVector.Unit[G3dVector.Sub[at, from]]; camy ¬ G3dVector.Unit[up]; IF leftHanded THEN { camx ¬ G3dVector.Unit[G3dVector.Cross[camy, camz]]; camy ¬ G3dVector.Unit[G3dVector.Cross[camz, camx]]; } ELSE { camx ¬ G3dVector.Unit[G3dVector.Cross[camz, camy]]; camy ¬ G3dVector.Unit[G3dVector.Cross[camx, camz]]; }; m[0] ¬ [scale*camx.x, scale*camy.x, scale*camz.x, 0.0]; m[1] ¬ [scale*camx.y, scale*camy.y, scale*camz.y, 0.0]; m[2] ¬ [scale*camx.z, scale*camy.z, scale*camz.z, 0.0]; m[3] ¬ [-G3dVector.Dot[from,camx],-G3dVector.Dot[from,camy],-G3dVector.Dot[from,camz],1]; }; ToRIB: PUBLIC PROC [ imageName: ROPE ¬ NIL, frameSize: G3dBasic.IntegerPair, color: BOOL, scale, fieldOfView: REAL, moves, rotates: Triple, shapes: G3dShape.ShapeSequence, lights: G3dLight.LightSequence, writer: WriteProc, comment: ROPE ¬ NIL] ~ { abort: ERROR = CODE; Inner: PROC ~ { Write: PROC [rope: ROPE] ~ {IF NOT writer[rope] THEN ERROR abort}; WriteMatrix: PROC [m: G3dMatrix.Matrix, concat: BOOL] ~ { Write[IO.PutFR1["%gTransform [\n", IO.rope[IF concat THEN "Concat" ELSE NIL]]]; FOR i: INTEGER IN [0..4) DO Write[IO.PutFLR["\t\t%g %g %g %g%g\n", LIST[ IO.real[m[i][0]], IO.real[m[i][1]], IO.real[m[i][2]], IO.real[m[i][3]], IO.rope[IF i = 3 THEN "]" ELSE NIL]]]]; ENDLOOP; }; WriteShape: PROC [s: G3dShape.Shape] ~ { GetStop: PROC [startPoly: INTEGER] RETURNS [stopPoly, startVert, stopVert: INTEGER] ~ { num: INTEGER ¬ 0; startVert ¬ stopVert ¬ s.surfaces[startPoly].vertices[0]; FOR stopPoly ¬ startPoly, stopPoly+1 WHILE stopPoly < INTEGER[s.surfaces.length] DO p: G3dBasic.NatSequence ¬ s.surfaces[stopPoly].vertices; IF (num ¬ num+3*(p.length-2)-- incr by # triangle vertices --) > 30000 THEN EXIT; FOR i: INTEGER IN [0..p.length) DO -- find vertex id bounds id: INTEGER ¬ p[i]; IF id < startVert THEN startVert ¬ id ELSE IF id > stopVert THEN stopVert ¬ id; ENDLOOP; ENDLOOP; stopPoly ¬ stopPoly-1; -- range is [startPoly..stopPoly] }; WriteSubShape: PROC [startPoly, stopPoly, startVert, stopVert: INTEGER] ~ { WritePoints: PROC [i0, i1: INTEGER, op: {pos, nrml, color}] ~ { Write[SELECT op FROM pos => "\"P\" [", nrml => "\"N\" [", ENDCASE => "\"Cs\" ["]; FOR i: INTEGER IN [i0..i1] DO v: G3dShape.Vertex ¬ s.vertices[i]; t: Triple ¬ SELECT op FROM pos => v.point, nrml => v.normal, ENDCASE => v.color; Write[IO.PutFR["%g %g %g ", IO.real[t.x], IO.real[t.y], IO.real[t.z]]]; ENDLOOP; Write["]\n"]; }; Write["AttributeBegin\n"]; Write[IO.PutFR1["Sides %g\n", IO.int[IF s.showBackfaces THEN 2 ELSE 1]]]; Write["ShadingRate 1\n"]; Write["ShadingInterpolation \"constant\"\n"]; Write["Color [1.0 1.0 1.0]\n"]; Write["Surface \"metal\" \"Ks\" 0.8 \"Ka\" 0.2 \"roughness\" 0.5\n"]; Write[IO.PutFR["Opacity [%g %g %g]\n", IO.real[opacity], IO.real[opacity], IO.real[opacity]]]; WriteMatrix[s.matrix, FALSE]; Write["PointsPolygons\n"]; Write["["]; FOR i: INTEGER IN [startPoly..stopPoly] DO FOR j: INT IN [0..s.surfaces[i].vertices.length-2) DO Write["3 "]; ENDLOOP; -- triangle ENDLOOP; Write["]\n["]; FOR i: INTEGER IN [startPoly..stopPoly] DO -- vertex index array (< 30000) p: G3dBasic.NatSequence ¬ s.surfaces[i].vertices; FOR j: INTEGER IN [1..p.length-2] DO -- triangulate Write[IO.PutFR["%g %g %g ", -- vertices referenced from 0, direction reversed: IO.int[p[j+1]-startVert], IO.int[p[j]-startVert], IO.int[p[0]-startVert]]]; ENDLOOP; ENDLOOP; Write["]\n"]; WritePoints[startVert, stopVert, pos]; WritePoints[startVert, stopVert, nrml]; IF color AND hasColor THEN WritePoints[startVert, stopVert, color]; Write["AttributeEnd\n"]; }; renderData: G3dRender.RenderData ¬ G3dRender.RenderDataFrom[s]; opacity: REAL ¬ 1.0-renderData.transmittance; hasColor: BOOL ¬ FALSE; startPoly, stopPoly, startVert, stopVert: INTEGER ¬ 0; FOR i: INTEGER IN [0..s.vertices.length) DO v: G3dShape.Vertex ¬ s.vertices[i]; IF v.color.x NOT IN[.99..1.01] OR v.color.y NOT IN[.99..1.01] OR v.color.z NOT IN[.99..1.01] THEN {hasColor ¬ TRUE; EXIT}; ENDLOOP; Write[IO.PutFR["# %g: %g polygons, %g vertices\n", IO.rope[s.name], IO.int[s.surfaces.length], IO.int[s.vertices.length]]]; DO [stopPoly, startVert, stopVert] ¬ GetStop[startPoly]; WriteSubShape[startPoly, stopPoly, startVert, stopVert]; IF stopPoly = INTEGER[s.surfaces.length]-1 THEN EXIT; startPoly ¬ stopPoly+1; ENDLOOP; }; WriteLight: PROC [l: G3dLight.Light, id: INTEGER] ~ { to: Triple ¬ G3dVector.Add[l.position, l.direction]; Write[IO.PutFLR["LightSource \"distantlight\" %g \"lightcolor\" [%g %g %g] \"intensity\" [1.0] \"from\" [%g %g %g] \"to\" [%g %g %g]\n", LIST[IO.int[id], IO.real[l.color.R], IO.real[l.color.G], IO.real[l.color.B], IO.real[l.position.x], IO.real[l.position.y], IO.real[l.position.z], IO.real[to.x], IO.real[to.y], IO.real[to.z]]]]; }; Write[IO.PutFR1["# RIB data %g\n", IO.rope[comment]]]; Write["PixelSamples 2 2\n"]; IF imageName = NIL THEN Write["Display \"framebuffer\" \"cedar\" \"rgba\"\n"] ELSE Write[IO.PutFR1["Display \"%g\" \"file\" \"rgba\"\n", IO.rope[imageName]]]; Write["ScreenWindow -1.33333 1.33333 -1 1\n"]; Write[IO.PutFR["Format %g %g 1\n", IO.int[frameSize.x], IO.int[frameSize.y]]]; Write["Identity\n"]; Write[IO.PutFR1["Projection \"perspective\" \"fov\" %g\n", IO.real[fieldOfView]]]; WriteMatrix[MatrixFromCamera[scale, moves, rotates, TRUE], TRUE]; Write["WorldBegin\n"]; IF lights # NIL THEN { Write[IO.PutFR["LightSource \"ambientlight\" 1 \"lightcolor\" [%g %g %g] \"intensity\" 1.0\n", IO.real[lights.ambient.R], IO.real[lights.ambient.G], IO.real[lights.ambient.B]]]; FOR i: INT IN [0..lights.length) DO WriteLight[lights[i], i+2]; ENDLOOP; }; IF shapes # NIL THEN FOR i: INT IN [0..shapes.length) DO WriteShape[shapes[i]]; ENDLOOP; Write["WorldEnd\n"]; }; Inner[ ! abort => CONTINUE]; }; Blink: PROC [msg: ROPE] ~ { MessageWindow.Append[msg]; MessageWindow.Blink[]; }; END. „ G3dToolRIBImpl.mesa Copyright c 1991 by Xerox Corporation. All rights reserved. Bloomenthal, March 8, 1993 4:41 pm PST 3d Tool: Renderman Rendering RIB From Render Tool Note: the Unix display driver written in C is in /usr/local/prman/etc/dspyinst/; after editing d¬cedar.c, then, in a Shell window: make install RenderButton: PUBLIC ViewerClasses.ClickProc ~ {Render[NARROW[clientData]]}; Rendering We note, dispiritedly, the following timings for a 5000 point, 5000 polygon shape: Transmission of RIB data to the spawned Unix render command: 1:30 Execution of spawned render command: 1:25 Total render time using Spawn: 2:55 Writing the RIB file: 0:25 Execution of render command using RIB file: 1:50 Total render time not using Spawn: 2:15 However, using Spawn has the advantage of seeing the image as it is rendered. ReadOut presumes this format (generated by /usr/local/prman/etc/dspyinst/d¬cedar.c): 1 ASCII integer (starting x location of window) 1 ASCII integer (starting y location of window) 1 ASCII integer (width of window) 1 ASCII integer (height of window) 1 carriage-return width*height groups of: 1 byte (red) 1 byte (green) 1 byte (blue) context: Imager.Context ¬ CtBasic.ContextFromSampleMaps[maps]; With thanks to Michael Plass. Could try these Unix commands: tiffcopy -noalpha Temp.tiff source /import/sandpiper/top/enable; readtif Temp.tiff | writeais -dir AIS mv AIS/r.ais Temp-red.ais; mv AIS/g.ais Temp-grn.ais; mv AIS/b.ais Temp-blu.ais Renderman Format Renderman does not do well with non-planar polygons, so we triangulate here. Current Renderman does not accept a vertex index array greater than 32K in length. Miscellany Κ‘•NewlineDelimiter ™™Jšœ Οmœ1™J˜—š ΟnœŸœŸœŸœŸœ˜7šŸœŸœŸœ˜.JšŸœ˜"JšŸœœ2Ÿœ˜>—J˜J˜—š‘œŸ œŸœ˜šŸœŸ˜ JšŸœ˜šŸœ˜Jš‘œŸœ˜+Jšœ˜JšŸœ ˜J˜——J˜J˜—š‘ œŸœ ˜/J˜\J˜[JšœŸœ˜#JšœŸœ˜'J˜*Jšœ ŸœŸœŸœ˜8Jš œ ŸœŸœŸœ'ŸœŸœ˜ZJšœΟsœ ’œ’œ’œ’œ’œ’œ ’œ’œ’œ ˜bJ˜J˜—š‘ œŸœŸœ˜4Jšœ/˜/J˜,J˜J˜—š‘œŸœ˜3Jšœ Ÿœ ˜šŸœ˜JšŸœ ˜šŸœ˜šœŸœ)Ÿœ˜9JšΟcœ ’Ÿœ ’œ’œ’œ’ŸœŸœ˜XJš ££œŸœ Ÿœ ’œŸœ˜Qš££œŸœ˜JšœŸœ’œ˜ JšœŸœ&˜,——JšœŸœ˜šŸœŸ˜J˜TJšœœŸœ ˜JšœœŸœŸœŸœ˜:JšŸœ˜—JšœŸœ˜J˜——J˜J˜—JšΠbn œŸœ#Ÿœ™L—šž ™ š‘ œ˜)Jšœ Ÿœ˜JšœβΟbœt₯œM™­J˜šŸœ˜JšŸœ˜JšŸœ˜—J˜J˜—š‘œŸœ˜'Jšœ ŸœŸœŸœ˜EJšœ:˜:JšœŸœŸœ˜AJš œ ’œ’œ ’œ’œ’œ˜RJšœ8˜8J˜J˜—š‘œŸœ˜&š‘œ˜šŸœŸ˜JšŸœ&˜*JšŸœŸœŸœ˜Jšœ˜——J˜:šŸœ ’œ’œ’œ ’œ ’œ’œ’œŸ˜[JšŸœ˜JšŸœ˜—J˜0J˜J˜—™TJšœ’œ(™/Jšœ’œ(™/Jšœ’œ™!Jšœ’œ™"J™™J™ J™J™ —J™—š œ ŸœŸœŸœŸœ˜YJ˜—š‘œ£˜4JšœŸœŸœ ˜'J˜QJ˜2J˜J˜—š‘ œ£˜7JšœŸœŸœ ˜'J™>J˜R˜!J˜C—Icodešœ’œ’œ’œ%˜EJšœ)˜)L˜J˜J˜—š‘œ˜&J™Lš‘œŸœŸœ˜š‘œŸœŸœ˜<šŸœŸœŸœ$Ÿœ˜AJšŸœŸœŸœ%˜6J˜9J˜—Jšœ˜—Jšœ ŸœŸœ˜JšœŸœŸœ ˜$JšœŸœ Ÿœ˜ JšœŸœ˜%Jšœ Ÿœ˜,˜0JšœKŸœ˜Q—JšœŸœŸœ˜.J˜/J˜*Jšœ Ÿœ3˜>J˜AJ˜0šŸœ Ÿœ˜J˜/J˜/J˜/J˜J˜J˜J˜—L˜šŸœŸœ˜ LšŸœ Ÿœ˜š ‘œŸœŸœŸœŸœŸ œ˜4šŸœŸœ˜LšŸœ9ŸœŸœ˜KL˜Lšœ˜—L˜L˜Lšœ˜—LšœŸœ˜L˜šŸœŸ˜L˜(LšŸœ˜—Lšœ ŸœŸœ ˜Jšœ Ÿœ˜Jšœ Ÿœ˜JšŸœŸœŸœ ˜5JšŸœŸœŸœ ˜5JšŸœ ŸœŸœ˜JšŸœ ŸœŸœ˜JšŸœ Ÿœ ˜JšŸœ Ÿœ ˜J˜J˜šŸœŸœŸœŸ˜šŸœŸœŸœŸ˜LšœŸœŸœ ˜LšœŸœŸœ ˜LšœŸœŸœ ˜LšŸœ Ÿœ,˜;Jš œ ŸœŸœŸœŸœŸœ˜MLšŸœ˜—L˜8šŸœ Ÿœ˜L˜8L˜8L˜8L˜—LšŸœ˜—J˜$J˜J˜LšŸœ˜—JšŸœ Ÿœ:˜IJšœ˜J˜ š ŸœŸœŸœŸœ&ŸœŸœŸ˜XJšŸœ ŸœŸœ-˜BJšŸœ˜—J˜(šŸœŸœ˜Jšœ Ÿœ<ŸœŸœ%˜ˆJšœ Ÿœ<ŸœŸœŸœŸœŸœ’œ’œ˜Ίšœ Ÿœ!˜0Lš ŸœŸœŸœ ŸœŸœŸœ˜Q—™J™J™JJ™O—J˜—J˜J˜—š‘œ˜!Jšœ Ÿœ ˜JšœŸœŸœ ˜LJ˜ JšœŸœ˜JšŸœŸœ?˜YJ˜——šž™š‘œ’ŸΠksŸ’œ’Ÿœ’œ’œ’œ’œ Ÿœ˜UJšŸœ˜Jšœ£J˜NJ˜'J˜J˜CJ˜/J˜šŸœ ˜ šŸœ˜J˜3J˜3Jšœ˜—šŸœ˜J˜3J˜3Jšœ˜——J˜7J˜7J˜7J˜YJšœ˜J˜—š‘œŸ œ˜Jšœ ŸœŸœ˜Jšœ ˜ JšœŸœ˜ JšœŸœ˜J˜Jšœ˜Jšœ˜Jšœ˜Jšœ ŸœŸœ˜Jšœ˜JšœŸœŸœ˜š‘œŸœ˜Jš‘œŸœŸœŸœŸœŸœŸœ˜Bš‘ œŸœŸœ˜9Jš œŸœŸœŸœŸœ ŸœŸœ˜OšŸœŸœŸœŸ˜šœŸœŸœ˜,JšŸœŸœŸœŸœ˜GJš ŸœŸœŸœŸœŸœ˜'—JšŸœ˜—J˜—š‘ œŸœ˜(J™LJšœ’œ ’œ’œ’œ’œ’œ’œ’œ’œ’œ’œ’œ’œ™Rš‘œ’Ÿ’œ ’Ÿœ’Ÿ’œ ’œ ’œ ’Ÿœ’œ’œ˜WJšœŸœ˜J˜9šŸœ"Ÿœ ŸœŸ˜SJ˜8JšŸ’œ’œ’œ£Πcs£§£§£§£§£§£œ’œ’œ’Ÿ’Ÿœ˜Qš ŸœŸœŸœŸœ£˜;JšœŸœ˜Jš ŸœŸœŸœŸœŸœ˜OJšŸœ˜—JšŸœ˜—Jšœ£!˜8J˜—š‘ œŸœ,Ÿœ˜Kš‘ œŸœ Ÿœ˜?JšœŸœŸœ&Ÿœ˜QšŸœŸœŸœ Ÿ˜J˜#Jšœ’œ’œ’Ÿ’œ’Ÿ’œ’œ’œ’œ’œ’œ ¦Ÿ’œ’œ˜PJš œŸœŸœ Ÿœ Ÿœ ˜GJšŸœ˜—J˜ Jšœ˜—Jšœ˜Jš œŸœŸœŸœŸœŸœ˜IJšœ˜Jšœ-˜-Jšœ˜JšœE˜Eš œŸœ’œ’œ’œ˜&JšŸœ’Ÿœ’Ÿœ˜7—JšœŸœ˜Jšœ˜Jšœ ˜ šŸœŸœŸœŸ˜*JšŸ’œ’Ÿ’Ÿ’œ$’Ÿ’œ’œ’Ÿœ’£§£˜WJšŸœ˜—J˜š ŸœŸœŸœŸœ£˜JJ˜1š ŸœŸœŸœŸœ£˜3šœŸœ£2˜NJšŸœ˜JšŸœ˜JšŸœ˜—JšŸœ˜—JšŸœ˜—Jšœ ˜ Jšœ&˜&Jšœ'˜'JšŸœŸœ Ÿœ)˜CJšœ˜J˜—J˜?Jšœ Ÿœ ˜-Jšœ ŸœŸœ˜Jšœ*Ÿœ˜6šŸœŸœŸœŸ˜+J˜#šŸ’œ ’Ÿ’Ÿœ ’Ÿ’œ ’Ÿ’Ÿœ ’Ÿ’œ ’Ÿ’Ÿœ ˜\JšŸœ ŸœŸœ˜—JšŸœ˜—šœŸœ*˜2JšŸœŸœŸœ˜H—šŸ˜J˜5J˜8JšŸœ ŸœŸœŸœ˜5J˜JšŸœ˜—J˜—š‘ œŸœŸœ˜5J˜4JšœŸœŸœŸœ ŸœŸœŸœŸœŸœŸœŸœ Ÿœ Ÿœ˜ΚJ˜—JšœŸœŸœ˜6Jšœ˜šŸœ Ÿ˜JšŸœ6˜:JšŸœŸœ.Ÿœ˜P—Jšœ.˜.JšœŸœŸœŸœ˜NJšœ˜JšœŸœ3Ÿœ˜RJšœ4ŸœŸœ˜AJšœ˜šŸœ ŸœŸœ˜Jš œŸœWŸœŸœŸœ˜±Jš ŸœŸœŸœŸœŸœ˜HJ˜—JšŸ’œ’œ’Ÿ’Ÿ’Ÿœ’ŸœŸœŸœŸœ˜XJšœ˜J˜—JšœŸœ˜J˜——šž ™ š‘œŸœŸœ˜J˜J˜J˜——J˜JšŸœ˜—…—8\Pq