DIRECTORY CD, CDCommandOps, CDDirectory, CDInstances, CDLayers, CDOps, CDPanelFonts, CDProperties, CDRects, CDSatellites, CDSequencer, CDTexts, CDViewer, Core, CoreCreate, CoreOps, CoreProperties, PopUpMenus, IO, PW, REFBit, Rope, Sisyph, TerminalIO, ViewerClasses, ViewerOps, WireIconExtras; WireIconExtrasImpl: CEDAR PROGRAM IMPORTS CD, CDCommandOps, CDDirectory, CDInstances, CDLayers, CDOps, CDPanelFonts, CDProperties, CDRects, CDSatellites, CDTexts, CDViewer, CoreCreate, CoreProperties, CoreOps, IO, PW, REFBit, Rope, Sisyph, TerminalIO, ViewerOps EXPORTS WireIconExtras = BEGIN ROPE: TYPE = Rope.ROPE; Wire: TYPE = Core.Wire; RecWire: PUBLIC PROC[rec: ROPE, dual: BOOL _ FALSE] RETURNS[wire: Wire] = {RETURN[RefWire[REFBit.NEWFromName[rec], rec.Substr[rec.Index[0,"."]+1]]]}; RefWire: PUBLIC PROC[ref: REF, name: ROPE, dual: BOOL _ FALSE] RETURNS[wire: Wire] = { ZeroIfOne: PROC[s: INT] RETURNS[INT] = {RETURN[IF s=1 THEN 0 ELSE s]}; fieldForm: REFBit.Format _ REFBit.Desc[ref].fieldForm; wires: LIST OF Wire _ NIL; temp: LIST OF Wire _ NIL; FOR field: INT IN[0..fieldForm.size) DO fieldName: ROPE _ BitRopeToSigRope[fieldForm[field].name]; SELECT fieldForm[field].bitSize FROM 1 => {wires _ CONS[CoreCreate.Seq[fieldName, IF dual THEN 2 ELSE 0], wires]}; >1 => { fieldWire: Wire _ CoreOps.CreateWires[fieldForm[field].bitSize, fieldName]; wires _ CONS[fieldWire, wires]; FOR bit: INT IN[0..fieldWire.size) DO fieldWire[bit] _ CoreCreate.Seq[NIL, IF dual THEN 2 ELSE 0] ENDLOOP}; ENDCASE => ERROR; ENDLOOP; temp _ wires; wires _ NIL; FOR temp _ temp, temp.rest WHILE temp#NIL DO wires _ CONS[temp.first, wires] ENDLOOP; wire _ CoreOps.CreateWire[wires, name]}; ETWire: PUBLIC PROC[prefix, suffix, type: ROPE] RETURNS[wire: Wire] = { bitName, bitNameInv: ROPE; refREF: REF _ REFBit.NEWFromName[type]; format: REFBit.Format _ REFBit.Desc[refREF].bitForm; wire _ CoreOps.CreateWires[MAX[2, format.size], prefix.Cat[suffix]]; FOR i: INT IN[0..format.size) DO bitName _ BitRopeToSigRope[format[i].name]; bitNameInv _ BitRopeToSigRope[format[i].nameInv]; IF ((format.size#1) = (i+1=format.size)) = (bitName#NIL) THEN ERROR; IF ((format.size#1) = (bitNameInv#NIL)) = (bitName#NIL) THEN ERROR; IF bitName=NIL THEN bitName _ bitNameInv; wire[i] _ CoreOps.CreateWires[0, prefix.Cat[bitName, suffix]]; IF format.size=1 THEN wire[1] _ CoreOps.CreateWires[0, prefix.Cat[bitNameInv, suffix]]; ENDLOOP}; BitRopeToSigRope: PROC [name: ROPE] RETURNS [ROPE] ~ { Cap: PROC[rope: ROPE, idx: INT] RETURNS[ROPE] = { char: CHAR _ rope.Fetch[idx+1]; IF char IN ['a..'z] THEN char _ char + LOOPHOLE['A - 'a]; RETURN[IO.PutFR["%g", IO.char[char]]]}; IF name = NIL THEN RETURN[NIL]; name _ Rope.Cat[Cap[name, -1], name.Substr[1]]; DO -- remove peiods and Capitalize next letters until end or next char is number index: INT _ name.Index[0, "."]; IF index+1 >= name.Length[] OR name.Fetch[index+1] IN ['0..'9] THEN RETURN[name]; name _ Rope.Cat[name.Substr[0,index], Cap[name, index], name.Substr[index+2]]; ENDLOOP }; ConstructRecWireIconCommand: PROC [comm: CDSequencer.Command] ~ { type: ROPE _ TerminalIO.RequestRope["Type (eg. Def.Record): "]; wire: Core.Wire _ RecWire[type]; name: ROPE _ type.Substr[type.Index[0,"."]+1]; icon: CD.Object _ ConstructWireIcon[comm, wire, name.Cat[".icon"]]; CDProperties.PutObjectProp[icon, $CodeFor, Rope.Cat["WireIconExtras.RecWire[\"", type, "\"]" ]]; CDProperties.PutObjectProp[icon, Sisyph.mode.extractProcProp, $SisyphExtractNamedWireIcon]}; ConstructDETWireIconCommand: PROC [comm: CDSequencer.Command] ~ { type: ROPE _ TerminalIO.RequestRope["Type (eg. Def.Enumerated): "]; pre: ROPE _ TerminalIO.RequestRope["Prefix:"]; suf: ROPE _ TerminalIO.RequestRope["Suffix:"]; wire: Core.Wire _ ETWire[pre, suf, type]; icon: CD.Object _ ConstructWireIcon[comm, wire, Rope.Cat[pre, suf, ".icon"]]; CDProperties.PutObjectProp [icon, $CodeFor, IO.PutFR["WireIconExtras.ETWire[\"%g\", \"%g\", \"%g\"]", IO.rope[pre], IO.rope[suf], IO.rope[type] ]]; CDProperties.PutObjectProp[icon, Sisyph.mode.extractProcProp, $SisyphExtractNamedWireIcon]}; ConstructWireIcon: PROC [comm: CDSequencer.Command, wire: Core.Wire, name: ROPE] RETURNS[icon: CD.Object] ~ { font: CDTexts.CDFont _ CDPanelFonts.CurrentFont[comm.design]; w: INT _ CDLayers.LayerWidth[comm.design, CD.commentLayer]; fw2: INT _ font.height/2 - w - font.origin.y; grid: CD.Number _ Grid[comm.design, font]; insts: CD.InstanceList _ NIL; pinObject: CD.Object _ CDRects.CreateRect[size: [grid/2, w], l: CD.commentLayer]; text: CD.Object; sat: CD.Instance; pin: CD.Instance; maxX: INT _ 0; FOR i: INT IN [0..wire.size) DO text _ CDTexts.Create[CoreOps.GetShortWireName[wire[i]], font]; maxX _ MAX[ maxX, CD.InterestSize[text].x]; sat _ CDInstances.NewInst[text, [[x: grid, y: grid*(i+2)-fw2 ]]]; pin _ CDInstances.NewInst[pinObject, [[x: 0, y: grid*(i+2) ]]]; insts _ CONS[sat, CONS[pin, insts]]; CDSatellites.Associate[master: pin, text: sat] ENDLOOP; text _ CDTexts.Create[CoreOps.GetShortWireName[wire], font]; maxX _ ((MAX[ maxX, CD.InterestSize[text].x] + 3*grid-1)/grid)*grid; sat _ CDInstances.NewInst[text, [[x: maxX-grid-CD.InterestSize[text].x, y: grid-fw2 ]]]; pin _ CDInstances.NewInst[pinObject, [[x: maxX-grid/2, y: grid ]]]; insts _ CONS[sat, CONS[pin, insts]]; CDSatellites.Associate[master: pin, text: sat]; icon _ PW.CreateCell[instances: insts, ir: [0, 0, maxX, grid*(wire.size+2)+w]]; IF NOT CDDirectory.Include[comm.design, icon, name] THEN {TerminalIO.PutF["*** Directory insertion of %g failed.\n", IO.rope[name]]; ERROR}; []_CDOps.IncludeObjectI[comm.design, icon, comm.pos]}; Grid: PROC[design: CD.Design, font: CDTexts.CDFont _ NIL] RETURNS[grid: NAT] = { viewers: CDViewer.ViewerList _ CDViewer.ViewersOf[design]; IF viewers#NIL THEN WITH ViewerOps.GetViewer[viewers.first, $Grid] SELECT FROM rgrid: REF CD.Number => grid _ rgrid^; ENDCASE => NULL ELSE grid _ design.technology.lambda*2; IF font#NIL THEN WHILE font.height > (grid*4)/3 DO grid _ grid*2 ENDLOOP}; mark: ATOM _ CoreProperties.RegisterProperty[$TemporaryMark]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Create Wire Icon from Cedar Record Type", doc: "RECORDs with field types such as: RECORD, INT, BOOL, enumerated, subranges", key: $ConstructRecWireIconCommand, proc: ConstructRecWireIconCommand ]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Create Wire Icon from Cedar Enumerated Type", doc: "Decoded Enumerated types encoded as: 0, 3, 5, 9, 17 etc.", key: $ConstructDETWireIconCommand, proc: ConstructDETWireIconCommand ]; END. +„WireIconExtrasImpl.mesa Don Curry May 14, 1987 4:33:34 pm PDT Last Edited by: Don Curry September 15, 1987 1:58:56 pm PDT Wire From Cedar Types Icon From Cedar Types CDCells.SetSimplificationTreshhold[cell: icon, val: 30, inPixels: TRUE]; Icon From Schematic Procs -- Old ConstructIconCommand: PROC [comm: CDSequencer.Command] ~ { schFullName: ROPE; iconName: ROPE; icon: CD.Object; cell: Core.CellType; selected: CD.Instance; multiple: BOOL; cellRef: REF; sort: BOOL; [selected, multiple] _ CDOps.SelectedInstance[comm.design]; IF ~IsSingleSelectedAndCell[selected, multiple] THEN RETURN; schFullName _ CDDirectory.Name[selected.ob, comm.design]; IF schFullName=NIL THEN {TerminalIO.PutF["*** Selected schematic has no name.\n"]; RETURN}; IF NOT Rope.Match["*.sch", schFullName] THEN TerminalIO.PutF["*** Convention for schematics is to suffix them with '.sch'.\n"]; cellRef _ SinixOps.ExtractCDInstance[selected, comm.design, Sisyph.mode].result; IF ISTYPE [cellRef, Core.CellType] THEN cell _ NARROW [cellRef] ELSE {TerminalIO.PutF["*** Selected cell does not extract to Core CellType\n"]; RETURN}; iconName _ TerminalIO.RequestRope["Type icon short name: "]; IF Rope.IsEmpty[iconName] THEN iconName _ IF Rope.Match["*.sch", schFullName] THEN Rope.Substr[schFullName, 0, Rope.Length[schFullName]-4] ELSE schFullName; IF Rope.IsEmpty[schFullName] THEN {TerminalIO.PutF["No name provided, no default from schematic.\n"]; RETURN}; IF CDDirectory.Fetch[comm.design, Rope.Cat[iconName, ".icon"]]#NIL THEN { TerminalIO.PutF["*** The icon %g.icon already exists!\n", IO.rope[iconName]]; RETURN}; sort _ SELECT comm.key FROM $ConstructIconCommand => FALSE, $ConstructIconCommandSort => TRUE, ENDCASE => ERROR; icon _ IconFromSchematic[cell, schFullName, iconName, comm.design, sort]; IF icon=NIL THEN RETURN; CDCells.SetSimplificationTreshhold[cell: icon, val: 30, inPixels: TRUE]; []_CDOps.IncludeObjectI[comm.design, icon, comm.pos]}; IconFromSchematic: PROC[ schCT: Core.CellType, schFullName: ROPE, iconName: ROPE, design: CD.Design, sort: BOOL ] RETURNS [iconObj: CD.Object] ~ { L16: PROC[in: INT] RETURNS[INT] = {XX: INT _ design.technology.lambda*16; RETURN[((in+XX-1)/XX)*XX]}; font: CDTexts.CDFont _ CDPanelFonts.CurrentFont[design]; grid: CD.Number _ Grid[design, font]; insts: CD.InstanceList _ NIL; schDeco: CoreGeometry.Decoration _ Sisyph.mode.decoration; schSize: CD.Position _ CD.InterestSize[CoreGeometry.GetObject[schDeco, schCT]]; iconSize: CD.Position; hChans: INT; vChans: INT; iNmOb: CD.Object _ CDTexts.Create[iconName, font]; pins: ARRAY CoreGeometry.Side OF CD.InstanceList _ ALL[NIL]; cnt: ARRAY CoreGeometry.Side OF NAT _ ALL[0]; smax: ARRAY CoreGeometry.Side OF INT _ ALL[16]; w: INT _ CDLayers.LayerWidth[design, CD.commentLayer]; fw2: INT _ font.height/2 - w - font.origin.y; iconFullName: ROPE _ iconName.Cat[".icon"]; pinObject: CD.Object; horWall: CD.Object; verWall: CD.Object; clearMark: CoreOps.EachWireProc = {CoreProperties.PutWireProp[wire, mark, NIL]}; FOR side: CoreGeometry.Side IN CoreGeometry.Side DO eachSortedPin: CoreGeometry.EachSortedPinProc = { IF CoreProperties.GetWireProp[wire, mark]=NIL THEN { text: CD.Object _ CDTexts.Create[CoreOps.GetShortWireName[wire], font]; inst: CD.Instance _ CDInstances.NewInst[text]; CoreProperties.PutWireProp[wire, mark, mark]; pins[side] _ CONS[inst, pins[side]]; cnt[side] _ cnt[side] + 1; smax[side] _ MAX[ smax[side], CD.InterestSize[text].x] }}; [] _ CoreGeometry.EnumerateSortedSides[schDeco, schCT, side, eachSortedPin]; []_CoreOps.VisitWire[schCT.public, clearMark]; ENDLOOP; IF sort THEN FOR side: CoreGeometry.Side IN CoreGeometry.Side DO DO ok: BOOL _ TRUE; FOR insts: CD.InstanceList _ pins[side], insts.rest WHILE insts#NIL AND insts.rest#NIL DO TwoObj: TYPE = RECORD[ob1, ob2: CD.Object]; r1: ROPE _ NARROW[insts.first.ob.specific, CDTexts.TextSpecific].text; r2: ROPE _ NARROW[insts.rest.first.ob.specific, CDTexts.TextSpecific].text; SELECT Rope.Compare[r1, r2] FROM less => LOOP; equal => ERROR; ENDCASE; [insts.first.ob, insts.rest.first.ob] _ TwoObj[insts.rest.first.ob, insts.first.ob]; ok_FALSE; ENDLOOP; IF ok THEN EXIT; ENDLOOP; ENDLOOP; hChans _ MAX[cnt[left], cnt[right]]; vChans _ MAX[cnt[top], cnt[bottom]]; iconSize.x_ L16[(vChans+4)*grid + 2*MAX[smax[left], smax[right],CD.InterestSize[iNmOb].x]]; iconSize.y_ L16[(hChans+4)*grid + 2*MAX[smax[top], smax[bottom]]]; IF schSize.x > schSize.y THEN iconSize.x _ L16[MAX[iconSize.x, (iconSize.y*schSize.x + schSize.y/2) /schSize.y]] ELSE iconSize.y _ L16[MAX[iconSize.y, (iconSize.x*schSize.y + schSize.x/2) /schSize.x]]; pinObject _ CDRects.CreateRect[size: [grid/2, w], l: CD.commentLayer]; horWall _ CDRects.CreateRect[size: [iconSize.x, w], l: CD.commentLayer]; verWall _ CDRects.CreateRect[size: [w, iconSize.y], l: CD.commentLayer]; FOR side: CoreGeometry.Side DECREASING IN CoreGeometry.Side DO tr: CD.Transformation _ SELECT side FROM top => [ [iconSize.x/2 - vChans*grid/2, iconSize.y], rotate270 ], bottom => [ [iconSize.x/2 - vChans*grid/2, 0], rotate90 ], left => [ [0, iconSize.y/2 - hChans*grid/2], original], right => [ [iconSize.x, iconSize.y/2 - hChans*grid/2], rotate180], ENDCASE => ERROR; index: INT _ (cnt[side]+(SELECT side FROM top,bottom=>vChans, ENDCASE => hChans)+1)/2; FOR temp: CD.InstanceList _ pins[side], temp.rest WHILE temp#NIL DO pin, sat: CD.Instance; index _ index-1; insts _ CONS[(sat _ temp.first), insts]; insts _ CONS[(pin _ CDInstances.NewInst[pinObject]), insts]; sat.trans.orient _ pin.trans.orient _ tr.orient; CDSatellites.Associate[master: pin, text: sat]; SELECT side FROM top => { pin.trans.off _ CDBasics.AddPoints[tr.off, [index*grid+0, 0 ]]; sat.trans.off _ CDBasics.AddPoints[tr.off, [index*grid+0-fw2, -grid ]]}; bottom => { pin.trans.off _ CDBasics.AddPoints[tr.off, [index*grid+w, 0 ]]; sat.trans.off _ CDBasics.AddPoints[tr.off, [index*grid+w+fw2, +grid ]]}; left => { pin.trans.off _ CDBasics.AddPoints[tr.off, [0, index*grid+0 ]]; sat.trans.off _ CDBasics.AddPoints[tr.off, [+grid, index*grid+0-fw2 ]]}; right => { pin.trans.off _ CDBasics.AddPoints[tr.off, [0, index*grid+w ]]; sat.trans.off _ CDBasics.AddPoints[tr.off, [-grid, index*grid+w+fw2 ]]}; ENDCASE => ERROR; ENDLOOP; ENDLOOP; insts _ CONS[CDInstances.NewInst[horWall, [off:[0, 0 ]]], insts]; CDProperties.PutInstanceProp[insts.first, Sisyph.mode.extractProcProp, $ExtractNull]; insts _ CONS[CDInstances.NewInst[horWall, [off:[0, iconSize.y-w ]]], insts]; CDProperties.PutInstanceProp[insts.first, Sisyph.mode.extractProcProp, $ExtractNull]; insts _ CONS[CDInstances.NewInst[verWall, [off:[0, 0 ]]], insts]; CDProperties.PutInstanceProp[insts.first, Sisyph.mode.extractProcProp, $ExtractNull]; insts _ CONS[CDInstances.NewInst[verWall, [off:[iconSize.x-w, 0 ]]], insts]; CDProperties.PutInstanceProp[insts.first, Sisyph.mode.extractProcProp, $ExtractNull]; insts _ CONS[CDInstances.NewInst[iNmOb, [off:[grid, iconSize.y-2*grid ]]], insts]; iconObj _ PW.CreateCell[instances: insts]; IF NOT CDDirectory.Include[design, iconObj, iconFullName] THEN {TerminalIO.PutF["*** Directory insertion of %g failed.\n", IO.rope[iconFullName]]; ERROR}; CDProperties.PutObjectProp[iconObj, Sisyph.mode.extractProcProp, $SisyphExtractCellIcon]; CDProperties.PutObjectProp[iconObj, $IconFor, schFullName]}; LayoutStructureAndDrcCheckOfSelectedIcons: PROC [comm: CDSequencer.Command] = { count: INT _ 0; drcErrors: INT _ 0; errs: INT _ 0; result: REF; badguys: LIST OF ROPE; objName: ROPE; errorMsg: ROPE; errorType: ATOM; sourceCT: Core.CellType; indirectOb: CD.Object; directOb: CD.Object; directCT: Core.CellType; drcAtomDesign: ATOM _ DesignRules.FetchRulesID[comm.design]; drcAtom: ATOM _ IF drcAtomDesign#NIL THEN drcAtomDesign ELSE $VTI; rules: DesignRules.Rules _ DesignRules.GetRuleSet[drcAtom]; tech: Drc.Tech _ DrcCMOSB.NewTechnology[DrcCMOSB.cMosBcompleteKey, rules]; IF comm.design.actual.rest#NIL THEN {TerminalIO.PutF["Can't handle pushed in cell\n"]; RETURN}; TerminalIO.PutF["Using %g design rules\n", IO.atom[drcAtom]]; FOR w: CD.InstanceList _ CDOps.InstList[comm.design], w.rest WHILE w#NIL DO IF NOT w.first.selected THEN LOOP; objName _ CDDirectory.Name[w.first.ob, comm.design]; IF Rope.Find[objName, ".icon"]=-1 THEN {TerminalIO.PutF["%g is not an icon.\n", IO.rope[objName]]; LOOP}; result _ SinixOps.ExtractCDInstance[w.first, comm.design, Sisyph.mode].result; IF result=NIL OR NOT ISTYPE[result, Core.CellType] THEN {TerminalIO.PutF["%g does not extract as a cell.\n", IO.rope[objName]]; LOOP}; sourceCT _ NARROW[result]; errorType _ NIL; indirectOb _ PWCore.Layout[sourceCT ! PWCore.Error => {errorType _ type; errorMsg _ message; CONTINUE}]; IF errorType#NIL THEN { TerminalIO.PutF["Cell for %g has Layout %g ERROR\n %g.\n", IO.rope[objName], IO.atom[errorType], IO.rope[errorMsg]]; LOOP}; PWCoreLichen.Compare[sourceCT]; TerminalIO.PutF["Done extracting and comparing.\n"]; directOb _ CDDirectory.Expand1[indirectOb].new; IF directOb=NIL THEN ERROR; directCT _ NARROW[Sinix.Extract[directOb, PWCore.extractMode].result]; IF directCT=NIL THEN ERROR; errs _ Drc.CheckDesignRules[directCT, CoreOps.CopyWire[directCT.public], tech, TRUE, NIL, PWCore.extractMode.decoration]; TerminalIO.PutF[" %2g errors in %g.\n", IO.int[errs], IO.rope[CoreOps.GetCellTypeName[directCT]]]; IF errs#0 THEN { []_CDDebug.Draw[directOb, comm.design.technology, objName]; badguys _ CONS[objName, badguys]}; drcErrors _ drcErrors+errs; count _ count+1; ENDLOOP; TerminalIO.PutF["%2g drc errors in %g cells.\n", IO.int[drcErrors], IO.int[count]]; FOR badguys _ badguys, badguys.rest WHILE badguys#NIL DO TerminalIO.PutF[" %g\n", IO.rope[badguys.first]]; ENDLOOP}; IsSingleSelected: PROC [selected: CD.Instance, multiple: BOOL] RETURNS [BOOL] = { IF selected=NIL THEN {TerminalIO.PutF["*** No current selection--can't do it.\n"]; RETURN[FALSE]}; IF multiple THEN {TerminalIO.PutF["*** Multiple instances selected--can't do it.\n"]; RETURN[FALSE]}; RETURN[TRUE]}; IsSingleSelectedAndCell: PROC [selected: CD.Instance, multiple: BOOL] RETURNS [BOOL] = { IF ~IsSingleSelected[selected, multiple] THEN RETURN [FALSE]; IF ~CDCells.IsCell[selected.ob] THEN {TerminalIO.PutF["*** Selected instance is not a cellcan't do it.\n"]; RETURN[FALSE]}; RETURN[TRUE]}; CDCommandOps.RegisterWithMenu[ menu: $OtherProgramMenu, entry: "Library Layout Check", doc: "Lichen structure check and design rule check of the layouts of all selected icons", key: $LayoutStructureAndDrcCheckOfSelectedIcons, proc: LayoutStructureAndDrcCheckOfSelectedIcons]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Create Cell Icon from schematics - Grid 2", doc: "Pins on grid 2. Overall size in units of 16.", key: $ConstructIconCommand, proc: ConstructIconCommand ]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Create Cell Icon from schematics - Grid 2 - Sorted", doc: "Pins on grid 2. Overall size in units of 16. Names sorted.", key: $ConstructIconCommandSort, proc: ConstructIconCommand ]; Initialization Κͺ˜šœ™Jšœ"Οk™%Jšœ;™;—J˜Jš œœΕœœM˜€J˜šΟnœœ˜!Jšœœ¦œœ-˜γJšœ˜—J˜Jšœœœ˜Jšœœ ˜headšΟb™šžœœœœœœœ˜IJšœœD˜KJ˜—šžœœœœœœœœ˜VJšž œœœœœœœœœ˜FJšœ6˜6Jšœ œœœ˜Jšœœœœ˜šœœœ˜'Jšœ œ+˜:šœ˜$šœ˜Jš œ œœœœ ˜H—šœ ˜ JšœK˜KJšœœ˜šœœœ˜%Jš œ œœœœœ˜F——Jšœœ˜—Jšœ˜—Jšœœ˜Jš œœœœ œœ˜UJšœ(˜(J™—š žœœœœœ˜GJšœœ˜Jšœœ˜'Jšœ4˜4Jšœœ&˜Dšœœœ˜ Jšœ,˜,Jšœ1˜1Jšœ2œœœ˜DJš œ œœœœ˜CJšœ œœ˜)Jšœ>˜>šœ˜JšœA˜A—Jšœ˜ —J˜—š žœœœœœ˜6š žœœœœœœ˜1Jšœœ˜Jšœœ œœ ˜9Jšœœ œ˜'—Jš œœœœœ˜Jšœ/˜/šœΟcM˜PJšœœ˜ Jš œœœ œœ˜QJšœN˜NJšœ˜ ———šŸ™šžœœ ˜AJšœœ6˜@Jšœ ˜ Jšœœ%˜/Jšœœ;˜CJšœ`˜`Jšœ\˜\J˜—šžœœ ˜AJšœœ:˜DJšœœ&˜/Jšœœ&˜/Jšœ)˜)JšœœE˜Mšœ˜šœœ7˜JJšœ œ œ˜-——Jšœ\˜\J˜—šžœœ4œ˜PJšœœ ˜Jšœ?˜?Jšœœ$œ˜>Jšœœ%˜/Jšœœ"˜,Jšœ œœ˜Jšœ œ4œ˜RJšœœ˜Jšœœ ˜Jšœœ ˜Jšœœ˜šœœœ˜Jšœ?˜?Jšœœœ˜+JšœC˜CJšœB˜BJšœœœ˜$Jšœ/œ˜7—Jšœ<˜Jš œœœœœ™2Jš œœœœœ™5Jšœœœ™9Jšœœ%™/Jšœœ™+Jšœ œ™Jšœ œ™Jšœ œ™JšœKœ™Qšœœ™3šœ1™1šœ(œœ™4Jšœœ@™HJšœœ&™.Jšœ-™-Jšœœ™%Jšœ™Jšœœœ™<——JšœL™LJšœ.™.Jšœ™—š œœœœœ™CJšœœœ™š œœ'œœœ œ™YJšœœœ œ ™+Jšœœœ6™GJšœœœ:™Kšœ™ Jšœ œ™Jšœ œœ™—JšœT™TJšœœ™ Jšœ™—Jš œœœœœ™"—Jšœ œ™%Jšœ œ™%Jšœ œœœ™[Jšœ œœ™Bšœ™Jšœœœ>™WJšœœœ@™Y—Jšœ5œ™FJšœ7œ™HJšœ7œ™Hšœ œœ™>šœœœ™(JšœC™CJšœ=™=Jšœ;™;JšœC™CJšœœ™—Jš œœœœœ™Vš œœ&œœ™CJšœ œ ™Jšœ™Jšœœ™(Jšœœ0™Jšœ<œœ™[—JšœY™YJšœB™BJ™—šž)œœ ™OJšœœ™Jšœ œ™Jšœœ™Jšœ œ™ Jšœ  œ™Jšœ œ™Jšœ œ™Jšœ œ™Jšœ™Jšœ œ™Jšœ œ™Jšœ™Jšœœ)™™>JšœM™Mšœœ™#Jšœ3œ™;—Jšœ+œ™=š œœ4œœ™KJšœœœœ™"Icodešœ4™4šœ ™&Jšœ)œœ™B—JšœN™Nš œœœœœ™7Lšœ5œœ™N—Jšœ œ ™Jšœ™šœ%™%Jšœ7œ™B—šœ œœ™šœ;™;Lšœœœœ™@——Lšœ™Lšœ4™4Jšœ/™/Jšœ œ œ™Jšœ œ5™FJšœ œœœ™Jš œœ$žœœœ!™yšœ)œ ™6Jšœ*™,—šœœ™Jšœ;™;Jšœ"™"—Jšœ™Jšœ™Jšœ™—Jšœ0œœ ™Sšœ!œ œ™8Jšœœœ™<—J™—š žœœ œœœœ™Qšœ œ™Jšœ>œœ™M—šœ œ™JšœEœœ™T—Jšœœ™—š žœœ œœœœ™XJšœ'œœœ™=šœ™$JšœW™W—Jšœœ™—J˜šœ™Jšœ™Jšœ™JšœZ™ZJšœ1™1Jšœ2™2—šœ™Jšœ™Jšœ4™4Jšœ6™6Jšœ™Jšœ™—šœ™Jšœ™Jšœ=™=JšœE™EJšœ ™ Jšœ™——šŸ™šœ˜Jšœ˜Jšœ2˜2JšœS˜SJšœ#˜#Jšœ%˜%J˜—šœ˜Jšœ˜Jšœ6˜6JšœA˜AJšœ#˜#Jšœ%˜%—J˜—Jšœ˜—…—ΐWξ