DIRECTORY Atom, CD, CDCellCommands, CDCells, CDCellsInteractions, CDCommandOps, CDDirectory, CDImports, CDLayers, CDOps, CDPanel, CDPanelFonts, CDPopUpMenus, CDProperties, CDRects, CDSatellites, CDTexts, CDSequencer, CDSequencerExtras, CDValue, CDViewer, Core, CoreOps, SymTab, IO, PopUpMenus, PopUpSelection, RefTab, RegularExpression, Rope, Sisyph, TerminalIO, TextOps, ViewerClasses, ViewerOps; TextOpsImpl: CEDAR PROGRAM IMPORTS Atom, CD, CDCellCommands, CDCells, CDCellsInteractions, CDCommandOps, CDDirectory, CDImports, CDLayers, CDOps, CDPanel, CDPanelFonts, CDProperties, CDRects, CDSatellites, CDSequencer, CDSequencerExtras, CDTexts, CDValue, CDViewer, IO, CDPopUpMenus, CoreOps, PopUpSelection, SymTab, RefTab, RegularExpression, Rope, Sisyph, TerminalIO, ViewerOps SHARES CDCellCommands, CDPopUpMenus = BEGIN TSPType: TYPE = TextOps.TSPType; firstInvisible: TSPType = expr; tspNms: ARRAY TSPType OF IO.ROPE _ [ text: "Text", sat: "Satellite", expr: "Expression", -- firstInvisible name: "Name", iForC: "Icon Code", iForS: "Icon Sch", extract: "Extract Proc", virus: "Prop Virus", any: "ANY" ]; tspNms3: ARRAY TSPType OF IO.ROPE _ [ text: "text", sat: "sat", expr: "expr", name: "name", iForC: "code", iForS: "schm", extract: "extr", virus: "virus", any: "any" ]; tspProps: ARRAY TSPType OF ATOM _ [ text: NIL, sat: NIL, expr: $SisyphExpressions, name: $SignalName, iForC: $CodeFor, iForS: $IconFor, extract: $SisyphExtractProc, virus: $CDBringoverLibraryName, any: NIL]; Finder: TYPE = RegularExpression.Finder; InstProc: TYPE = PROC[inst: CD.Instance] RETURNS[quit: BOOL _ FALSE]; InstObProc: TYPE = PROC[inst: CD.Instance, ob: CD.Object] RETURNS[quit: BOOL _ FALSE]; ObjProc: TYPE = PROC[obj: CD.Object] RETURNS[quit: BOOL _ FALSE]; Signal: SIGNAL[msg: IO.ROPE] = CODE; InitTextScanPropPanel: PROC = { tech: CD.Technology _ CD.FetchTechnology[$cmosB]; panelHeight: INT _ CDValue.FetchInt[tech, $PanelHeight, global, 120]; CDValue.Store[tech, $TextScanProp, NEW[TSPType _ text]]; CDValue.Store[tech, $TextScanPropNm, tspNms[text]]; CDPanel.Button[button: [text: "search", xpos: 0], command: $TextOpsSearch, tech: tech]; CDPanel.Button[button: [text: "replace", xpos: 50], command: $TextOpsReplace, tech: tech]; CDPanel.Button[button: [text: "prop:", xpos: 105], proc: ChangeTextScanProp, tech: tech]; CDPanel.Label[[width: 140, cdValueKey: $TextScanPropNm, redisplay: TRUE], tech]; CDPanel.Line[tech]; CDValue.StoreInt[tech, $PanelHeight, panelHeight+18]; ReSizePanelViewers[18]}; ReSizePanelViewers: PROC[heightChange: INT] = { EachViewer: PROC[v: ViewerClasses.Viewer] RETURNS[BOOL _ TRUE] = { design: CD.Design _ CDViewer.DesignOf[v]; IF design#NIL THEN IF RefTab.Store[designs, design, design] THEN ReSizePanelViewer[design, heightChange]}; designs: RefTab.Ref _ RefTab.Create[]; ViewerOps.EnumerateViewers[EachViewer]}; ReSizePanelViewer: PROC[design: CD.Design, heightChange: INT] = { viewer: ViewerClasses.Viewer _ CDPanel.Create[design]; column: ViewerClasses.Column _ ViewerOps.ViewerColumn[viewer]; ViewerOps.SetOpenHeight[viewer, viewer.wh + heightChange]; ViewerOps.ComputeColumn[column]}; TextOpsMenuCommand: PROC [command: CDSequencer.Command] ~ { ThreeBools: TYPE = RECORD[doReplace, oneOnly, global: BOOL]; tb: ThreeBools _ SELECT command.key FROM $FindOneMatchingRopeInDesign => [FALSE, TRUE, TRUE], $FindOneMatchingRopeInContext => [FALSE, TRUE, FALSE], $FindEachMatchingRopeInDesign => [FALSE, FALSE, TRUE], $FindEachMatchingRopeInContext => [FALSE, FALSE, FALSE], $ReplaceOneMatchingRopeInDesign => [TRUE, TRUE, TRUE], $ReplaceOneMatchingRopeInContext => [TRUE, TRUE, FALSE], $ReplaceEachMatchingRopeInDesign => [TRUE, FALSE, TRUE], $ReplaceEachMatchingRopeInContext => [TRUE, FALSE, FALSE], ENDCASE => ERROR; TextOpsCommand[command, tb.doReplace, tb.oneOnly, tb.global]}; TextOpsCommand: PROC [command: CDSequencer.Command, doReplace, oneOnly, global: BOOL] ~ { DoInst: InstObProc = { IF aborted^ THEN RETURN[TRUE]; [quit, count] _ IF CDTexts.IsText[inst.ob] THEN ReplaceSat[tsp, design, doReplace, oneOnly, count, inst, ob, finder, replace] ELSE ReplaceExpr[tsp, design, doReplace, oneOnly, count, inst, finder, replace]}; DoObject: ObjProc = {[quit, count] _ ReplaceExpr[tsp, design, doReplace, oneOnly, count, obj, finder, replace]}; design: CD.Design _ command.design; count: NAT _ 0; tsp: TSPType _ GetTextScanProp[design]^; patternRef: IO.ROPE; pattern: IO.ROPE; replace: IO.ROPE; finder: Finder; searched: RefTab.Ref _ RefTab.Create[]; oneFound: BOOL _ FALSE; aborted: REF BOOL _ NEW[BOOL _ FALSE]; CDSequencer.UseAbortFlag[design, aborted]; IF doReplace THEN replace _ GetText[design]; patternRef _ GetPattern[design]; pattern _ OnlyStarOrHashMatching[patternRef]; finder _ RegularExpression.CreateFromRope [pattern: pattern, literal: FALSE, word: FALSE, ignoreCase: FALSE ! RegularExpression.MalformedPattern => { TerminalIO.PutF["Syntax error in adjusted pattern \"%g\"\n", IO.rope[pattern]]; GOTO prematureExit}]; TerminalIO.PutF["\nMatch Property: %g\n", IO.rope[tspNms[tsp]]]; TerminalIO.PutF["Match Pattern: \"%g\"\n", IO.rope[patternRef]]; IF doReplace THEN TerminalIO.PutF[" New Pattern: \"%g\"\n", IO.rope[replace]]; TerminalIO.PutF["Match Context: %g\n", IO.rope[IF global THEN "Global" ELSE "Local"]]; oneFound _ ScanContext[design, DoInst, DoObject, global, oneOnly]; TerminalIO.PutF["%g matches.\n", IO.int[count]]; IF oneFound OR doReplace AND count#0 THEN CDSequencer.ExecuteCommand [key: $ResetScaleTop, design: design, queue: dontQueue, comm: command]; EXITS prematureExit => TerminalIO.PutF["Replace not done.\n"]}; ChangeTextScanProp: PROC [comm: CDSequencer.Command] = { tspNmList: LIST OF IO.ROPE; tspCur: TSPType; n: CARDINAL; FOR ts: TSPType DECREASING IN TSPType DO tspNmList _ CONS[tspNms[ts], tspNmList] ENDLOOP; TerminalIO.PutRope["Change Match Property\n"]; n _ PopUpSelection.Request[header: "Match Property", choice: tspNmList]; tspCur _ IF n=0 THEN GetTextScanProp[comm.design]^ ELSE VAL[n-1]; SetTextScanProp[comm.design, tspCur]}; TextOpsButtonCommand: PROC [comm: CDSequencer.Command] ~ { doReplace: BOOL _ SELECT comm.key FROM $TextOpsSearch => FALSE, $TextOpsReplace => TRUE, ENDCASE => ERROR; global: BOOL _ comm.b; oneOnly: BOOL _ comm.n#2; IF comm.n#1 THEN { TerminalIO.PutRope["Flush TextOps Cache\n"]; RefTab.Erase[globalCtx]; globalCtx _ RefTab.Create[]}; TextOpsCommand[comm, doReplace, oneOnly, global]}; ScanContext: PROC [design: CD.Design, instProc: InstObProc, objProc: ObjProc, allLevels, oneOnly: BOOL] RETURNS[found: BOOL _ FALSE] = { Push: PROC = { inst: CD.Instance _ CDOps.TheInstance[design: design]; []_CDCellsInteractions.PushInCellInstance[design, inst]}; pushes: INT; popped: BOOL _ FALSE; top: CD.Object; IF allLevels THEN WHILE CDCells.IsPushedIn[design] DO [] _ CDCellsInteractions.PopFromCell[design, interactive] ENDLOOP ELSE IF CDCells.IsPushedIn[design] THEN { popped _ TRUE; [] _ CDCells.EnumerateInstances[design.actual.rest.first.dummyCell.ob, DeselectAll]; [] _ CDCellsInteractions.PopFromCell[design, interactive]; top _ CDOps.TheInstance[design: design].ob}; IF top=NIL THEN top _ design.actual.first.dummyCell.ob; pushes _ ScanAll[design, top, allLevels, oneOnly, instProc, objProc]; IF popped THEN Push[]; IF pushes>1 THEN THROUGH [2..pushes] DO Push[] ENDLOOP; RETURN[pushes>0]}; ScanAll: PROC[design: CD.Design, top: CD.Object, goDeep, oneOnly: BOOL, instProc: InstObProc, objProc: ObjProc] RETURNS[pushes: INT _ 0] = { doInst: InstProc = { obVal: REF _ RefTab.Fetch[globalCtx, inst.ob].val; dive: BOOL _ goDeep AND (oneOnly OR obVal=NIL OR obVal=inst.ob); IF RefTab.Store[globalCtx, inst, inst] THEN IF instProc[inst, top] THEN GOTO MarkSelected; IF RefTab.Store[globalCtx, inst.ob, inst.ob] THEN IF objProc[inst.ob] THEN GOTO MarkSelected; IF dive AND CDCells.IsCell[inst.ob] THEN IF ((pushes _ ScanAll[design, inst.ob, goDeep, oneOnly, instProc, objProc])>0) THEN GOTO MarkSelected ELSE []_RefTab.Store[globalCtx, inst.ob, NEW[INT_1]]; EXITS MarkSelected => { []_CDCells.EnumerateInstances[top, DeselectAll]; inst.selected _ TRUE; RETURN[TRUE]}}; IF CDCells.EnumerateInstances[top, doInst] THEN pushes _ pushes + 1}; globalCtx: RefTab.Ref _ RefTab.Create[]; DeselectAll: InstProc = {inst.selected _ FALSE}; EnumDirectoryObjectsWithPattern: PROC [comm: CDSequencer.Command] ~ { proc: PROC [design: CD.Design, ob: CD.Object] _ GetObProc[comm.key]; finder: Finder _ GetFinder[comm.design]; CellEnumeratorProc: CDDirectory.EachEntryAction = { IF RegularExpression.SearchRope[finder, name].found THEN proc[comm.design, ob]}; [] _ CDDirectory.Enumerate[comm.design, CellEnumeratorProc]}; EnumSelectedObjects: PROC [comm: CDSequencer.Command] ~ { proc: PROC [design: CD.Design, ob: CD.Object] _ GetObProc[comm.key]; FOR w: CD.InstanceList _ CDOps.InstList[comm.design], w.rest WHILE w#NIL DO IF w.first.selected THEN proc[comm.design, w.first.ob] ENDLOOP}; ListUninstantiatedIconSchematics: PROC [comm: CDSequencer.Command] ~ { schTab: SymTab.Ref _ SymTab.Create[]; visited: RefTab.Ref _ RefTab.Create[]; EachInst: CDCells.InstEnumerator = { sch: IO.ROPE _ NARROW[CDProperties.GetProp[inst.ob, $IconFor]]; IF NOT CDCells.IsCell[inst.ob] THEN RETURN[FALSE]; IF sch.Length[]>0 THEN [] _ SymTab.Store[schTab, sch, sch]; IF RefTab.Store[visited, inst.ob, inst.ob] THEN [] _ CDCells.EnumerateInstances[inst.ob, EachInst]}; EachVisited: RefTab.EachPairAction = { nm: IO.ROPE _ CDDirectory.Name[NARROW[key], comm.design]; IF nm.Length[]>0 THEN [] _ SymTab.Delete[schTab, nm]}; EachUnVisited: SymTab.EachPairAction = {TerminalIO.PutF["%g\n", IO.rope[key]]}; FOR w: CD.InstanceList _ CDOps.InstList[comm.design], w.rest WHILE w#NIL DO []_EachInst[w.first] ENDLOOP; [] _ RefTab.Pairs[visited, EachVisited]; [] _ SymTab.Pairs[schTab, EachUnVisited]}; GetObProc: PROC[key: ATOM] RETURNS[proc: PROC [design: CD.Design, ob: CD.Object]] = { proc _ SELECT key FROM $ChangeColorSelected, $ChangeColorPattern => ChangeColor, ENDCASE => ERROR}; OnlyStarOrHashMatching: PROC[text: IO.ROPE] RETURNS[IO.ROPE] = { Insert: PROC[str: IO.ROPE] = {text _ Rope.Cat[text.Substr[0,index], str, text.Substr[index]]; index _ index+1}; index: INT; FOR index _ 0, index+1 WHILE index ERROR; '* => Insert["#"]; '# => LOOP; '[, '., '], '~, '^, '$, '+, '(, '|, '), '\\, '<, ':, ',, '>, '{, '} => Insert["'"]; ENDCASE ENDLOOP; RETURN[text]}; LogFind: PROC[ design: CD.Design, type: IO.ROPE, text: IO.ROPE, doReplace: BOOL, delete: BOOL, replace: IO.ROPE, on: REF, cell: CD.Object ] = { line0: IO.ROPE _ IO.PutFR["%g: %g ", IO.rope[type], IO.rope[text]]; online: IO.ROPE _ ""; inline: IO.ROPE _ ""; limit: INT _ 90; -- 120 if small IF doReplace THEN IF delete THEN {line0 _ line0.Cat[IO.PutFR["deleted "]]} ELSE { TerminalIO.PutF["%gchanged to\n", IO.rope[line0]]; line0 _ NIL; line0 _ IO.PutFR[" %g ", IO.rope[replace]]}; IF on#NIL THEN IF ISTYPE[on, CD.Object] THEN online _ IO.PutFR["on obj %g ", IO.rope[GetID[design, NARROW[on]]]] ELSE { inst: CD.Instance _ NARROW[on]; iRope: IO.ROPE _ CDOps.InstRope[inst]; IF ~iRope.Equal["rect comment"] THEN { oRope: IO.ROPE _ CDDirectory.Name[inst.ob, design]; IF oRope.Length[]=0 THEN online _ IO.PutFR["on inst %g ", IO.rope[iRope]] ELSE online _ IO.PutFR["on inst %g ", IO.rope[oRope]]}}; IF cell#NIL THEN inline _ IO.PutFR["in %g", IO.rope[GetID[design, cell]]]; IF line0.Length[] + online.Length[] + inline.Length[] < limit THEN {TerminalIO.PutF["%g%g%g\n", IO.rope[line0], IO.rope[online], IO.rope[inline]]; RETURN}; TerminalIO.PutF["%g\n", IO.rope[line0]]; SELECT online.Length[] + inline.Length[] FROM > limit => TerminalIO.PutF[" %g\n %g\n", IO.rope[online], IO.rope[inline]]; > 0 => TerminalIO.PutF[" %g%g\n", IO.rope[online], IO.rope[inline]]; ENDCASE}; GetID: PROC[design: CD.Design, obj: CD.Object] RETURNS[name: IO.ROPE] = { IF obj = CDOps.RealTopCell[design] THEN RETURN["(top level of design)"]; IF obj = design.actual.first.dummyCell.ob THEN RETURN [Rope.Cat[CDDirectory.Name[design.actual.first.mightReplace.ob, design], " (pushed in)"]]; name _ CDDirectory.Name[obj, design]; IF name.Length[]#0 THEN RETURN[name]; name _ CDOps.ToRope[obj]}; ReplaceRope: PROC[finder: Finder, text, replace: IO.ROPE] RETURNS[new: IO.ROPE] = { found: BOOL; at, atEnd, before, after: INT; IF finder=NIL THEN RETURN[text]; [found, at, atEnd, before, after] _ RegularExpression.SearchRope[finder, text]; IF NOT found THEN RETURN[text]; IF at=0 AND atEnd=0 AND before=0 AND after=0 THEN RETURN[replace]; -- * replace new _ Rope.Cat[text.Substr[0,at], replace, text.Substr[atEnd] ]}; ReplaceSat: PROC[tsp: TSPType, design: CD.Design, doReplace, oneOnly: BOOL, count: NAT, inst: CD.Instance, cell: CD.Object, finder: Finder, replace: IO.ROPE] RETURNS[quit: BOOL, newCount: NAT] = { delete: BOOL _ doReplace AND replace.Length[]=0; textSpec: CDTexts.TextSpecific _ NARROW[inst.ob.specific]; on: REF _ CDSatellites.GetMaster[cell, inst]; new: IO.ROPE _ replace; SELECT tsp FROM any => tsp _ IF on#NIL THEN sat ELSE text; text => IF on#NIL THEN RETURN[FALSE, count]; sat => IF on=NIL THEN RETURN[FALSE, count]; ENDCASE => RETURN[FALSE, count]; IF CD.InterestSize[inst.ob].x=0 OR CD.InterestSize[inst.ob].y=0 THEN {Signal["Zero dimension satellite"]; inst.selected _ TRUE; RETURN[TRUE, count]}; IF doReplace THEN { newOb: CD.Object; new _ ReplaceRope[finder, textSpec.text, replace]; IF new=textSpec.text THEN RETURN[FALSE, count]; newOb _ CDTexts.Create[new, textSpec.cdFont]; delete _ CD.InterestSize[newOb].x=0 OR CD.InterestSize[newOb].y=0; CDSequencer.MarkChangedIOOnly[design]; IF delete THEN {inst.selected _ TRUE; oneOnly _ TRUE} ELSE inst.ob _ newOb} ELSE IF ~RegularExpression.SearchRope[finder, textSpec.text].found THEN RETURN[FALSE, count]; LogFind[design, tspNms3[tsp], textSpec.text, doReplace, delete, new, on, cell]; RETURN[oneOnly, count+1]}; ReplaceExpr: PROC[ tsp: TSPType, design: CD.Design, doReplace: BOOL, oneOnly: BOOL, count: NAT, from: REF, finder: Finder, replace: IO.ROPE] RETURNS[quit: BOOL, newCount: NAT] = { quit _ FALSE; newCount _ count; IF tsp#any THEN [quit, newCount] _ ReplaceExprOnProp [tsp, design, doReplace, oneOnly, newCount, from, finder, replace] ELSE FOR tsp IN [firstInvisible..any) WHILE NOT quit DO [quit, newCount] _ ReplaceExprOnProp [tsp, design, doReplace, oneOnly, newCount, from, finder, replace] ENDLOOP}; ReplaceExprOnProp: PROC [tsp: TSPType, design: CD.Design, doReplace, oneOnly: BOOL, count: NAT, from: REF, finder: Finder, replace: IO.ROPE] RETURNS[quit: BOOL, newCount: NAT] = { propAtom: ATOM _ tspProps[tsp]; new: LIST OF IO.ROPE _ NIL; delete: BOOL _ doReplace AND replace.Length[]=0; changed: BOOL _ FALSE; exprs: LIST OF IO.ROPE _ NIL; ref: REF _ CDProperties.GetProp[from, propAtom]; quit _ FALSE; WITH ref SELECT FROM ropes: LIST OF IO.ROPE => {exprs _ ropes}; rope: IO.ROPE => {exprs _ LIST[rope]}; text: REF TEXT => {rope: IO.ROPE _ Rope.FromRefText[text]; exprs _ LIST[rope]}; atom: ATOM => {rope: IO.ROPE _ Atom.GetPName[atom]; exprs _ LIST[rope]}; ENDCASE => {exprs _ NIL}; FOR exprs _ exprs, exprs.rest WHILE exprs#NIL DO IF NOT doReplace THEN { IF ~ RegularExpression.SearchRope[finder, exprs.first].found THEN LOOP; LogFind[design, tspNms3[tsp], exprs.first, doReplace, delete, NIL, from, NIL]; count _ count +1; IF oneOnly THEN RETURN[TRUE, count]} ELSE { expr: IO.ROPE _ ReplaceRope[finder, exprs.first, replace]; IF (expr= exprs.first) THEN LOOP; LogFind[design, tspNms3[tsp], exprs.first, doReplace, delete, expr, from, NIL]; count _ count +1; changed _ TRUE; IF NOT delete THEN new _ CONS[expr, new]; IF oneOnly THEN { FOR temp: LIST OF IO.ROPE _ exprs.rest, temp.rest WHILE temp#NIL DO new _ CONS[temp.first, new] ENDLOOP; quit _ TRUE; EXIT} }; ENDLOOP; IF doReplace AND changed THEN { one: IO.ROPE _ IF new=NIL THEN NIL ELSE new.first; WITH ref SELECT FROM ropes: LIST OF IO.ROPE => ref _ new; rope: IO.ROPE => ref _ one; text: REF TEXT => ref _ Rope.ToRefText[one]; atom: ATOM => ref _ Atom.MakeAtom[one]; ENDCASE => ERROR; CDSequencer.MarkChangedIOOnly[design]; CDProperties.PutProp[from, propAtom, ref]}; RETURN[quit, count]}; ChangeColor: PROC[design: CD.Design, ob: CD.Object] = { size: CD.Position _ CD.InterestSize[ob]; off: CD.Position _ CD.InterestBase[ob]; layer: CD.Layer _ CDLayers.CurrentLayer[design]; mask: CD.Object _ CDRects.CreateRect[size: size, l: layer]; maskI: CD.Instance; name: IO.ROPE _ CDDirectory.Name[ob, design]; delete: BOOL _ layer = CD.commentLayer; EachInst: CDCells.InstEnumerator = { IF NOT CDRects.IsBareRect[inst.ob] THEN RETURN[FALSE]; IF CD.InterestSize[inst.ob]#size THEN RETURN[FALSE]; IF CD.InterestBase[inst.ob]#inst.trans.off THEN RETURN[FALSE]; IF CDProperties.GetProp[inst, $SisyphExtractProc]=NIL THEN RETURN[FALSE]; IF NARROW[CDProperties.GetProp[inst, $SisyphExtractProc], ATOM]#$ExtractNull THEN RETURN[FALSE]; IF delete THEN {maskI _ inst; TerminalIO.PutF["Color deleted in %g\n", IO.rope[name]]; RETURN[TRUE]}; IF inst.ob.layer=layer THEN {TerminalIO.PutF["Color unchanged in %g\n", IO.rope[name]]; RETURN[TRUE]}; inst.ob _ mask; TerminalIO.PutF["Color modified in %g\n", IO.rope[name]]; RETURN[TRUE]}; IF delete THEN { IF CDCells.EnumerateInstances[ob, EachInst] THEN IF CDCells.RemoveInstance[design, ob, maskI] THEN Signal["???"]} ELSE IF NOT CDCells.EnumerateInstances[ob, EachInst] THEN { maskI _ NEW[CD.InstanceRep _ [ob: mask, trans: [off: off] ] ]; CDProperties.PutProp[maskI, $SisyphExtractProc, $ExtractNull]; IF CDCells.IncludeInstance[design, ob, maskI] THEN Signal["???"]; TerminalIO.PutF["Color added in %g\n", IO.rope[name]]}; CDOps.Redraw[design]}; AddExpressionToEachSelected: PROC [command: CDSequencer.Command] ~ { count: NAT _ 0; id: IO.ROPE _ SELECT command.key FROM $AddInstanceExpressionToEachSelected => "Instance", $AddObjectExpressionToEachSelected => "Object", ENDCASE => ERROR; expr: IO.ROPE _ TerminalIO.RequestRope[id.Cat[" expression to add to selected: "]]; FOR w: CD.InstanceList _ CDOps.InstList[command.design], w.rest WHILE w#NIL DO IF w.first.selected THEN { on: REF _ SELECT command.key FROM $AddInstanceExpressionToEachSelected => w.first, $AddObjectExpressionToEachSelected => w.first.ob, ENDCASE => ERROR; exprs: LIST OF IO.ROPE _ NARROW[CDProperties.GetProp[on, Sisyph.expressionsProp]]; FOR test: LIST OF IO.ROPE _ exprs, test.rest WHILE test#NIL DO IF expr.Equal[test.first] THEN GOTO exit; REPEAT exit => LOOP ENDLOOP; exprs _ CONS[expr, exprs]; CDProperties.PutProp[on, Sisyph.expressionsProp, exprs]; count _ count+1}; ENDLOOP; TerminalIO.PutF["%g matches.\n", IO.int[count]]}; AddTextLines: PROC [command: CDSequencer.Command] ~ { pos: CD.Position _ command.pos; ob: CD.Object; lay: CD.Layer _ CDLayers.CurrentLayer[command.design]; r: IO.ROPE; font: CDTexts.CDFont _ CDPanelFonts.CurrentFont[command.design]; grid: INT _ Grid[command.design, font]; CDOps.Redraw[command.design]; lay _ CDPanelFonts.LayerForText[lay, command.design.technology]; IF font=NIL THEN CDSequencer.Quit["** no font"]; pos.y _ pos.y + font.origin.y; r _ TerminalIO.RequestRope["create text >"]; DO WHILE ~r.IsEmpty[] AND r.Fetch[] IN [IO.NUL..IO.SP] DO r _ r.Substr[1] ENDLOOP; WHILE ~r.IsEmpty[] AND r.Fetch[r.Length[]-1] IN [IO.NUL..IO.SP] DO r _ r.Substr[0, r.Length[]-1] ENDLOOP; IF r.IsEmpty[] THEN EXIT; ob _ CDTexts.Create[text: r, font: font, layer: lay]; IF ob=NIL THEN CDSequencer.Quit["***bad line***"]; []_CDOps.IncludeObject[design: command.design, ob: ob, trans: [pos, original]]; r _ TerminalIO.RequestRope[NIL]; pos.y _ pos.y - grid ENDLOOP}; BuildCrossReferenceLists: PROC [comm: CDSequencer.Command] ~ { InstEnumeratorProc: CDCells.InstEnumerator = { IF CDCells.IsCell[inst.ob] AND inst.selected THEN {nofCells _ nofCells+1; objNms _ CONS[CDDirectory.Name[inst.ob, comm.design], objNms]}}; ListEm: SymTab.EachPairAction = {list _ CONS[NARROW[val], list]}; rootCell: CD.Object _ comm.design^.actual.first.dummyCell.ob; objNms: LIST OF IO.ROPE _ NIL; top: Sisyph.Context _ Sisyph.Create[comm.design]; index: INT _ 0; nofCells: INT _ 0; maxNm: INT _ 0; OccSeq: TYPE = RECORD[name: IO.ROPE, seq: SEQUENCE size: CARDINAL OF BOOL]; list: LIST OF REF OccSeq; table: SymTab.Ref _ SymTab.Create[]; []_CDCells.EnumerateInstances[rootCell, InstEnumeratorProc]; FOR m: LIST OF IO.ROPE _ objNms, m.rest WHILE m#NIL DO AddToTable: PROC[wire: Core.Wire] = { name: IO.ROPE _ CoreOps.GetShortWireName[wire]; IF name.Length[]>0 THEN { ref: REF OccSeq _ NARROW[SymTab.Fetch[table, name].val]; IF ref=NIL THEN ref _ NEW[OccSeq[nofCells]]; ref.name _ name; ref[index] _ TRUE; maxNm _ MAX[name.Length[], maxNm]; []_SymTab.Store[table, name, ref]}; FOR i: INT IN [0..wire.size) DO AddToTable[wire[i]] ENDLOOP}; sub: Core.CellType _ Sisyph.ES[m.first, top]; AddToTable[sub.public]; index _ index +1; ENDLOOP; [ ] _ SymTab.Pairs[table, ListEm]; DO ok: BOOL _ TRUE; FOR l: LIST OF REF OccSeq _ list, l.rest WHILE l.rest#NIL DO TwoOcc: TYPE = RECORD[occ1, occ2: REF OccSeq]; SELECT Rope.Compare[l.first.name, l.rest.first.name] FROM less => LOOP; equal => ERROR; ENDCASE; [l.first, l.rest.first] _ TwoOcc[l.rest.first, l.first]; ok _ FALSE; ENDLOOP; IF ok THEN EXIT; ENDLOOP; TerminalIO.PutF["\nCross reference list for:\n"]; index _ 0; FOR m: LIST OF IO.ROPE _ objNms, m.rest WHILE m#NIL DO TerminalIO.PutF["%4g: %g\n", IO.int[index], IO.rope[m.first]]; index _ index +1; ENDLOOP; FOR m: LIST OF REF OccSeq _ list, m.rest WHILE m#NIL DO IF comm.key=$BuildCrossReferenceListsUnique THEN { used: NAT _ 0; FOR i: INT IN [0..nofCells) DO IF m.first[i] THEN used_used+1 ENDLOOP; IF used#1 THEN LOOP}; TerminalIO.PutF["%g ", IO.rope[m.first.name]]; FOR i: INT IN [0..(maxNm-m.first.name.Length[])) DO TerminalIO.PutRope[" "] ENDLOOP; FOR i: INT IN [0..nofCells) DO IF m.first[i] THEN TerminalIO.PutF["%2g", IO.int[i]] ELSE TerminalIO.PutF[" "] ENDLOOP; TerminalIO.PutF["\n"]; ENDLOOP}; ReplaceUnboundLibrary: PROC[command: CDSequencer.Command] ~ { DoInst: InstObProc = { }; DoObject: ObjProc = { imp: CDImports.ImportSpecific; new: IO.ROPE; IF ~CDImports.IsImport[obj] THEN RETURN; imp _ NARROW[obj.specific]; new _ ReplaceRope[finder, imp.designName, replace]; IF new=imp.designName THEN RETURN; TerminalIO.PutF["%g\n", IO.rope[imp.objectName]]; IF imp.boundOb#NIL THEN ERROR; -- RollBackAnd CDRead -X designFile IF imp.boundDesign#NIL THEN ERROR; -- RollBackAnd CDRead -X designFile imp.designName _ new; count _ count+1}; design: CD.Design _ command.design; tsp: TSPType _ name; count: NAT _ 0; doReplace: BOOL _ TRUE; replace: IO.ROPE _ IF doReplace THEN GetText[design] ELSE NIL; delete: BOOL _ doReplace AND replace.Length[]=0; patternRef: IO.ROPE _ GetPattern[design]; pattern: IO.ROPE _ OnlyStarOrHashMatching[patternRef]; oneFound: BOOL _ FALSE; finder: Finder _ RegularExpression.CreateFromRope [pattern: pattern, literal: FALSE, word: FALSE, ignoreCase: FALSE ! RegularExpression.MalformedPattern => { TerminalIO.PutF["Syntax error in adjusted pattern \"%g\"\n", IO.rope[pattern]]; GOTO prematureExit}]; TerminalIO.PutF["\nReplace Unbound Library\n"]; TerminalIO.PutF[" Old Library: \"%g\"\n", IO.rope[patternRef]]; TerminalIO.PutF[" New Library: \"%g\"\n", IO.rope[replace]]; TerminalIO.TOS[].Flush[]; IF ~TerminalIO.Confirm["Ready to proceed?"] THEN RETURN; oneFound _ ScanContext[design, DoInst, DoObject, TRUE, FALSE]; TerminalIO.PutF["%g matches.\n", IO.int[count]]; CDSequencer.ExecuteCommand [key: $ResetScaleTop, design: design, queue: dontQueue, comm: command]; EXITS prematureExit => TerminalIO.PutF["Replace not done.\n"]}; 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}; GetFinder: PROC[design: CD.Design] RETURNS[finder: Finder] = { pattern: IO.ROPE _ OnlyStarOrHashMatching[GetPattern[design]]; finder _ RegularExpression.CreateFromRope [pattern: pattern, literal: FALSE, word: FALSE, ignoreCase: FALSE]}; GetPattern: PROC [design: CD.Design] RETURNS [pattern: Rope.ROPE] = { pattern _ CDPanel.TakeDownText[design, $pattern]; IF Rope.IsEmpty[pattern] THEN pattern _ NIL}; GetText: PROC [design: CD.Design] RETURNS [text: Rope.ROPE] = { text _ CDPanel.TakeDownText[design, $text]; IF Rope.IsEmpty[text] THEN text _ NIL}; PutText: PROC [design: CD.Design, text: Rope.ROPE] RETURNS[Rope.ROPE] = {CDPanel.PutUpText[design, $text, text]; RETURN[text]}; GetTextScanProp: PROC [design: CD.Design] RETURNS[tspRef: REF TSPType] = { tspRef _ NARROW[CDValue.Fetch[design, $TextScanProp]]; IF tspRef=NIL THEN { tspRef _ NEW[TSPType _ text]; CDValue.Store[design, $TextScanProp, tspRef]}; RETURN[tspRef]}; SetTextScanProp: PROC [design: CD.Design, tsp: TSPType] = { tspRef: REF TSPType _ GetTextScanProp[design]; tspRef^ _ tsp; CDValue.Store[design, $TextScanPropNm, tspNms[tsp]]; []_CDPanel.PutUp[design, $TextScanPropNm]}; CycleTextScanProp: PROC[design: CD.Design] = { tsp: TSPType _ GetTextScanProp[design]^; tspLast: TSPType _ LAST[TSPType]; tspn: CARDINAL _ tsp.ORD; tspl: CARDINAL _ tspLast.ORD; SetTextScanProp[design, VAL[(tspn+1) MOD (tspl+1)]]}; menu: PopUpMenus.Menu _ CDPopUpMenus.MakeMenu[ key: $TextOps, header: "TextOps", doc: "Text Search and Replace Operations" ]; CDCommandOps.RegisterWithMenu[ menu: $OtherProgramMenu, entry: "TextOps", doc: "Text Search and Replace Operations", key: $TextOps, proc: NIL]; CDSequencerExtras.RegisterCommand [key: $TextOpsSearch, proc: TextOpsButtonCommand, queue: doQueue]; CDSequencerExtras.RegisterCommand [key: $TextOpsReplace, proc: TextOpsButtonCommand, queue: doQueue]; CDValue.RegisterKey[ $TextScanProp, NIL, $djc]; CDValue.RegisterKey[ $TextScanPropNm, NIL, $djc]; InitTextScanPropPanel[]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "List Uninstantiated Icon Schematics", doc: "Examines the IconFor property.", key: $ListUninstantiatedIconSchematics, proc: ListUninstantiatedIconSchematics ]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Change Color Pattern", doc: "Use panel color and pattern", key: $ChangeColorPattern, proc: EnumDirectoryObjectsWithPattern ]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Change Color Selected", doc: "Use panel color and selected cells", key: $ChangeColorSelected, proc: EnumSelectedObjects ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Add Instance Expression To Each Selected", doc: "Add Instance Expression To Each Selected", key: $AddInstanceExpressionToEachSelected, proc: AddExpressionToEachSelected ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Add Object Expression To Each Selected", doc: "Add Object Expression To Each Selected", key: $AddObjectExpressionToEachSelected, proc: AddExpressionToEachSelected ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Add mulitple text lines", doc: "Terminate with 2 CR's", key: $AddTextLines, proc: AddTextLines ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Build Cross Reference Lists", doc: "Build cross reference lists from public of selected", key: $BuildCrossReferenceLists, proc: BuildCrossReferenceLists ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Build Cross Reference Lists - Unique only", doc: "Build cross reference lists from public of selected - Unique only", key: $BuildCrossReferenceListsUnique, proc: BuildCrossReferenceLists ]; CDCommandOps.RegisterWithMenu[ menu: $ImportMenu, entry: "Replace Unbound Library", doc: "Replace Unbound Library", key: $ReplaceUnboundLibrary, proc: ReplaceUnboundLibrary ]; END. 8TextOpsImpl.mesa Don Curry May 14, 1987 4:41:05 pm PDT Last Edited by: Don Curry May 21, 1988 0:55:08 am PDT Types and Data Structures TextOps Main Procs DoPLAFix: PROC [comm: CDSequencer.Command] ~ { DoInst: PROC[inst: CD.Instance, ob: CD.Object] RETURNS[quit: BOOL _ FALSE] = { refExtrProc: REF _ CDProperties.GetProp[inst, $SisyphExtractProc]; refCodeFor: REF _ CDProperties.GetProp[inst, $CodeFor]; code: IO.ROPE; IF refExtrProc=NIL THEN RETURN[FALSE]; IF refCodeFor=NIL THEN RETURN[FALSE]; code _ NARROW[refCodeFor]; IF code.Find["PLAGen"]=-1 THEN RETURN[FALSE]; IF code.Find["PLAOutDrHeader"]#-1 THEN RETURN[FALSE]; IF CDProperties.GetProp[inst.ob, $SisyphExtractProc]#NIL THEN ERROR; IF CDProperties.GetProp[inst.ob, $CodeFor]#NIL THEN ERROR; CDProperties.PutProp[inst.ob, $SisyphExtractProc, refExtrProc]; CDProperties.PutProp[inst.ob, $CodeFor, refCodeFor]; CDProperties.PutProp[inst, $SisyphExtractProc, NIL]; CDProperties.PutProp[inst, $CodeFor, NIL]; TerminalIO.PutF["%g\n", IO.rope[NARROW[code]]]}; DoObject: PROC[obj: CD.Object] RETURNS[quit: BOOL _ FALSE] = { }; top: CD.Object; WHILE CDCells.IsPushedIn[comm.design] DO [] _ CDCellsInteractions.PopFromCell[comm.design, interactive] ENDLOOP; top _ comm.design.actual.first.dummyCell.ob; [] _ ScanAll[comm.design, top, TRUE, FALSE, DoInst, DoObject]; TerminalIO.PutRope["Done\n"]}; [key: $ResetScaleSel, design: design, queue: dontQueue, comm: command]; TextOps Enumeration ScanDesign: PROC [design: CD.Design, instProc: InstProc, objProc: ObjProc] = { CellEnumeratorProc: CDDirectory.EachEntryAction = {RETURN[ScanCell[name, ob]]}; IF CDDirectory.Enumerate[design, CellEnumeratorProc] THEN RETURN; FOR pushes: LIST OF CD.PushRec _ design^.actual, pushes.rest WHILE pushes#NIL DO IF ScanCell[NIL, pushes.first.dummyCell.ob] THEN EXIT ENDLOOP}; $AddIconBorderSelected, $AddIconBorderPattern => AddIconBorder, TextOps Satellite and Expression processing Add Borders and Color AddIconBorder: PROC [design: CD.Design, ob: CD.Object] ~ { name: IO.ROPE _ CDDirectory.Name[ob, design]; layer: CD.Layer _ CDLayers.CurrentLayer[design]; w: INT _ CDLayers.LayerWidth[design, layer]; ir: CD.Rect _ CD.InterestRect[ob]; vert: CD.Object _ CDRects.CreateRect[size: [w,ir.y2-ir.y1], l: layer]; hor: CD.Object _ CDRects.CreateRect[size: [ir.x2-ir.x1,w], l: layer]; inst: CD.Instance; inst _ NEW[CD.InstanceRep _ [ob: vert, trans: [off: [ir.x1, ir.y1]] ] ]; CDProperties.PutProp[inst, $SisyphExtractProc, $ExtractNull]; IF CDCells.IncludeInstance[design, ob, inst] THEN Signal["???"]; inst _ NEW[CD.InstanceRep _ [ob: vert, trans: [off: [ir.x2-w, ir.y1]] ] ]; CDProperties.PutProp[inst, $SisyphExtractProc, $ExtractNull]; IF CDCells.IncludeInstance[design, ob, inst] THEN Signal["???"]; inst _ NEW[CD.InstanceRep _ [ob: hor, trans: [off: [ir.x1, ir.y1]] ] ]; CDProperties.PutProp[inst, $SisyphExtractProc, $ExtractNull]; IF CDCells.IncludeInstance[design, ob, inst] THEN Signal["???"]; inst _ NEW[CD.InstanceRep _ [ob: hor, trans: [off: [ir.x1, ir.y2-w]] ] ]; CDProperties.PutProp[inst, $SisyphExtractProc, $ExtractNull]; IF CDCells.IncludeInstance[design, ob, inst] THEN Signal["???"]; TerminalIO.PutF["Borders added in %g\n", IO.rope[name]]; CDOps.Redraw[design]}; Add Expression To Selected Add Multiple Text Lines Build Cross Reference Lists Replace Unbound Library Panel Utilities Command/Menu Registration and Panel Init TextOps CDCommandOps.RegisterWithMenu[ menu: $OtherProgramMenu, entry: "DoPLAFix", doc: "DoPLAFix", key: $DoPLAFix, proc: DoPLAFix]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Find one matching rope in Design", doc: "Find one matching rope in Design", key: $FindOneMatchingRopeInDesign, proc: TextOpsMenuCommand ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Find one matching rope in Context", doc: "Find one matching rope in Context", key: $FindOneMatchingRopeInContext, proc: TextOpsMenuCommand ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Find each matching rope in Design", doc: "Find each matching rope in Design", key: $FindEachMatchingRopeInDesign, proc: TextOpsMenuCommand ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Find each matching rope in Context", doc: "Find each matching rope in Context", key: $FindEachMatchingRopeInContext, proc: TextOpsMenuCommand ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Replace one matching rope in Design", doc: "Replace one matching rope in Design", key: $ReplaceOneMatchingRopeInDesign, proc: TextOpsMenuCommand ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Replace one matching rope in Context", doc: "Replace one matching rope in Context", key: $ReplaceOneMatchingRopeInContext, proc: TextOpsMenuCommand ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Replace each matching rope in Design", doc: "Replace each matching rope in Design", key: $ReplaceEachMatchingRopeInDesign, proc: TextOpsMenuCommand ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Replace each matching rope in Context", doc: "Replace each matching rope in Context", key: $ReplaceEachMatchingRopeInContext, proc: TextOpsMenuCommand ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Search", doc: "Uses PROP and PATTERN from panel", key: $TextOpsSearch, proc: TextOpsButtonCommand ]; CDCommandOps.RegisterWithMenu[ menu: $TextOps, entry: "Replace", doc: "Uses PROP, PATTERN and TEXT from panel", key: $TextOpsReplace, proc: TextOpsButtonCommand ]; List Uninstantiated Icon Schematics Add Color Add Expression To Selected Add Multiple Text Lines Build Cross Reference Lists Replace Unbound Library Κ'd˜šœ™Jšœ%™%J™5—J˜JšΟk œœ„œ\Οf œ ˜J˜šΟn œœ˜Jšœœίœo˜ΰJšœ ˜&—Jš˜headšœ™Jšœ œ˜"Jšœ˜š œ œ œœœ˜%Jšœ˜Jšœ˜Jšœ&˜&Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜—š œ œ œœœ˜&Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜—šœ œ œœ˜$Jšœœ˜ Jšœœ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœœ˜ —J˜Jšœ œ˜)Jš œ œœœœœœ˜JJšœ œœœœ œœœ˜VJš œ œœœœœœ˜GJš Ÿœœœœœ˜%—™šŸœœ ™.šŸœœœœ œœœ™NJšœ œ2™BJšœ œ(™7Jšœœœ™Jš œ œœœœ™&Jš œ œœœœ™%Jšœœ ™Jšœœœœ™-Jšœ œœœ™5Jšœ3œœœ™DJšœ)œœœ™:Jšœ?™?Jšœ6™6Jšœ0œ™5Jšœ(œ™-Jšœœœ ™0—Jš Ÿœœœ œœœ™AJšœœ™šœ!™(Icodešœ?œ™G—Lšœ,™,Jšœ,ŸœŸœ™>Jšœ™J™—šŸœœ˜Jšœœœ˜3Jšœ œ5˜EJšœ&œ˜;Jšœ4˜4Jšœ<Ÿœ ˜WJšœ>Ÿœ ˜ZJšœY˜YJšœCœ ˜PJšœ˜Jšœ5˜5JšŸœ˜J˜—šŸœœœ˜/š Ÿ œœœœœ˜BJšœœ˜)šœœœœ&˜;Jšœ*˜.——Jšœ&˜&Jšœ(˜(J˜—šŸœœ œœ˜AJšœ6˜6Jšœ>˜>Jšœ:˜:Jšœ!˜!J˜—šŸœœ#˜;Jšœ œœœ˜<šœœ ˜(Jšœ#œœœ˜7Jšœ$œœœ˜9Jšœ$œœœ˜8Jšœ$œœœ˜9Jšœ%œœœ˜8Jšœ&œœœ˜:Jšœ&œœœ˜9Jšœ'œœœ˜;Jšœ œ˜—Jšœ>˜>J˜—šŸœ˜Jšœ;œ˜DšŸœ˜Jšœ œœœ˜šœœ˜*JšœN˜RJšœM˜Q——šŸœ˜$JšœK˜K—Jšœ œ˜$Jšœ œ˜Jšœ*˜*Jšœ œœ˜Jšœ œœ˜Jšœ œœ˜Jšœ˜Jšœ(˜(Jšœ œœ˜Jš œ œœœœœ˜'Jšœ*˜*Jšœ œ˜,Jšœ ˜ Jšœ.˜.šœ)˜)šœœœœ˜Cšœ'˜'Jšœ=œ˜OJšœ˜———Jšœ*œ˜@Jšœ,œ˜Ašœ ˜Jšœ,œ˜>—Jš œ(œœœ œ ˜WJšœB˜BJšœ!œ ˜0šœ œ œ œ˜DJšœG˜GJšœG™G—š˜Jšœ9˜9—J˜—šŸœœ ˜8Jš œ œœœœ˜Jšœ˜Jšœœ˜šœ  œœ˜%Jšœ œœ˜3—Jšœ.˜.JšœH˜HJš œ œœœœ˜AJšœ&˜&J˜—šŸœœ ˜:šœ œœ ˜'Jšœœ˜Jšœœ˜Jšœœ˜—Jšœœ ˜Jšœ œ ˜šœ œ˜Jšœ,˜,Jšœ˜Jšœ˜—Jšœ2˜2——™šŸ œ˜šœ œEœ˜UJšœœœ˜ —šŸœœ˜Jšœœ/˜7Jšœ9˜9—Jšœœ˜ Jšœœœ˜Jšœœ˜šœ ˜ šœœ˜(Lšœ:˜A—šœœœ˜)Jšœ œ˜JšœT˜TJšœ:˜:Jšœ,˜,——Lšœœœ(˜7JšœE˜EJšœœ˜Jš œ œœ œœ˜7Jšœ ˜J˜—š Ÿœœ œœœ˜Gšœ'˜'Jšœ œ ˜—šœ˜Jšœœ(˜2Jš œœ œ œœœ˜Ašœ'˜-Jšœœœ˜3—šœ+˜1Jšœœœ˜1—šœœœ˜*šœL˜NJšœœ ˜Jšœ$œœ˜5——šœ˜Jšœ0˜0Jšœœ˜Jšœœ˜——Jšœ)œ˜EJ˜—šœ(˜(J˜—šŸ œœ˜0J˜—šŸ œœ œ2™NJšŸœ!œ™OJšœ3œœ™Aš œ œœœ'œœ™PJš œ œœœœ™?—J™—šŸœœ ˜EJšœœ œ œ˜DJšœ(˜(šŸœ!˜3šœ1˜3Jšœ˜——Jšœ=˜=J˜—šŸœœ ˜9Jšœœ œ œ˜Dš œœ4œœ˜KJšœœœ˜@—J˜—šŸ œœ ˜FJšœ%˜%Jšœ&˜&šŸœ˜$Jšœœœœ*˜?Jš œœœœœ˜2Jšœœ%˜;šœ(˜*Jšœ5˜9——šŸ œ˜&Jšœœœœ˜9Jšœœ!˜6—JšœO˜Oš œœ4œœ˜KJšœœ˜—Jšœ Ÿœ˜(Jšœ Ÿœ˜*J˜—šŸ œœœœœ œ œ ˜Ušœœ˜Jšœ™Jšœ(™(Jšœ˜Jšœ$˜$Jšœ œ˜———™+šŸœœœœœœœ˜@šŸœœœœ˜JšœR˜R—Jšœœ˜ šœœ˜3šœ˜Jšœ œ˜Jšœ˜Jšœ œ˜Jšœ˜Jšœ˜Jšœ&˜&Jšœœ˜—Jšœ˜——J˜šŸœœ˜Jšœ œ˜Jšœœœ˜Jšœ œœ˜Jšœ œ˜Jšœ œ˜Jšœ œœ˜Jšœœ˜ Jšœœ ˜Jš œœœœœ œ ˜DJšœ œœ˜Jšœ œœ˜Jšœ œΟc˜"šœ œœ˜Jšœ*˜.šœ˜Jšœ"œœ˜?Jšœœœ˜-——š œœœœœœ˜'Jšœ!œœ˜Hšœ˜Jšœœ˜Jšœœœ˜&šœœ˜'Jšœœœ%˜3šœ˜Jšœ"œ ˜5Jšœ"œ˜8————Jšœœœ˜Jšœ<˜BJš œœœœœ˜X—Jšœœ˜(šœ#˜-Jšœ+œœ˜MJšœ$œœ˜FJšœ˜ ——J˜šŸœœ œœ œœœ˜IJšœ!œœ˜Hšœ(œ˜5JšœZ˜Z—Jšœ%˜%Jšœœ˜%Jšœ˜—J˜šŸ œœ œœœœœ˜SJšœ œ˜Jšœœ˜Jšœœœœ˜ JšœO˜OJšœœœœ˜Jš œœ œ œ œœ   ˜OJšœA˜A—J˜šŸ œœœœ œœœ"œœ˜Jšœœ œ˜&Jšœ œ œ˜1Jšœ"œ˜;Jšœœ&˜/Jšœœœ ˜šœ˜Jš œ œœœœ˜*Jš œœœœœœ ˜,Jš œœœœœœ ˜-Jšœ œœ ˜%—šœœœœ˜?Jšœ6œœœ ˜U—šœ ˜ šœ˜Jšœœ˜Jšœ2˜2Jšœœœœ ˜/Jšœ-˜-Jšœ œœœ˜CJšœ Ÿœ ˜&šœ˜ Jšœœ œ˜+Jšœ˜——šœœ;˜BJšœœœ ˜——JšœO˜OJšœ˜J˜—šŸ œœ˜Jšœ˜Jšœ œ˜Jšœ œ˜Jšœ œ˜Jšœ œ˜ Jšœœ˜ Jšœ˜šœ œœ˜Jšœœ œ˜&—Jšœœ˜šœ˜ š˜šœ$˜$JšœB˜B——š œœœœœœ˜8šœ$˜$JšœCœ˜L———J˜—šŸœ˜Jšœœœ œœœœœœ œ˜›Jšœ œ˜Jš œœœœœœ˜Jšœœ œ˜0Jšœ œœ˜Jš œœœœœœ˜Jšœœ(˜1Jšœœ˜šœœ˜Jš œœœœœ˜*Jšœœœœ˜(Jš œœœ œœ#œ˜PJš œœœœ œ˜KJšœœ˜—š œœœœœœ ˜Ašœ˜Jšœ;œœ˜GJšœ>œœ˜NJšœ˜Jšœ œœœ ˜$—šœ˜Jšœœœ-˜:Jšœœœ˜!JšœJœ˜OJšœ˜Jšœ œ˜Jšœœœœ ˜)šœ œ˜šœœœœœœœ˜CJšœœœ˜$—Jšœœœ˜——Jšœ˜—šœ œ œ˜Jšœœœœœœœœ ˜2šœœ˜Jš œœœœœ˜$Jšœœœ˜Jšœœœ˜-Jšœœ ˜*Jšœœ˜—Jšœ Ÿœ ˜&Jšœ+˜+—Jšœ˜——šœ™šŸ œœ œ œ ™:Jšœœœ!™/Jšœœ(™2Jšœœ(™0Jšœœ œ™%Jšœœ?™HJšœœ?™GJšœœ ™Jšœœœ;™HJšœ=™=Jšœ+œ™@Jšœœœ=™JJšœ=™=Jšœ+œ™@Jšœœœ:™GJšœ=™=Jšœ+œ™@Jšœœœ<™IJšœ=™=Jšœ+œ™@Jšœ)œ ™8Jšœ™J™—šŸ œœ œ œ ˜7Jšœœ œ˜)Jšœœ œ˜(Jšœœ(˜2Jšœœ4˜=Jšœ˜Jšœœœ ˜.Jšœœ œ˜'šŸœ˜$Jš œœœœœ˜7Jš œœœœœ˜6Jš œœ&œœœ˜>Jš œ0œœœœ˜Išœœ1œ˜LJšœœœ˜—šœ˜Jšœ8œœœ˜V—šœ˜Jšœ,œœœ˜J—Jšœ˜Jšœ*œœœ˜H—šœ˜ šœ˜šœ*˜0Jšœ+œ˜@——Jšœœœ*œ˜;Jšœœœ0˜>Jšœ>˜>Jšœ,œ˜AJšœ'œ˜7—Jšœ˜——šŸ™šŸœœ#˜DJšœœ˜šœœœœ ˜%Jšœ3˜3Jšœ0˜0Jšœ œ˜—JšœœœF˜Sš œœ7œœ˜Nšœœ˜šœœœ ˜!Jšœ0˜0Jšœ2˜2Jšœ œ˜—Jš œœœœœœ3˜Ršœœœœœœœ˜>Jšœœœ˜)Jšœ œœ˜—Jšœœ˜Jšœ8˜8Jšœ˜—Jšœ˜—Jšœ!œ˜1——™šŸ œœ#˜5Jšœœ˜ Jšœœ˜Jšœœ/˜7Jšœœœ˜ JšœA˜AJšœœ˜(Jšœ˜Jšœ@˜@Jšœœœ ˜0Jšœ˜Jšœ,˜,š˜Jšœœ œœœœœœœ˜Ošœœœœœœœ˜?Jšœœ˜)—Jšœ œœ˜Jšœ5˜5Jšœœœ$˜2JšœO˜OJšœœ˜ Jšœœ˜———šœŸ™šŸœœ ˜>šŸœ˜.šœœ˜1Jšœ!œ3˜X——JšŸœ"œœ˜AJšœ œ1˜=Jš œœœœœœ˜Jšœ2˜2Jšœœ˜Jšœ œ˜Jšœœ˜Jšœœœœœœœœœ˜KJšœœœœ˜Jšœ%˜%Jšœ<˜<šœœœœœœœ˜6šŸ œœ˜%Jšœœœ"˜/šœœ˜Jšœœ œ ˜8Jšœœœœ˜,Jšœ˜Jšœ œ˜Jšœœ˜"Jšœ#˜#—Jš œœœœœ˜=—Jšœœ˜.Jšœ˜Jšœœ˜—Jšœ"˜"š˜Jšœœœ˜š œœœœœœ˜Jšœœ˜—š œœœœœœ˜7šœ*œ˜2Jšœœ˜Jšœœœœœ œ œ˜FJšœœœ˜—Jšœœ˜.Jš œœœ$œœ˜Tš œœœœœ ˜,Jšœœ˜&Jšœœ˜#—Jšœ˜Jšœ˜ ———šŸ™šŸœœ"˜=JšŸœ˜šŸœ ˜Jšœ˜Jšœ ˜ Jšœœœ˜)Jšœœ˜Jšœ3˜3Jšœœœ˜"Jšœœ˜1Jš œ œœœ #˜CJš œœœœ #˜FJšœ˜Jšœ˜—Jšœ œ˜$Jšœ˜Jšœ œ˜Jšœ œœ˜Jš œ œœœ œœœ˜@Jšœ œœ˜3Jšœ œœ˜*Jšœ œœ'˜8Jšœ œœ˜šœ3˜3šœœœœ˜Cšœ'˜'Jšœ=œ˜OJšœ˜———Jšœ/˜/Jšœ,œ˜AJšœ,œ˜>Jšœ œ ˜Jšœ*œœ˜8Jšœ1œœ˜>Jšœ!œ ˜0šœ˜JšœG˜G—š˜Jšœ9˜9———™š Ÿœœ œ œœœ˜PJšœ:˜:šœ ˜šœœ+œ˜?Jšœœœœ˜6—Jšœ#˜'—Jš œœœœœœ˜JJ˜—šŸ œœ œ œ˜>Jšœ œœ/˜?šœ)˜)Jšœœœœ˜D—J˜—š Ÿ œœ œ œœ˜EJšœ1˜1Jšœœ œ˜-J˜—š Ÿœœ œ œ œ˜?Jšœ+˜+Jšœœœ˜'J˜—š Ÿœœ œœœœ˜GJšœ)œ˜7J˜—š Ÿœœ œ œ œ ˜JJšœ œ'˜6šœœœ˜Jšœ œ˜Jšœ/˜/—Jšœ ˜J˜—šŸœœ œ˜;Jšœœ#˜.Jšœ˜Jšœ4˜4Jšœ+˜+J˜—šŸœœ œ ˜.Jšœ)˜)Jšœœ ˜!Jšœœœ˜Jšœœ œ˜Jšœœ œ ˜5——šœ(™(šœ™šœ.˜.Jšœ˜Jšœ˜Jšœ-˜-J˜—šœ˜Jšœ˜Jšœ˜Jšœ+˜+Jšœ˜Jšœœ˜ J˜—šœ™Jšœ™Jšœ™Jšœ™Jšœ™Jšœ™J™—šœ™Jšœ™Jšœ,™,Jšœ*™*Jšœ#™#Jšœ™—šœ™Jšœ™Jšœ-™-Jšœ+™+Jšœ$™$Jšœ™—šœ™Jšœ™Jšœ,™,Jšœ*™*Jšœ$™$Jšœ™—šœ™Jšœ™Jšœ-™-Jšœ+™+Jšœ%™%Jšœ™—šœ™Jšœ™Jšœ/™/Jšœ-™-Jšœ&™&Jšœ™—šœ™Jšœ™Jšœ0™0Jšœ.™.Jšœ'™'Jšœ™—šœ™Jšœ™Jšœ/™/Jšœ-™-Jšœ'™'Jšœ™—šœ™Jšœ™Jšœ0™0Jšœ.™.Jšœ(™(Jšœ™—J™šœ™Jšœ™Jšœ™Jšœ)™)Jšœ™Jšœ™—šœ™Jšœ™Jšœ™Jšœ/™/Jšœ™Jšœ™—J˜šœ!˜!JšœB˜B—šœ!˜!JšœC˜C—Jšœ%œ˜0Jšœ&œ˜1J˜JšŸœ˜—šœŸœŸœŸ ™#šœ˜Jšœ˜JšœŸœŸœŸ œ˜.Jšœ'˜'JšœŸ œ˜(JšœŸ œ˜*——šœ ™ šœ˜Jšœ˜Jšœ˜Jšœ$˜$Jšœ˜Jšœ)˜)—šœ˜Jšœ˜Jšœ ˜ Jšœ+˜+Jšœ˜Jšœ˜——šœ™šœ˜Jšœ˜Jšœ3˜3Jšœ1˜1Jšœ+˜+Jšœ%˜%—šœ˜Jšœ˜Jšœ1˜1Jšœ/˜/Jšœ)˜)Jšœ%˜%——™šœ˜Jšœ˜Jšœ"˜"Jšœ˜Jšœ˜Jšœ˜——šœ™šœ˜Jšœ˜Jšœ&˜&Jšœ<˜