DIRECTORY Basics, CD, CDBasics, CDCells, CDCurves, CDDirectory, CDRects, CDSymbolicObjects, CGArea, CGClipper, CGReducer, CIFParser, CifToCD, Convert, GraphicsBasic, IntHashTable, IO, Real, RealFns, RefTab, Rope, RuntimeError, SymTab, TerminalIO; CifToCDImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDCurves, CDDirectory, CDRects, CDSymbolicObjects, CGArea, CGClipper, CGReducer, CIFParser, Convert, IntHashTable, IO, Real, RealFns, RefTab, Rope, RuntimeError, SymTab, TerminalIO EXPORTS CifToCD ~ BEGIN PolygonDescriptor: TYPE ~ CGReducer.Ref; ReadCifHandle: TYPE ~ REF ReadCifHandleRec; ReadCifHandleRec: TYPE ~ RECORD[ design: CD.Design, basicTransf: CD.Transformation, curObj: CifObject _ NIL, curLayerData: LayerData _ NIL, prevLayerData: LayerData _ NIL, layerTable: SymTab.Ref, symNo: CARD _ LAST[CARD], mult: CARD _ 1, div: CARD _ 1, cifPerLambda: INT _ 0, symbolTable: IntHashTable.Table, commented: BOOLEAN ]; LayerData: TYPE ~ REF LayerDataRec; LayerDataRec: TYPE ~ RECORD[ layer: CD.Layer, compensation: INT _ 0 ]; CifObject: TYPE ~ REF CifObjectRec; CifObjectRec: TYPE ~ RECORD[ ob: CD.Object, name: Rope.ROPE _ NIL, undefSymb: LIST OF CARD _ NIL, included, fullyDefined, instantiated: BOOLEAN _ FALSE ]; registredTables: RefTab.Ref _ RefTab.Create[]; -- table of the CIF to CD layer tables numSides: NAT _ 12; --number of sides of the "round" flash polygon verbose: BOOLEAN _ FALSE; --debugging printout PolyCreate: PROC RETURNS [polygon: PolygonDescriptor] ~ { huge: REAL _ 1.0E20; clipper: CGClipper.Ref _ CGClipper.New[size: 4]; CGClipper.SetBox[self: clipper, box: [xmin: -huge, ymin: -huge, xmax: huge, ymax: huge]]; polygon _ CGReducer.New[size: 4]; CGClipper.Load[self: clipper, reducer: polygon]; }; PolyVertex: PROC [polygon: PolygonDescriptor, x, y: REAL] = {CGReducer.Vertex[self: polygon, v: [x: x, y: y]]}; PolyGenerate: PROC[polygon: PolygonDescriptor, outputTrapezoid: PROC[llx, lrx, ly, ulx, urx, uy: REAL]] ~ { tiling: CGArea.Ref = CGArea.New[size: 4]; CGReducer.Close[polygon]; CGReducer.Generate[self: polygon, area: tiling]; UNTIL CGArea.Empty[tiling] DO t: GraphicsBasic.Trap = CGArea.Remove[tiling]; outputTrapezoid[llx: t.xbotL, lrx: t.xbotR, ly: t.ybot, ulx: t.xtopL, urx: t.xtopR, uy: t.ytop]; ENDLOOP; }; GetLayerTable: PROC [regKey: ATOM] RETURNS [table: SymTab.Ref] ~ { found: BOOLEAN; val: RefTab.Val; [found, val] _ RefTab.Fetch[registredTables, regKey]; IF found THEN RETURN[NARROW[val, SymTab.Ref]]; table _ SymTab.Create[]; [] _ RefTab.Store[registredTables, regKey, table]; }; RegisterLayer: PUBLIC PROC [regKey: ATOM, cifName: Rope.ROPE, cdLayer: CD.Layer, compensation: INT _ 0] RETURNS [found: BOOLEAN] ~ { layerTable: SymTab.Ref _ GetLayerTable[regKey]; IF cdLayer=CD.undefLayer THEN found _ SymTab.Delete[layerTable, cifName] ELSE found _ NOT SymTab.Store[layerTable, cifName, NEW[LayerDataRec _ [cdLayer, compensation]]]; }; GetLayerData: PROC [layerTable: SymTab.Ref, cifName: Rope.ROPE] RETURNS [layerData: LayerData] ~ { found: BOOLEAN; val: SymTab.Val; [found, val] _ SymTab.Fetch[layerTable, cifName]; IF found THEN RETURN[NARROW[val, LayerData]] ELSE CIFParser.ClientError[Rope.Concat["No registration for layer ", cifName]] }; NewCifObject: PROC [i: CARD, readH: ReadCifHandle] RETURNS [obj: CifObject] ~ { obj _ NEW [CifObjectRec]; obj.ob _ CDCells.CreateEmptyCell[]; IF NOT IntHashTable.Store[readH.symbolTable, i, obj] THEN ERROR; -- implementation bug }; IncludeAll: PROC [obj: CifObject, readH: ReadCifHandle] ~ { IF obj.included THEN RETURN; UNTIL obj.undefSymb=NIL DO son: CifObject _ NARROW[IntHashTable.Fetch[readH.symbolTable, obj.undefSymb.first].value]; IncludeAll[son, readH]; obj.undefSymb _ obj.undefSymb.rest; ENDLOOP; [] _ CDCells.ResizeCell[NIL, obj.ob]; [] _ CDDirectory.Include[design: readH.design, object: obj.ob, name: obj.name]; obj.included _ TRUE; }; IncludeOb: PROC [ob: CD.Object, trans: CD.Transformation, readH: ReadCifHandle] ~ { IF readH.curObj = NIL THEN [] _ CDCells.IncludeOb[ design: readH.design, cell: NIL, ob: ob, trans: CDBasics.ComposeTransform[trans, readH.basicTransf], mode: dontNotify ] ELSE [] _ CDCells.IncludeOb[ design: NIL, cell: readH.curObj.ob, ob: ob, trans: trans, mode: dontResize ]; }; CIFtoCDPosition: PROC[m: CIFParser.TMatrix, mult, div: INT] RETURNS [transf: CD.Transformation] = { newOr: CIFParser.Point _ CIFParser.TransformPt[m, [0, 0]]; transf.off _ [newOr.x*mult/div, newOr.y*mult/div]; IF m.a11 # 0.0 THEN { SELECT TRUE FROM m.a11>0.0 AND m.a22>0.0 => transf.orient _ original; m.a11>0.0 AND m.a22<0.0 => transf.orient _ rotate180X; m.a11<0.0 AND m.a22>0.0 => transf.orient _ mirrorX; m.a11<0.0 AND m.a22<0.0 => transf.orient _ rotate180; ENDCASE => ERROR; } ELSE { SELECT TRUE FROM m.a21>0.0 AND m.a12>0.0 => transf.orient _ rotate90X; m.a21>0.0 AND m.a12<0.0 => transf.orient _ rotate270; m.a21<0.0 AND m.a12>0.0 => transf.orient _ rotate90; m.a21<0.0 AND m.a12<0.0 => transf.orient _ rotate270X; ENDCASE => ERROR; }; }; OnAxis: PROC[p1, p2: CIFParser.Point] RETURNS[BOOL] = { RETURN[p1.x = p2.x OR p1.y = p2.y]; }; DefDelete: PROC[i: CARD, data: REF ANY] ~ { KillBiggerThanI: PROC [key: IntHashTable.Key, value: IntHashTable.Value] RETURNS [quit: BOOLEAN _ FALSE] ~ { IF key>=INT[i] THEN [] _ IntHashTable.Delete[readH.symbolTable, key]; }; readH: ReadCifHandle ~ NARROW[data]; [] _ IntHashTable.Pairs[readH.symbolTable, KillBiggerThanI] }; DefStart: PROC[i, a, b: CARD, data: REF ANY] ~ { readH: ReadCifHandle ~ NARROW[data]; IF readH.symNo#LAST[CARD] THEN ERROR; -- internal check readH.curObj _ NARROW[IntHashTable.Fetch[readH.symbolTable, i].value]; IF readH.curObj#NIL THEN { IF readH.curObj.fullyDefined THEN { readH.curObj.ob _ CDCells.CreateEmptyCell[]; TerminalIO.PutF["***Warning: Symbol #%d already defined, old symbol erased\n", IO.card[i]]; }; } ELSE readH.curObj _ NewCifObject[i, readH]; readH.curObj.fullyDefined _ TRUE; readH.symNo _ i; readH.mult _ a; readH.div _ b; readH.prevLayerData _ readH.curLayerData; -- push the global level layer readH.curLayerData _ NIL; -- a layer should be specified inside each symbol }; DefFinish: PROC[data: REF ANY] ~ { readH: ReadCifHandle ~ NARROW[data]; IF readH.curObj.undefSymb=NIL THEN IncludeAll[readH.curObj, readH]; readH.curLayerData _ readH.prevLayerData; --pop the global level layer readH.curObj _ NIL; readH.symNo _ LAST[CARD]; -- to allow to flag nested DSs (should be caught by the parser) readH.mult _ 1; readH.div _ 1; }; Polygon: PROC[p: CIFParser.Path, data: REF ANY] ~ { IncludeTrapezoid: PROC[llx, lrx, ly, ulx, urx, uy: REAL] = { IF ulx # llx OR urx # lrx THEN { points: LIST OF CD.Position _ NIL; ob: CD.Object; offset: CD.Position; points _ CONS[[Real.Round[(llx+compensation)*cdpl/cifpl], Real.Round[(ly+compensation)*cdpl/cifpl]], points]; points _ CONS[[Real.Round[(lrx-compensation)*cdpl/cifpl], Real.Round[(ly+compensation)*cdpl/cifpl]], points]; points _ CONS[[Real.Round[(urx-compensation)*cdpl/cifpl], Real.Round[(uy-compensation)*cdpl/cifpl]], points]; points _ CONS[[Real.Round[(ulx+compensation)*cdpl/cifpl], Real.Round[(uy-compensation)*cdpl/cifpl]], points]; [ob, offset] _ CDCurves.CreatePolygon[points, layer]; IncludeOb[ob, [offset], readH]; } ELSE { rect: CD.Object _ CDRects.CreateRect[ size: [Real.Round[(urx-ulx-2*compensation)*cdpl/cifpl], Real.Round[(uy-ly-2*compensation)*cdpl/cifpl]], l: layer]; ib: CD.Position _ CD.InterestBase[rect]; IncludeOb[rect, [[Real.Round[(ulx+compensation)*cdpl/cifpl]-ib.x, Real.Round[(ly+compensation)*cdpl/cifpl]-ib.y]], readH]; } }; readH: ReadCifHandle ~ NARROW[data]; pd: PolygonDescriptor; cdpl, cifpl, compensation: INT; layer: CD.Layer; IF readH.curLayerData=NIL THEN CIFParser.ClientError["undefined layer for polygon"]; compensation _ readH.curLayerData.compensation; layer _ readH.curLayerData.layer; cdpl _ readH.design.technology.lambda*readH.mult; cifpl _ readH.cifPerLambda*readH.div; pd _ PolyCreate[]; FOR l: CIFParser.Path _ p, l.rest WHILE l#NIL DO PolyVertex[polygon: pd, x: l.first.x, y: l.first.y]; ENDLOOP; PolyGenerate[polygon: pd, outputTrapezoid: IncludeTrapezoid]; }; Box: PROC[l, w: CARD, c, d: CIFParser.Point, data: REF ANY] ~ { readH: ReadCifHandle ~ NARROW[data]; cdpl, cifpl, compensation: INT; layer: CD.Layer; IF readH.curLayerData=NIL THEN CIFParser.ClientError["undefined layer for box"]; compensation _ readH.curLayerData.compensation; cdpl _ readH.design.technology.lambda*readH.mult; cifpl _ readH.cifPerLambda*readH.div; layer _ readH.curLayerData.layer; IF (d.x=0 AND d.y#0) OR (d.x#0 AND d.y=0) THEN { xLength: CARD _ IF d.x#0 THEN l ELSE w; yWidth: CARD _ IF d.x#0 THEN w ELSE l; rect: CD.Object _ CDRects.CreateRect[ size: [(xLength-2*compensation)*cdpl/cifpl, (yWidth-2*compensation)*cdpl/cifpl], l: layer]; ib: CD.Position _ CD.InterestBase[rect]; IncludeOb[rect, [[(c.x-xLength/2+compensation)*cdpl/cifpl-ib.x, (c.y-yWidth/2+compensation)*cdpl/cifpl-ib.y]], readH]; } ELSE CIFParser.ClientError["Only Manhatan boxes implemented"]; }; RoundFlash: PROC[d: CARD, c: CIFParser.Point, data: REF ANY] ~ { theta: REAL _ 360.0/numSides; p: CIFParser.Path; FOR i: NAT IN [0..numSides) DO p _ CONS[[Real.Round[d/2.0*RealFns.CosDeg[theta/2 + i*theta] + c.x], Real.Round[d/2.0*RealFns.SinDeg[theta/2 + i*theta] + c.y]], p]; ENDLOOP; Polygon[p, data]; }; Wire: PROC[w: CARD, p: CIFParser.Path, data: REF ANY] ~ { readH: ReadCifHandle ~ NARROW[data]; cdpl, cifpl, compensation: INT; layer: CD.Layer; IF readH.curLayerData=NIL THEN CIFParser.ClientError["undefined layer for wire"]; compensation _ readH.curLayerData.compensation; layer _ readH.curLayerData.layer; cdpl _ readH.design.technology.lambda*readH.mult; cifpl _ readH.cifPerLambda*readH.div; FOR l: CIFParser.Path _ p, l.rest WHILE l.rest#NIL DO IF OnAxis[l.first, l.rest.first] THEN { rect: CD.Object _ CDRects.CreateRect[ size: IF l.first.x=l.rest.first.x THEN [(w-2*compensation)*cdpl/cifpl, (ABS[l.first.y-l.rest.first.y]-2*compensation)*cdpl/cifpl] ELSE [(ABS[l.first.x-l.rest.first.x]-2*compensation)*cdpl/cifpl, (w-2*compensation)*cdpl/cifpl], l: layer]; ib: CD.Position _ CD.InterestBase[rect]; pos: CD.Position _ IF l.first.x=l.rest.first.x THEN [(l.rest.first.x-(w/2) + compensation)*cdpl/cifpl, ((IF l.first.y < l.rest.first.y THEN l.first.y ELSE l.rest.first.y) + compensation)*cdpl/cifpl] ELSE [((IF l.first.x < l.rest.first.x THEN l.first.x ELSE l.rest.first.x) + compensation)*cdpl/cifpl, (l.rest.first.y - (w/2) + compensation)*cdpl/cifpl]; IncludeOb[rect, [[pos.x-ib.x, pos.y-ib.y]], readH]; } ELSE { RealPoint: TYPE = RECORD[x, y: REAL]; vector, unitVector: RealPoint; h0, h90, h180, h270: RealPoint; length: REAL; p: CIFParser.Path; vector _ [l.rest.first.x-l.first.x, l.rest.first.y-l.first.y]; length _ RealFns.SqRt[vector.x*vector.x + vector.y*vector.y]; unitVector _ [vector.x/length, vector.y/length]; h0 _ [unitVector.x*w/2, unitVector.y*w/2]; h90 _ [-h0.y, h0.x]; h180 _ [-h90.y, h90.x]; h270 _ [-h180.y, h180.x]; p _ CONS[[Real.Round[l.first.x+h270.x], Real.Round[l.first.y+h270.y]], p]; p _ CONS[[Real.Round[l.rest.first.x+h270.x], Real.Round[l.rest.first.y+h270.y]], p]; p _ CONS[[Real.Round[l.rest.first.x+h90.x], Real.Round[l.rest.first.y+h90.y]], p]; p _ CONS[[Real.Round[l.first.x+h90.x], Real.Round[l.first.y+h90.y]], p]; Polygon[p, readH]; }; ENDLOOP; { -- fix up the endpoints with flashes or boxes prevSegOnAxis: BOOLEAN _ TRUE; nextSegOnAxis: BOOLEAN _ FALSE; FOR l: CIFParser.Path _ p, l.rest WHILE l.rest#NIL DO nextSegOnAxis _ OnAxis[l.first, l.rest.first]; IF prevSegOnAxis AND nextSegOnAxis THEN Box[w, w, l.first, [1, 0], data] ELSE RoundFlash[w, l.first, data]; prevSegOnAxis _ nextSegOnAxis; REPEAT FINISHED => IF prevSegOnAxis THEN Box[w, w, l.first, [1, 0], data] ELSE RoundFlash[w, l.first, data] ENDLOOP; }; }; Layer: PROC[n: Rope.ROPE, data: REF ANY] ~ { readH: ReadCifHandle ~ NARROW[data]; readH.curLayerData _ GetLayerData[readH.layerTable, n]; }; Call: PROC[s: CARD, t: CIFParser.Transformation, data: REF ANY] ~ { readH: ReadCifHandle ~ NARROW[data]; obj: CifObject; transf: CD.Transformation; cdpl: INT _ readH.design.technology.lambda*readH.mult; cifpl: INT _ readH.cifPerLambda*readH.div; m: CIFParser.TMatrix _ CIFParser.TransfToMatrix[t]; IF ~CIFParser.IsOrthogonalTransform[m] THEN CIFParser.ClientError["Cell called with non-orthogonal cell placement"]; transf _ CIFtoCDPosition[m, cdpl, cifpl]; obj _ NARROW[IntHashTable.Fetch[readH.symbolTable, s].value]; IF obj=NIL THEN { obj _ NewCifObject[s, readH]; readH.curObj.undefSymb _ CONS[s, readH.curObj.undefSymb]; IF verbose THEN TerminalIO.PutF[" Symbol %d called in definition of %d before being defined\n", IO.int[s], IO.int[readH.symNo]]; }; IF readH.curObj = NIL THEN IncludeAll[obj, readH]; IncludeOb[obj.ob, transf, readH]; }; UserExtension: PROC[u: CARD, t: Rope.ROPE, data: REF ANY] ~ { ENABLE IO.Error, IO.EndOfStream, RuntimeError.BoundsFault => GOTO Abort; --punt if we don't understand the syntax readH: ReadCifHandle ~ NARROW[data]; lastCharIndex: NAT _ Rope.Length[t]-1; UNTIL Rope.Fetch[t, lastCharIndex]#' DO --skip trailing blanks lastCharIndex _ lastCharIndex-1; ENDLOOP; SELECT TRUE FROM u=9 AND NOT Rope.Fetch[t, 0]='4 => IF readH.curObj.name = NIL THEN readH.curObj.name _ Rope.Substr[t, 1, lastCharIndex]; u=9 AND Rope.Fetch[t, 0]='4 => { MyTokenProc: IO.BreakProc = { RETURN [SELECT char FROM IN [IO.NUL .. IO.SP] => sepr, ',, ':, '; => sepr, ENDCASE => other]; }; ris: IO.STREAM _ IO.RIS[t]; junk: Rope.ROPE _ IO.GetTokenRope[ris, MyTokenProc].token; name: Rope.ROPE _ IO.GetTokenRope[ris, MyTokenProc].token; xPos: INT _ Convert.IntFromRope[IO.GetTokenRope[ris, MyTokenProc].token]; yPos: INT _ Convert.IntFromRope[IO.GetTokenRope[ris, MyTokenProc].token]; layer: CD.Layer _ GetLayerData[readH.layerTable, IO.GetTokenRope[ris, MyTokenProc].token].layer; cdpl, cifpl: INT; cdpl _ readH.design.technology.lambda*readH.mult; cifpl _ readH.cifPerLambda*readH.div; xPos _ xPos*cdpl/cifpl; yPos _ yPos*cdpl/cifpl; [] _ CDCells.IncludeInstance[ design: readH.design, cell: readH.curObj.ob, inst: CDSymbolicObjects.CreateSymInst[ name: name, denotes: [xPos, yPos, xPos, yPos], layer: layer ], mode: dontResize ] }; ENDCASE => TerminalIO.PutF["Unknown User Cmd #%d, content:%g\n", IO.card[u], IO.rope[t]]; EXITS Abort => TerminalIO.PutF["Can't parse User Cmd #%d, content:%g\n", IO.card[u], IO.rope[t]]; }; Comment: PROC[c: Rope.ROPE, data: REF ANY] ~ { readH: ReadCifHandle ~ NARROW[data]; IF readH.commented THEN TerminalIO.PutRopes["CIF comment: ", c, "\n"]; }; ReadFile: PUBLIC PROC [cifFile: IO.STREAM, design: CD.Design, regKey: ATOM, basicTransf: CD.Transformation _ [], cifPerLambda: INT _ 100, commented: BOOLEAN _ FALSE] RETURNS [errMsg: Rope.ROPE] ~ { readH: ReadCifHandle _ NEW[ReadCifHandleRec _ [ design: design, basicTransf: basicTransf, layerTable: GetLayerTable[regKey], cifPerLambda: cifPerLambda, symbolTable: IntHashTable.Create[], commented: commented ]]; readReg: CIFParser.Registration _ NEW[CIFParser.RegistrationRec _ [ defDelete: DefDelete, defStart: DefStart, defFinish: DefFinish, polygon: Polygon, box: Box, roundFlash: RoundFlash, wire: Wire, layer: Layer, call: Call, userExtension: UserExtension, comment: Comment, data: readH ]]; CIFParser.Parse[cifFile, readReg ! CIFParser.Error => { errMsg _ IO.PutFR["%g @ %d\n", IO.rope[msg], IO.int[IO.GetIndex[cifFile]]]; GOTO Exit; }]; EXITS Exit => {}; }; END. ,CifToCDImpl.mesa Copyright Σ 1987 by Xerox Corporation. All rights reserved. Ch. LeCocq, September 14, 1987 Christian Le Cocq July 13, 1988 4:30:04 pm PDT Last Edited by: Gasbarro May 4, 1988 10:19:24 am PDT Converts Cif format data into ChipNDale cells. Previous code has been very helpful. It has been written by : Frank Bowers, Jim Gasbarro, Christian Jacobi, Ed McCreight, Martin Newell, Bertrand Serlet, and probably others who didn't put their name on top of the file in the begining of the ages. external types internal types global variables Polygons Create new polygon Add vertex to polygon Generate the polygon defined up to last PolyVertex Layer Tables Misc... CIF commands interpretation IntHashTable.EachPairAction IF ~curCell.warningInSubCell THEN TerminalIO.PutRope["Non-rectilinear geometry", Warning]; readH: ReadCifHandle ~ NARROW[data]; -- cell name syntax: 9 RamCell; -- signal name syntax: 94 Vdd 268 -8 CM1; -- accepts +, -, and _ as other '[, '], '(, '), '{, '}, '", '*, '/, '@ => break, -- they could be part of a name: {[43][5]} Κj˜codešœ™Kšœ<™K˜K˜—š   œœœœœ˜@Kšœœ™$Kšœœ˜J˜šœœœ˜Kšœœ}˜…Kšœ˜—Kšœ˜K˜K˜—š  œœœœœ˜9Kšœœ˜$Kšœœ˜Kšœœ˜Kšœœœ3˜QKšœ/˜/Kšœ!˜!Kšœ1˜1Kšœ%˜%šœœœ˜5šœœ˜'šœœ˜%šœœœ"œ7˜‚KšœœV˜`—Kšœ ˜ —Kšœœ œ˜(š œœ œœ6œœ œ,˜ΖKšœœœ œa˜š—Kšœ3˜3K˜—šœ˜Kšœ œœœ˜%Kšœ˜Kšœ˜Kšœœ˜ K˜K˜>K˜=K˜0K˜*K˜K˜K˜KšœœB˜JKšœœL˜TKšœœJ˜RKšœœ@˜HK˜K˜—Kšœ˜—šœŸ-˜/Kšœœœ˜Kšœœœ˜šœœœ˜5K˜.Kšœœœ!˜HKšœ˜"K˜Kš˜šœœœ!˜BKšœ˜!—Kšœ˜—K˜—K˜K˜—š  œœ œœœ˜,Kšœœ˜$Kšœ7˜7K˜K˜—š  œœœ%œœ˜CKšœœ˜$Kšœ˜Kšœœ˜Kšœœ-˜6Kšœœ ˜*Kšœ3˜3Kšœ%œI˜tKšœ)˜)Kšœœ1˜=šœœœ˜Kšœ˜Kšœœ˜9Kšœ œQœ œ˜€K˜—Kšœœœ˜2Kšœ!˜!K˜K˜—š   œœœ œœœ˜=Kš œœœ*œ Ÿ(˜rK˜Kšœœ˜$Kšœœ˜&šœ!œŸ˜?Kšœ ˜ Kšœ˜—šœœ˜šœœœ˜"KšœŸ œ™ Kšœœœ6˜U—K™šœœ˜ KšœŸ œ™*š  œœ˜Kšœ™šœœ˜K™[Kš œœœœœ ˜Kšœ˜Kšœ ˜—K˜K˜—Kš œœœœœ˜Kšœ œœ&˜:Kšœ œœ&˜:Kšœœœ'˜IKšœœœ'˜IKšœœ(œ-˜`Kšœ œ˜Kšœ1˜1Kšœ%˜%K˜Kšœ˜Kšœ˜K˜šœ˜Kšœ˜Kšœ œ ˜šœ&˜&Kšœ ˜ Kšœ"˜"Kšœ ˜ Kšœ˜—Kšœ˜Kšœ˜—Kšœ˜—Kšœ:œ œ ˜Y—š˜šœ ˜ Kšœ:œ œ ˜R——K˜K˜—š  œœ œœœ˜.Kšœœ˜$Jšœœ œ.˜FK˜K˜—š œœœ œœ œœœ$œœœœœ˜Εšœœ˜/K˜Kšœ˜Kšœ"˜"Kšœ˜Kšœ#˜#K˜K˜—šœ"œ˜CKšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜—šœ7˜7Kš œ œœ œœ˜KKšœ˜ K˜—Kšœ ˜K˜K™——K˜Kšœ˜—…—<&RΌ