DIRECTORY Atom, CD, CDCellCommands, CDCells, CDCellsInteractions, CDCommandOps, CDDirectory, CDLayers, CDOps, CDPanel, CDPanelFonts, CDPopUpMenus, CDProperties, CDRects, CDSatellites, CDTexts, CDSequencer, CDValue, CDViewer, Core, CoreOps, SymTab, IO, PopUpMenus, PopUpSelection, RefTab, RegularExpression, Rope, Sisyph, TerminalIO, TextOps, ViewerOps; TextOpsImpl: CEDAR PROGRAM IMPORTS Atom, CD, CDCellCommands, CDCells, CDCellsInteractions, CDCommandOps, CDDirectory, CDLayers, CDOps, CDPanel, CDPanelFonts, CDProperties, CDRects, CDSatellites, CDSequencer, 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]}; 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 = { [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; 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] = { pushes: INT; IF allLevels THEN WHILE CDCells.IsPushedIn[design] DO [] _ CDCellsInteractions.PopFromCell[design, interactive] ENDLOOP; pushes _ ScanAll[design, design.actual.first.dummyCell.ob, allLevels, oneOnly, instProc, objProc]; IF pushes>1 THEN { THROUGH [2..pushes] DO inst: CD.Instance _ CDOps.TheInstance[design: design, text: "push into "]; []_CDCellsInteractions.PushInCellInstance[design, inst] 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}; GetObProc: PROC[key: ATOM] RETURNS[proc: PROC [design: CD.Design, ob: CD.Object]] = { proc _ SELECT key FROM $AddIconBorderSelected, $AddIconBorderPattern => AddIconBorder, $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.MarkChanged[design]; CDProperties.PutProp[from, propAtom, ref]}; RETURN[quit, count]}; 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]}; 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}; 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]; 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 ]; CDValue.RegisterKey[ $TextScanProp, NIL, $djc]; CDValue.RegisterKey[ $TextScanPropNm, NIL, $djc]; InitTextScanPropPanel[]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Add Icon Border Pattern", doc: "Uses current layer and width and marks it as invisible to Sisyph.", key: $AddIconBorderPattern, proc: EnumDirectoryObjectsWithPattern ]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Add Icon Border Selected", doc: "Uses current layer and width and marks it as invisible to Sisyph.", key: $AddIconBorderSelected, proc: EnumSelectedObjects ]; 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 ]; END. ¬TextOpsImpl.mesa Don Curry May 14, 1987 4:41:05 pm PDT Last Edited by: Don Curry September 11, 1987 1:10:22 pm PDT Types and Data Structures TextOps Main Procs [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}; TextOps Satellite and Expression processing Add Borders and Color Add Expression To Selected Add Multiple Text Lines Build Cross Reference Lists Panel Utilities Command/Menu Registration and Panel Init TextOps Add Border Add Color Add Expression To Selected Add Multiple Text Lines Build Cross Reference Lists Κ!]˜šœ™Jšœ%™%J™;—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š žœœœœœ˜%—™šžœœ˜Jšœœœ˜1Jšœ œ5˜EJšœ&œ˜;Jšœ4˜4Jšœ<žœ ˜WJšœ>žœ ˜ZJšœY˜YJšœCœ ˜PJšœ˜Jšœ6˜6J˜—šžœœ#˜;Jšœ œœœ˜<šœœ ˜(Jšœ#œœœ˜7Jšœ$œœœ˜9Jšœ$œœœ˜8Jšœ$œœœ˜9Jšœ%œœœ˜8Jšœ&œœœ˜:Jšœ&œœœ˜9Jšœ'œœœ˜;Jšœ œ˜—Jšœ>˜>J˜—šžœ˜Jšœ;œ˜Dšžœ˜šœœ˜*JšœN˜RJšœM˜Q——šžœ˜$JšœK˜K—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šœœ˜ šœ œœ˜5Icodešœ:œ˜B—šœ˜JšœY˜Y—šœ œ˜šœ ˜JšœœC˜KJšœ8œ˜A——Jšœ ˜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˜—šž œœœœœ œ œ ˜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šœ˜ ———™š žœœ œ œœœ˜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šœ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šœ%œ˜0Jšœ&œ˜1J˜Jšžœ˜—™ šœ˜Jšœ˜Jšœ"˜"JšœJ˜JJšœ˜Jšœ)˜)—šœ˜Jšœ˜Jšœ#˜#JšœJ˜JJšœ˜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šœ<˜