DIRECTORY CD, CDCells, CDCommandOps, CDDirectory, CDImports, CDOps, CDProperties, CDSatellites, CDSequencer, Core, CoreClasses, CoreOps, CoreGeometry, CoreProperties, IO, Rope, RopeList, Sinix, SinixOps, Sisyph, SymTab, TerminalIO, ViewerClasses; SisyphCmdsImpl: CEDAR PROGRAM IMPORTS CD, CDCells, CDCommandOps, CDDirectory, CDImports, CDOps, CDProperties, CDSatellites, CDSequencer, CoreClasses, CoreOps, CoreGeometry, CoreProperties, IO, Rope, RopeList, Sinix, SinixOps, Sisyph, SymTab, TerminalIO SHARES Sinix, Sisyph = BEGIN ROPE: TYPE = Rope.ROPE; ROPES: TYPE = LIST OF ROPE; Wire: TYPE = Core.Wire; Wires: TYPE = Core.Wires; CellType: TYPE = Core.CellType; UnMakeIcon: PROC [comm: CDSequencer.Command] = { selected: CD.Instance _ TheCellInstance[comm.design, "UnMakeIcon\n"]; IF selected=NIL THEN RETURN; CleanUpIconProperties[selected.ob]; TerminalIO.PutF ["UnMakeIcon of %g done.\n", IO.rope[CDDirectory.Name[selected.ob, comm.design]]]}; MakeCellIcon: PROC [comm: CDSequencer.Command] = { key: ATOM; rope, name: ROPE; selected: CD.Instance _ TheCellInstance[comm.design, "MakeCellIcon\n"]; IF selected=NIL THEN RETURN; name _ CDDirectory.Name[selected.ob, comm.design]; IF NOT Rope.Match["*.icon", name] THEN TerminalIO.PutF["*** Convention for icons is to suffix them with '.icon'.\n"]; SELECT TerminalIO.RequestSelection[Rope.Cat["MakeCellIcon of ", name], LIST ["From Code", "From Schematic"], "choice of the nature of the cell icon", LIST ["Code returns a CellType", "Schematic should extract as a CellType"]] FROM 1 => { key _ $CodeFor; rope _ TerminalIO.RequestRope["Type code: "]; TerminalIO.PutF["done.\n"]}; 2 => { rope _ TerminalIO.RequestRope["Type schematic name: "]; IF Rope.IsEmpty[rope] AND Rope.Match["*.icon", name] THEN rope _ Rope.Cat[Rope.Substr[name, 0, Rope.Length[name]-5], ".sch"]; IF CDDirectory.Fetch[comm.design, rope]=NIL THEN { TerminalIO.PutF["*** No object '%g' in design.\n", IO.rope[rope]]; RETURN}; IF Rope.Equal[rope, name] THEN { TerminalIO.PutF["*** You can't do that: same icon and sch name!\n"]; RETURN}; IF NOT Rope.Match["*.sch", rope] THEN TerminalIO.PutF["*** Convention for schematics is to suffix them with '.sch'.\n"]; key _ $IconFor; TerminalIO.PutF["%g made cell icon of %g.\n", IO.rope[name], IO.rope[rope]]}; ENDCASE => {TerminalIO.PutF["*** Not done.\n"]; RETURN}; CleanUpIconProperties[selected.ob]; CDProperties.PutObjectProp[selected.ob, key, rope]; CDProperties.PutObjectProp[selected.ob, Sisyph.mode.extractProcProp, $SisyphExtractCellIcon]}; MakeWireIcon: PROC [comm: CDSequencer.Command] = { key: ATOM; rope, name: ROPE; choice: INT; selected: CD.Instance _ TheCellInstance[comm.design, "MakeWireIcon\n"]; IF selected=NIL THEN RETURN; name _ CDDirectory.Name[selected.ob, comm.design]; IF NOT Rope.Match["*.icon", name] THEN TerminalIO.PutF["*** Convention for icons is to suffix them with '.icon'.\n"]; choice _ TerminalIO.RequestSelection[ Rope.Cat["MakeWireIcon of ", name], LIST ["From Code; Named", "From Code; UnNamed", "From Schematic; Named", "From Schematic; UnNamed"], "choice of the nature of the cell icon", LIST ["Code returns a Wire", "Code returns a Wire", "Schematic should extract as a CellType", "Schematic should extract as a CellType"] ]; SELECT choice FROM 1, 2 => { key _ $CodeFor; rope _ TerminalIO.RequestRope["Type code: "]; TerminalIO.PutF["done.\n"]}; 3, 4 => { rope _ TerminalIO.RequestRope["Type schematic name: "]; IF Rope.IsEmpty[rope] AND Rope.Match["*.icon", name] THEN rope _ Rope.Cat[Rope.Substr[name, 0, Rope.Length[name]-5], ".sch"]; IF CDDirectory.Fetch[comm.design, rope]=NIL THEN { TerminalIO.PutF["*** No object '%g' in design.\n", IO.rope[rope]]; RETURN}; IF Rope.Equal[rope, name] THEN { TerminalIO.PutF["*** You can't do that: same icon and sch name!\n"]; RETURN}; IF NOT Rope.Match["*.sch", rope] THEN TerminalIO.PutF["*** Convention for schematics is to suffix them with '.sch'.\n"]; key _ $IconFor; TerminalIO.PutF["%g made wire icon of %g.\n", IO.rope[name], IO.rope[rope]]}; ENDCASE => {TerminalIO.PutF["*** Not done.\n"]; RETURN}; CleanUpIconProperties[selected.ob]; CDProperties.PutObjectProp[selected.ob, key, rope]; CDProperties.PutObjectProp[selected.ob, Sisyph.mode.extractProcProp, SELECT choice FROM 1, 3 => $SisyphExtractNamedWireIcon, 2, 4 => $SisyphExtractUnNamedWireIcon, ENDCASE => ERROR]}; MakeSequenceIcon: PROC [comm: CDSequencer.Command] = { selected: CD.Instance _ TheCellInstance[comm.design, "MakeSequenceIcon\n"]; IF selected=NIL THEN RETURN; CleanUpIconProperties[selected.ob]; CDProperties.PutObjectProp[selected.ob, Sisyph.mode.extractProcProp, $SisyphExtractSequence]; IF ParseSatellites[CDSatellites.GetSatelliteRopes[selected.ob]].keyword=NIL THEN TerminalIO.PutF["*** Warning: there is no satellite of the form 'Keyword: Expression'.\n"]; TerminalIO.PutF["Sequencing of %g done.\n", IO.rope[CDDirectory.Name[selected.ob, comm.design]]]}; MakeInvisibleToExtractor: PROC [comm: CDSequencer.Command] = { nInstances: INT _ 0; FOR w: LIST OF CD.Instance _ CDOps.InstList[comm.design], w.rest WHILE w#NIL DO inst: CD.Instance _ w.first; IF inst.selected THEN { CDProperties.PutInstanceProp[inst, Sisyph.mode.extractProcProp, $ExtractNull]; nInstances _ nInstances+1; FlushCache[comm.design, inst.ob] } ENDLOOP; TerminalIO.PutF["Made %g instances invisible to Sisyph\n", IO.int[nInstances]] }; MakeVisibleToExtractor: PROC [comm: CDSequencer.Command] = { nInstances: INT _ 0; FOR w: LIST OF CD.Instance _ CDOps.InstList[comm.design], w.rest WHILE w#NIL DO inst: CD.Instance _ w.first; IF inst.selected THEN { CDProperties.PutInstanceProp[inst, Sisyph.mode.extractProcProp, NIL]; nInstances _ nInstances+1; FlushCache[comm.design, inst.ob]} ENDLOOP; TerminalIO.PutF["Made %g instances visible to Sisyph\n", IO.int[nInstances]]}; FlushCache: PROC [design: CD.Design, obj: CD.Object] = { name: ROPE _ CDDirectory.Name[obj, design]; iconFor: REF = CDProperties.GetObjectProp[obj, $IconFor]; schName: ROPE = IF ISTYPE [iconFor, ROPE] THEN NARROW [iconFor] ELSE NIL; sch: CD.Object = IF schName#NIL THEN CDDirectory.Fetch[design, schName] ELSE NIL; FlushEachInstance: CDCells.InstEnumerator = {FlushCache[design, inst.ob]}; IF name=NIL AND (CDCells.IsCell[obj] OR CDImports.IsImport[obj]) THEN name _ CD.Describe[ob: obj, design: design]; IF (CDProperties.GetObjectProp[obj, $SinixInstanceCache]#NIL OR CDProperties.GetObjectProp[obj, $SinixObjectCache]#NIL) AND name#NIL THEN TerminalIO.PutF["Flushing %g.\n", IO.rope[name]]; -- We use the property although it is PRIVATE because printing is just a hint Sinix.FlushCache[obj]; IF CDCells.IsCell[obj] THEN [] _ CDCells.EnumerateInstances[obj, FlushEachInstance]; IF sch#NIL THEN FlushCache[design, sch]}; FlushSisyphCaches: PROC [comm: CDSequencer.Command] = { FOR w: LIST OF CD.Instance _ CDOps.InstList[comm.design], w.rest WHILE w#NIL DO IF w.first.selected THEN FlushCache[comm.design, w.first.ob]; ENDLOOP}; ShowInstExpressions: PROC [comm: CDSequencer.Command] = { selected: CD.Instance _ CDOps.TheInstance[comm.design, "ShowInstExpressions\n"]; IF selected=NIL THEN RETURN; PutRopes["Instance Expressions:\n", NARROW [CDProperties.GetInstanceProp[selected, Sisyph.expressionsProp]]]}; AddInstExpression: PROC [comm: CDSequencer.Command] = { exprs: ROPES; selected: CD.Instance _ CDOps.TheInstance[comm.design, "AddInstExpression\n"]; IF selected=NIL THEN RETURN; exprs _ NARROW [CDProperties.GetInstanceProp[selected, Sisyph.expressionsProp]]; PutRopes["Add Instance Expression. Previous Instance Expressions:\n", exprs]; exprs _ CONS [TerminalIO.RequestRope[Rope.Cat[" New Expression: "]], exprs]; CDProperties.PutInstanceProp[selected, Sisyph.expressionsProp, exprs]}; EditInstExpressions: PROC [comm: CDSequencer.Command] = { exprs: ROPES; selected: CD.Instance _ CDOps.TheInstance[comm.design, "EditInstExpressions\n"]; IF selected=NIL THEN RETURN; TerminalIO.PutF["Edit Instance Expressions\n"]; exprs _ NARROW[CDProperties.GetInstanceProp[selected, Sisyph.expressionsProp]]; exprs _ EditExpressions[exprs, "Expression"]; CDProperties.PutInstanceProp[selected, Sisyph.expressionsProp, exprs]}; ShowObjExpressions: PROC [comm: CDSequencer.Command] = { selected: CD.Instance _ CDOps.TheInstance[comm.design, "ShowObjExpressions\n"]; IF selected=NIL THEN RETURN; PutRopes["Object Expressions:\n", NARROW [CDProperties.GetObjectProp[selected.ob, Sisyph.expressionsProp]]]; IF NOT CDImports.IsImport[selected.ob] THEN RETURN; IF NARROW [selected.ob.specific, CDImports.ImportSpecific].boundOb=NIL THEN TerminalIO.PutF["Object is an unbound import.\n"] ELSE PutRopes["Object Expressions of the bound import:\n", NARROW [CDProperties.GetObjectProp[NARROW [selected.ob.specific, CDImports.ImportSpecific].boundOb, Sisyph.expressionsProp]]]}; AddObjExpression: PROC [comm: CDSequencer.Command] = { exprs: ROPES; selected: CD.Instance _ TheCellInstance[comm.design, "AddObjExpression\n"]; IF selected=NIL THEN RETURN; exprs _ NARROW [CDProperties.GetObjectProp[selected.ob, Sisyph.expressionsProp]]; PutRopes["Add Object Expression. Previous Object Expressions:\n", exprs]; exprs _ CONS [TerminalIO.RequestRope[Rope.Cat[" New Expression: "]], exprs]; CDProperties.PutObjectProp[selected.ob, Sisyph.expressionsProp, exprs]}; EditObjExpressions: PROC [comm: CDSequencer.Command] = { exprs: ROPES; selected: CD.Instance _ TheCellInstance[comm.design, "EditObjExpressions\n"]; IF selected=NIL THEN RETURN; TerminalIO.PutF["Edit Object Expressions\n"]; exprs _ NARROW[CDProperties.GetObjectProp[selected.ob, Sisyph.expressionsProp]]; exprs _ EditExpressions[exprs, "Expression"]; CDProperties.PutObjectProp[selected.ob, Sisyph.expressionsProp, exprs]}; ShowParmNames: PROC [comm: CDSequencer.Command] = { selected: CD.Instance _ CDOps.TheInstance[comm.design, "ShowParmNames\n"]; -- not TheCellInstance for discovering old settings IF selected=NIL THEN RETURN; PutRopes["Parameter Names (0 for no parameter):\n", NARROW [CDProperties.GetObjectProp[selected.ob, Sisyph.parmNamesProp]]]}; SetParmName: PROC [comm: CDSequencer.Command] = { insts: LIST OF CD.Instance _ AllCellInstances[comm.design, "SetParmName\n"]; IF insts=NIL THEN RETURN; SELECT TerminalIO.RequestSelection["Setting Parameters", LIST ["Explicitly", "Implicitly"], "Better ABORT and click the doc if you do not know what you are doing ...", LIST ["All selected cells with get the specified parameters", "Automatic program setting parameters"]] FROM 1 => { parms: ROPES _ NIL; DO input: ROPE _ TerminalIO.RequestRope[" Parameter: "]; IF Rope.IsEmpty[input] THEN EXIT; parms _ CONS [input, parms]; ENDLOOP; WHILE insts#NIL DO TerminalIO.PutF["Setting parameters on cell %g.\n", IO.rope[CD.Describe[ob: insts.first.ob, design: comm.design]]]; CDProperties.PutObjectProp[insts.first.ob, Sisyph.parmNamesProp, parms]; insts _ insts.rest; ENDLOOP}; 2 => { IF TRUE THEN {TerminalIO.PutF["Not yet implemented.\n"]; RETURN}; WHILE insts#NIL DO name: ROPE = CDDirectory.Name[object: insts.first.ob, design: comm.design]; parms: ROPES; reasonForWorld: ROPE; [parms, reasonForWorld] _ ComputeParameters[comm.design, insts.first.ob, insts.first.properties]; IF reasonForWorld=NIL THEN { TerminalIO.PutF["Setting parameters on cell %g.\n", IO.rope[name]]; CDProperties.PutObjectProp[insts.first.ob, Sisyph.parmNamesProp, parms]} ELSE TerminalIO.PutF["*** Could not set parameters for cell %g because %g.\n", IO.rope[name], IO.rope[reasonForWorld]]; insts _ insts.rest; ENDLOOP}; ENDCASE => RETURN}; EditParmNames: PROC [comm: CDSequencer.Command] = { parms: ROPES; selected: CD.Instance _ TheCellInstance[comm.design, "EditParmNames\n"]; IF selected=NIL THEN RETURN; TerminalIO.PutF["Edit Object Expressions\n"]; parms _ NARROW [CDProperties.GetObjectProp[selected.ob, Sisyph.parmNamesProp]]; parms _ EditExpressions[parms, "Parameter"]; CDProperties.PutObjectProp[selected.ob, Sisyph.parmNamesProp, parms]}; sequenceKeyWords: SymTab.Ref _ SymTab.Create[5]; ParseSatellites: PROC [ropes: ROPES] RETURNS [keyword, expr: ROPE _ NIL, others: ROPES _ NIL] = { WHILE ropes#NIL DO tokenKind1, tokenKind2: IO.TokenKind; token1, token2: ROPE; rest: ROPE; [tokenKind1, token1, rest] _ Sisyph.ParseRope[ropes.first]; [tokenKind2, token2, rest] _ Sisyph.ParseRope[rest]; IF tokenKind1=tokenID AND SymTab.Fetch[sequenceKeyWords, token1].found AND Sisyph.IsParsedChar[tokenKind2, token2, ':] THEN IF keyword=NIL THEN {keyword _ token1; expr _ rest} ELSE {TerminalIO.PutF["*** SisyphExtractSequence: Conflicting sequencing satellites '%g:%g' and '%g'.\n", IO.rope[keyword], IO.rope[expr], IO.rope[ropes.first]]; ERROR} ELSE others _ CONS [ropes.first, others]; ropes _ ropes.rest; ENDLOOP}; FindPorts: PROC [baseCell: CellType, wires: Wires] RETURNS [set: CoreClasses.SequenceSet] = { nats: LIST OF NAT _ NIL; size: NAT _ 0; WHILE wires#NIL DO FOR w: NAT IN [0 .. baseCell.public.size) DO sequenceName: ROPE _ CoreOps.GetShortWireName[wires.first]; IF wires.first=baseCell.public[w] OR (sequenceName#NIL AND Rope.Equal[sequenceName, CoreOps.GetShortWireName[baseCell.public[w]]]) THEN { nats _ CONS [w, nats]; size _ size + 1; EXIT}; REPEAT FINISHED => ERROR; ENDLOOP; wires _ wires.rest; ENDLOOP; set _ NEW [CoreClasses.SequenceSetRec[size]]; FOR i: INT IN [0 .. size) DO set[i] _ nats.first; nats _ nats.rest ENDLOOP}; ExtractSequence: Sinix.ExtractProc = { name: ROPE _ mode.nameProc[obj, userData]; cx: Sisyph.Context; keyword, expr: ROPE; others: ROPES; cellType: CellType; count: NAT; [keyword, expr, others] _ ParseSatellites[NARROW [CDProperties.GetObjectProp[obj, Sinix.satellitesProp]]]; IF keyword=NIL THEN { TerminalIO.PutF["*** SisyphExtractSequence: Sequence does not contain any of sequencing information (e.g. an object satellite 'SeqX: 32').\n"]; ERROR}; CDProperties.PutObjectProp[obj, Sinix.satellitesProp, others]; cx _ Sisyph.EvaluateParameters[userData, obj, properties]; Sisyph.EvalExpr[cx, keyword, expr, FALSE]; count _ NAT [Sisyph.FetchInt[cx, keyword].value]; Sinix.PutF["Extracting [Sisyph] cell %g (%g: %g)\n", IO.rope[name], IO.rope[keyword], IO.int[count]]; name _ Rope.Substr[name, 0, Rope.Index[name, 0, ".sch"]]; -- hack name _ Rope.Substr[name, 0, Rope.Index[name, 0, ".icon"]]; -- hack cellType _ ExtractSequenceIcon[obj, cx, keyword, count, name, Sisyph.GetCoreProps[cx]]; props _ Sisyph.GetCoreInstProps[cx]; result _ cellType}; ExtractSequenceIcon: PROC [obj: CD.Object, cx: Sisyph.Context, resultVar: ROPE, count: NAT, name: ROPE, props: Core.Properties] RETURNS [sequence: CellType] = { iconCT: CellType = NARROW [Sinix.ExtractCell[obj, Sisyph.mode, NIL, cx].result]; iconRCT: CoreClasses.RecordCellType = NARROW [iconCT.data]; subCT: CellType; layoutAtom: REF; sequenceWires, flatSequenceWires: Wires _ NIL; IF iconRCT.size#1 THEN { TerminalIO.PutF["*** SisyphExtractSequence: Sequence should contain one and only one subcell.\n"]; ERROR}; subCT _ iconRCT[0].type; Sisyph.ProcessGlobalNames[iconCT, cx]; FOR i: NAT IN [0 .. iconRCT.internal.size) DO wire: Wire = iconRCT.internal[i]; name: ROPE _ CoreOps.GetShortWireName[wire]; IF name=NIL THEN name _ "some wire"; IF NOT CoreOps.RecursiveMember[iconRCT[0].actual, wire] THEN { TerminalIO.PutF["*** SisyphExtractSequence: %g is not connected to subcell.\n", IO.rope[name]]; ERROR}; IF NOT CoreOps.RecursiveMember[iconCT.public, wire] THEN { TerminalIO.PutF["*** SisyphExtractSequence: %g is not public.\n", IO.rope[name]]; ERROR}; ENDLOOP; FOR i: NAT IN [0 .. subCT.public.size) DO IF CoreProperties.GetWireProp[iconRCT[0].actual[i], $Sequence]#NIL THEN sequenceWires _ CONS [subCT.public[i], sequenceWires]; IF CoreProperties.GetWireProp[iconRCT[0].actual[i], $FlatSequence]#NIL THEN flatSequenceWires _ CONS [subCT.public[i], flatSequenceWires]; ENDLOOP; sequence _ CoreClasses.CreateSequence[ args: NEW [CoreClasses.SequenceCellTypeRec _ [ base: subCT, count: count, sequence: FindPorts[subCT, sequenceWires], flatSequence: FindPorts[subCT, flatSequenceWires] ]], name: name, props: props ]; FOR i: NAT IN [0..sequence.public.size) DO iconWire: Wire = CoreClasses.CorrespondingActual[iconRCT[0], subCT.public[i]]; CopyWireProperties[from: iconWire, to: sequence.public[i]] ENDLOOP; CoreGeometry.PutObject[Sisyph.mode.decoration, sequence, obj]; layoutAtom _ SymTab.Fetch[sequenceKeyWords, resultVar].val; IF layoutAtom#NIL THEN CoreProperties.PutCellTypeProp[sequence, $Layout, layoutAtom]; }; CopyWireProperties: PROC[from, to: Wire] = { eachProp: PROC[atom:ATOM, ref: REF] = {CoreProperties.PutWireProp[to, atom, ref]}; CoreProperties.Enumerate[from.properties, eachProp]}; ComputeParameters: PROC [design: CD.Design, obj: CD.Object, properties: CD.PropList] RETURNS [parms: ROPES, reasonForWorld: ROPE _ NIL] = { cx: Sisyph.Context _ SymTab.Create[11]; parms _ NARROW [CDProperties.GetObjectProp[obj, Sisyph.parmNamesProp]]; IF parms#NIL THEN RETURN; Sisyph.Store[cx, "design", NEW [CD.Design _ design]]; Sisyph.Insert[cx, "globalNames", NEW [ROPES _ Sisyph.defaultGlobalNames]]; [] _ Sinix.Extract[ obj: obj, mode: Sisyph.mode, properties: properties, userData: cx ! ANY => {reasonForWorld _ "???"; GOTO Return} ]; parms _ LIST ["0"]; EXITS Return => RETURN}; PutRopes: PROC [rope: ROPE, ropes: ROPES] = { TerminalIO.PutF[rope]; WHILE ropes#NIL DO TerminalIO.PutF["\t%g\n", IO.rope[ropes.first]]; ropes _ ropes.rest; ENDLOOP}; TheCellInstance: PROC [design: CD.Design, text: ROPE _ NIL] RETURNS [inst: CD.Instance _ NIL] = { inst _ CDOps.TheInstance[design, text]; IF inst=NIL OR CDCells.IsCell[inst.ob] THEN RETURN; TerminalIO.PutF["*** Selected instance is not a cellcan't do it.\n"]; inst _ NIL}; AllCellInstances: PROC [design: CD.Design, text: ROPE _ NIL] RETURNS [insts: LIST OF CD.Instance _ NIL] = { IF text#NIL THEN TerminalIO.PutRope[text]; FOR w: CD.InstanceList _ CDOps.InstList[design], w.rest WHILE w#NIL DO IF NOT w.first.selected THEN LOOP; IF NOT CDCells.IsCell[w.first.ob] THEN {TerminalIO.PutRope[" selection is not a cell; failed\n"]; RETURN [NIL]}; insts _ CONS [w.first, insts]; ENDLOOP; IF insts=NIL THEN TerminalIO.PutRope[" no selection; failed\n"]}; CleanUpIconProperties: PROC [obj: CD.Object] = { Sinix.FlushCache[obj]; CDProperties.PutObjectProp[obj, $IconFor, NIL]; CDProperties.PutObjectProp[obj, $CodeFor, NIL]; CDProperties.PutObjectProp[obj, Sisyph.mode.extractProcProp, NIL]; CDProperties.PutObjectProp[obj, Sisyph.expressionsProp, StripResultExprs [NARROW [CDProperties.GetObjectProp[obj, Sisyph.expressionsProp]]]] }; StripResultExprs: PROC [in: ROPES] RETURNS [out: ROPES _ NIL] = { FOR l: ROPES _ in, l.rest WHILE l#NIL DO expr: ROPE _ l.first; IF NOT Rope.Match[expr, "*cI*_*"] AND NOT Rope.Match[expr, "*wI*_*"] AND NOT Rope.Match[expr, "*wire*_*"] THEN out _ CONS [expr, out] ENDLOOP}; EditExpressions: PROC [oldExprs: ROPES, prompt: ROPE] RETURNS [allExprs: ROPES _ NIL] = { input: ROPE; noOldExprs: BOOL _ oldExprs=NIL; TerminalIO.PutF["\n"]; WHILE oldExprs#NIL DO input _ TerminalIO.RequestRope[Rope.Cat[" ", prompt, ": ", oldExprs.first, " Replacement: "]]; SELECT TRUE FROM Rope.Equal[input, "-"] => TerminalIO.PutF[" ** Deleted\n"]; Rope.IsEmpty[input] => allExprs _ CONS [oldExprs.first, allExprs]; ENDCASE => allExprs _ CONS [input, allExprs]; oldExprs _ oldExprs.rest; ENDLOOP; IF noOldExprs THEN { input _ TerminalIO.RequestRope[Rope.Cat[" New ", prompt, ": "]]; WHILE ~Rope.IsEmpty[input] AND ~Rope.Equal[input, "-"] DO allExprs _ CONS [input, allExprs]; input _ TerminalIO.RequestRope[Rope.Cat[" New ", prompt, ": "]]; ENDLOOP}; allExprs _ RopeList.Reverse[allExprs]}; MatchProc: TYPE = PROC [old: ROPE] RETURNS [BOOL]; MatchTransistor: MatchProc = {RETURN [Rope.Match["*CreateTransistor[[*", old]]}; MatchAmpersand: MatchProc = {RETURN [Rope.Match["*&*_*", old]]}; MatchName: MatchProc = {RETURN [Rope.Match["name _ \"*\"", old]]}; MatchSchCI: MatchProc = {RETURN [Rope.Match["*cI*_*ES[\"*\",*cx]", old]]}; MatchCodeCI: MatchProc = {RETURN [Rope.Match["*cI*_*", old]]}; MatchCodeWI: MatchProc = {RETURN [Rope.Match["*wI*_*", old]]}; MatchWire: MatchProc = {RETURN [Rope.Match["*wire*_*", old]]}; MatchDeclare: MatchProc = {RETURN [Rope.Match[ "*Sisyph.Store[cx,*\"*\",*NEW[*_*]]", old]]}; Change: PROC [master: REF, location: ROPE] RETURNS [needInteraction: ROPE _ NIL] = { news: ROPES; CDProperties.PutProp[master, $CameFrom, NIL]; CDProperties.PutProp[master, $OriginalName, NIL]; CDProperties.PutProp[master, $CDBringoverLibraryName, NIL]; CDProperties.PutProp[master, $SisyphArguments, NIL]; FOR list: ROPES _ NARROW [CDProperties.GetProp[master, Sisyph.expressionsProp]], list.rest WHILE list#NIL DO old: ROPE = list.first; SELECT TRUE FROM MatchName[old] => { new: ROPE = Rope.Substr[old, 8, Rope.Length[old]-9]; TerminalIO.PutF["changed '%g' to '%g'.\n", IO.rope[old], IO.rope[new]]; news _ CONS [new, news]; }; MatchSchCI[old] => { pos1: INT _ Rope.Find[old, "\""]; pos2: INT _ Rope.Find[old, "\"", pos1+1]; sch: ROPE = Rope.Substr[old, pos1+1, pos2-pos1-1]; TerminalIO.PutF["changed '%g' to an $IconFor property '%g'.\n", IO.rope[old], IO.rope[sch]]; CDProperties.PutProp[master, $IconFor, sch]; CDProperties.PutProp[master, Sisyph.mode.extractProcProp, $SisyphExtractCellIcon]}; MatchCodeCI[old] => { code: ROPE = Rope.Substr[old, Rope.Find[old, "_"]+1]; TerminalIO.PutF["changed '%g' to an $CodeFor property '%g'.\n", IO.rope[old], IO.rope[code]]; CDProperties.PutProp[master, $IconFor, NIL]; -- because $IconFor was not the truth in CD24! CDProperties.PutProp[master, $CodeFor, code]; CDProperties.PutProp[master, Sisyph.mode.extractProcProp, $SisyphExtractCellIcon]}; MatchCodeWI[old] => { code: ROPE = Rope.Substr[old, Rope.Find[old, "_"]+1]; TerminalIO.PutF["changed '%g' to an $CodeFor property '%g'.\n", IO.rope[old], IO.rope[code]]; CDProperties.PutProp[master, $CodeFor, code]; CDProperties.PutProp[master, Sisyph.mode.extractProcProp, $SisyphExtractNamedWireIcon]}; MatchWire[old] OR MatchTransistor[old] => { TerminalIO.PutF["*** Found expression %g '%g' that is not converted automatically.\n", IO.rope[location], IO.rope[old]]; news _ CONS [old, news]}; MatchAmpersand[old] => { TerminalIO.PutF["*** Found expression %g '%g' that uses a variable starting with '&'.\n", IO.rope[location], IO.rope[old]]; news _ CONS [old, news]}; MatchDeclare[old] => { pos1: INT _ Rope.Find[old, "\""]; pos2: INT _ Rope.Find[old, "\"", pos1+1]; pos3: INT _ Rope.Find[old, "_", pos2+1]; pos4: INT _ Rope.Find[old, "]", pos3+1]; new: ROPE _ Rope.Cat[Rope.Substr[old, pos1+1, pos2-pos1-1], " ~ ", Rope.Substr[old, pos3+1, pos4-pos3-1]]; TerminalIO.PutF["changed '%g' to '%g'.\n", IO.rope[old], IO.rope[new]]; news _ CONS [new, news]}; ENDCASE => news _ CONS [old, news]; ENDLOOP; CDProperties.PutProp[master, Sisyph.expressionsProp, news]; IF MatchTransistor[NARROW [CDProperties.GetProp[master, $CodeFor]]] THEN TerminalIO.PutF["*** Found $CodeFor %g '%g' that cannot be converted automatically.\n", IO.rope[location], IO.rope[NARROW [CDProperties.GetProp[master, $CodeFor]]]]; IF CDProperties.GetProp[master, $CodeFor]#NIL AND CDProperties.GetProp[master, $IconFor]#NIL THEN TerminalIO.PutF["*** Found both $CodeFor and $IconFor %g. $CodeFor is probably the truth, but check that carefully!\n", IO.rope[location]]; FOR list: ROPES _ CDSatellites.GetSatelliteRopes[master], list.rest WHILE list#NIL DO old: ROPE = list.first; SELECT TRUE FROM MatchName[old] OR MatchSchCI[old] OR MatchCodeCI[old] OR MatchCodeWI[old] OR MatchWire[old] OR MatchDeclare[old] OR MatchTransistor[old] OR MatchAmpersand[old] => { needInteraction _ Rope.Cat["'", old, "' ", needInteraction]}; ENDCASE => {}; ENDLOOP}; Convert: PROC [comm: CDSequencer.Command] = { design: CD.Design = comm.design; EachObj: CDDirectory.EachObjectProc = { EachInst: CDCells.InstEnumerator = { needInteraction _ Change[inst, Rope.Cat["in ", name]]; IF needInteraction#NIL THEN TerminalIO.PutF["*** Some instance satellite(s) in %g need to be changed: %g.\n", IO.rope[name], IO.rope[needInteraction]]}; name: ROPE _ CDDirectory.Name[me, design]; needInteraction: ROPE _ Change[me, Rope.Cat["of ", name]]; IF needInteraction#NIL THEN TerminalIO.PutF["*** Some object satellite(s) of %g need to be changed: %g.\n", IO.rope[name], IO.rope[needInteraction]]; IF NOT CDCells.IsCell[me] THEN RETURN; [] _ CDCells.EnumerateInstances[me, EachInst]}; [] _ CDDirectory.EnumerateDesign[design, EachObj]; TerminalIO.PutF["\n*** Converted! Save the design\n"]}; NoDummiesInDir: PROC [comm: CDSequencer.Command] ~ { design: CD.Design = comm.design; n: INT _ 0; elem: TYPE ~ RECORD [ob: CD.Object, name: ROPE]; EachEntry: CDDirectory.EachEntryAction ~ { IF Rope.Match[pattern: "-no name*", object: name] OR -- style 1 `unnamed' object Rope.Match[pattern: "-noname-*", object: name] OR -- style 2 `unnamed' object Rope.Match[pattern: "/@*", object: name] OR -- twiddled SequencingSlash CDImports.IsImport[ob] -- Import THEN remove _ CONS [[ob, name], remove]}; remove: LIST OF elem; IF CDDirectory.Enumerate[design, EachEntry] THEN ERROR; WHILE remove#NIL DO -- remove them all, check that the name/object relation is OK n _ n+1; IF CDDirectory.Remove[design, remove.first.name, remove.first.ob]=NIL THEN ERROR; remove _ remove.rest; ENDLOOP; TerminalIO.PutF["\n%g objects made anonymous! Save the design!\n", IO.int[n]]}; ICom: PROC[ key: ATOM, proc: CDSequencer.CommandProc, queue: CDSequencer.QueueMethod _ doQueueAndMark ] = {CDSequencer.ImplementCommand[key, proc, NIL, queue]}; CDCommandOps.RegisterWithMenu [$Debug, "SisyphConvert", "Convert to new Sisyph syntax", $SisyphConvert, Convert, doQueueAndMark]; CDCommandOps.RegisterWithMenu [$Debug, "Get rid of -no name-*", "Remove from directory all entries for unnamed objects and imports", $SisyphNoDummiesInDir, NoDummiesInDir, doQueueAndMark]; [] _ SymTab.Store[sequenceKeyWords, "Seq", NIL]; [] _ SymTab.Store[sequenceKeyWords, "SeqX", $ArrayX]; [] _ SymTab.Store[sequenceKeyWords, "SeqY", $ArrayY]; [] _ SymTab.Store[sequenceKeyWords, "RSeqX", $ReverseArrayX]; [] _ SymTab.Store[sequenceKeyWords, "RSeqY", $ReverseArrayY]; Sinix.RegisterExtractProc[$SisyphExtractSequence, ExtractSequence]; ICom[key: $FlushSisyphCaches, proc: FlushSisyphCaches, queue: doQueue]; SinixOps.RegisterModeCommands[mode: Sisyph.mode]; ICom[key: $MakeCellIcon, proc: MakeCellIcon, queue: doQueueAndMark]; ICom[key: $MakeWireIcon, proc: MakeWireIcon, queue: doQueueAndMark]; ICom[key: $MakeSequenceIcon, proc: MakeSequenceIcon, queue: doQueueAndMark]; ICom[key: $UnMakeIcon, proc: UnMakeIcon, queue: doQueueAndMark]; ICom[key: $MakeInvisibleToExtractor, proc: MakeInvisibleToExtractor,queue: doQueueAndMark]; ICom[key: $MakeVisibleToExtractor, proc: MakeVisibleToExtractor, queue: doQueueAndMark]; ICom[key: $SisyphShowParmNames, proc: ShowParmNames, queue: doQueue]; ICom[key: $SisyphSetParmName, proc: SetParmName]; ICom[key: $SisyphEditParmNames, proc: EditParmNames]; ICom[key: $SisyphShowInstExpressions, proc: ShowInstExpressions, queue: doQueue]; ICom[key: $SisyphAddInstExpression, proc: AddInstExpression, queue: doQueueAndMark]; ICom[key: $SisyphEditInstExpressions, proc: EditInstExpressions, queue: doQueueAndMark]; ICom[key: $SisyphShowObjExpressions, proc: ShowObjExpressions, queue: doQueue]; ICom[key: $SisyphAddObjExpression, proc: AddObjExpression, queue: doQueueAndMark]; ICom[key: $SisyphEditObjExpressions, proc: EditObjExpressions, queue: doQueueAndMark]; END. ��t��SisyphCmdsImpl.mesa Copyright Ó 1985, 1986, 1987 by Xerox Corporation. All rights reserved. Created by Pradeep Sindhu, December 9, 1985 10:01:52 pm PST Pradeep Sindhu, September 26, 1986 2:06:15 pm PDT Barth, January 13, 1986 3:30:05 pm PST Bertrand Serlet April 28, 1988 12:23:59 pm PDT Jean-Marc Frailong December 9, 1987 6:50:30 pm PST Last Edited by: Jacobi July 15, 1986 2:40:48 pm PDT Don Curry January 20, 1988 3:43:54 pm PST Icon Commands Other Commands Sequence Icons There should be only one subcell We deal with Global Variables we check that there is no internal only We compute which wires are going to be sequenced We create the sequence New code to copy properties from the extracted public to the new sequence public. The object decoration! We decorate with the appriopriate layout atom Computing Parameters This function is, of course, slightly fancy ... Not really working, either! Internal Utilities Soon obsolete? Convertion code Remove from directory all entries for unnamed objects and imports. Returns number of removed objects. Initialization FilterSch: SinixOps.FilterProc = {RETURN [Rope.Match["*.sch", name] OR Rope.Match["*.icon", name]]}; Convertion Filling the Layout atoms for sequences At this point, there is a strange dependency between Sisyph and PWCore, but it is not worth the effort making a separate module Main Menu SinixOps.RegisterBackgroundExtractionCommand[CD.FetchTechnology[$cmosB], Sisyph.mode, "Sch background extraction", $SchBackgroundExtract, FilterSch]; -- only works for CMosB. Not very clean Make Icon Menu Change Visibility Menu Make Parameter Menu (normally hidden) Expressions Menu �ʬ��˜�™JšœH™HJšœ8Ïk™;Jšœ.™1Jšœ#™&Jšœ.™.Jšœ/™2Jšœ0™3Jšœ&™)—J™�š ˜ Jšœ`˜bJšœ9˜9Jšœ˜Jšœ!˜!Jšœ˜J˜�—šÏnœœ˜Jšœœ•œ=˜ÞJšœ˜J™�Jšœœœ˜Jš œœœœœ˜Jšœœ ˜Jšœœ˜Jšœ œ˜—head™ šž œœ ˜0Jšœ œ9˜EJšœ œœœ˜Jšœ#˜#šœ˜Jšœœ5˜T—J˜�—šžœœ ˜2Jšœœ˜ Jšœœ˜Jšœ œ;˜GJšœ œœœ˜Jšœ2˜2šœœ˜"JšœO˜S—šœAœKœH˜æšœ˜Jšœ=˜=Jšœ˜—šœ˜Jšœ7˜7šœœ˜5JšœE˜I—šœ&œœ˜2Jšœ3œ ˜BJšœ˜—šœœ˜ JšœD˜DJšœ˜—JšœœœS˜xJšœ˜Jšœ.œ œ˜M—Jšœ)œ˜8—Jšœ#˜#Jšœ3˜3Jšœ_˜_J˜�—šžœœ ˜2Jšœœ˜ Jšœœ˜Jšœœ˜Jšœ œ;˜GJšœ œœœ˜Jšœ2˜2šœœ˜"JšœO˜S—šœ%˜%Jšœ$˜$Jšœa˜eJšœ)˜)Jšœ†˜Š—šœ˜šœ ˜ Jšœ=˜=Jšœ˜—šœ ˜ Jšœ7˜7šœœ˜5JšœE˜I—šœ&œœ˜2Jšœ3œ ˜BJšœ˜—šœœ˜ JšœD˜DJšœ˜—JšœœœS˜xJšœ˜Jšœ.œ œ˜M—Jšœ)œ˜8—Jšœ#˜#Jšœ3˜3Jš œEœœMœœ˜¸J˜�—šžœœ ˜6Jšœ œ?˜KJšœ œœœ˜Jšœ#˜#Jšœ]˜]JšœFœœ\˜¬Jšœ,œ5˜c——™šžœœ ˜>Jšœœ˜š œœœœ0œœ˜OJšœœ˜šœœ˜JšœN˜NJšœ˜Jšœ"˜"—Jšœ˜—Jšœ;œ˜RJ˜�—šžœœ ˜<Jšœœ˜š œœœœ0œœ˜OJšœœ˜šœœ˜Jšœ@œ˜EJšœ˜Jšœ!˜!—Jšœ˜—Jšœ9œ˜OJ˜�—šž œœ œœ˜8Jšœœ!˜+Jšœ œ-˜9Jšœ œœœœœœœœ˜IJš œœ œ œœ$œœ˜QJšžœ9˜JJšœœœœœœ#˜ršœ7œœ4œœœ˜…Jšœ#œÏcM˜„—Jšœ˜šœ˜Jšœ9˜=—šœœ˜Jšœ˜—J˜�—šžœœ ˜7š œœœœ0œœ˜OJšœœ%˜=Jšœ˜ —J˜�—šžœœ ˜9Jšœ œD˜PJšœ œœœ˜Jšœ$œD˜nJ˜�—šžœœ ˜7Jšœœ˜ Jšœ œB˜NJšœ œœœ˜JšœœB˜PJšœN˜NJšœœA˜MJšœG˜GJ˜�—šžœœ ˜9Jšœœ˜ Jšœ œD˜PJšœ œœœ˜Jšœ/˜/JšœœA˜OJ˜-JšœG˜GJ˜�—šžœœ ˜8Jšœ œC˜OJšœ œœœ˜Jšœ"œD˜lJšœœ!œœ˜3šœœ:œ˜GJšœ2˜6Jšœ7œœV˜º—J˜�—šžœœ ˜6Jšœœ˜ Jšœ œ?˜KJšœ œœœ˜JšœœC˜QJšœJ˜JJšœœA˜MJšœH˜HJ˜�—šžœœ ˜8Jšœœ˜ Jšœ œA˜MJšœ œœœ˜Jšœ-˜-JšœœB˜PJ˜-JšœH˜HJ˜�—šž œœ ˜3Jšœ œ?Ÿ3˜~Jšœ œœœ˜Jšœ4œC˜}J™�—šžœœ ˜1Jšœœœœ;˜LJšœœœœ˜šœ3œkœc˜“˜Jšœœœ˜š˜Jšœœ+˜6Jšœœœ˜!Jšœœ˜Jšœ˜—šœœœ˜Jšœ4œœ5˜sJšœI˜IJšœ˜Jšœ˜ ——˜Jšœœœ-œ˜Ašœœœ˜J•StartOfExpansion*[object: CD.Object, design: CD.Design]šœœA˜KJšœœœ˜#Jšœa˜ašœ˜šœ˜Jšœ4œ ˜CJšœH˜H—JšœKœ œ˜w—Jšœ˜Jšœ˜ ——Jšœœ˜—J™�—šž œœ ˜3Jšœœ˜ Jšœ œ<˜HJšœ œœœ˜Jšœ-˜-JšœœA˜OJ˜,JšœF˜F——™šœ0˜0J˜�—šžœœ œ˜$Jš œœœ œœ˜<šœœ˜Jšœœœœ˜GJšœ;˜;Jšœ4˜4šœœ.œ-˜wšœœ œ˜Jšœ!˜%Jš œfœœ œœ˜¨—Jšœ œ˜)—Jšœ˜Jšœ˜ —J˜�—šž œœ$œ#˜]Jš œœœœœ˜Jšœœ˜šœœ˜šœœœ˜,Jšœœ*˜<š œ œœœIœ˜‰Jšœœ˜'Jšœ˜—Jšœœœ˜Jšœ˜ —Jšœ˜Jšœ˜—Jšœœ$˜-Jš œœœ œ'œ˜LJ˜�—šžœ˜&Jšœœ ˜*Jšœ˜Jšœœ˜Jšœœ˜Jšœ˜Jšœœ˜Jšœ*œ:˜jšœ œœ˜Jšœ˜Jšœ˜—Jšœ>˜>Jšœ:˜:Jšœ#œ˜*Jšœœ&˜1Jšœ5œ œœ ˜eJšœ:Ÿ˜AJšœ;Ÿ˜BJšœX˜XJ˜$Jšœ˜J˜�—–¡ -- [obj: CD.Object, mode: Sinix.Mode, properties: PropertyLists.PropList _ NIL, userData: REF ANY _ NIL] RETURNS [result: REF ANY, props: Core.Properties _ NIL]šžœ˜Jšœœ(œ œœœ˜†Jšœœ&œ˜PJšœ&œ˜;Jšœ˜Jšœœ˜Jšœ*œ˜.Jšœ ™ šœœ˜Jšœb˜bJšœ˜—Jšœ˜J™Jšœ&˜&Jšœ'™'šœœœ˜-Jšœ!˜!Jšœœ"˜,Jšœœœ˜$šœœ2œ˜>JšœPœ ˜_Jšœ˜—šœœ.œ˜:JšœBœ ˜QJšœ˜—Jšœ˜—Jšœ0™0šœœœ˜)šœ=œ˜CJšœœ"˜;—šœAœ˜GJšœœ&˜C—Jšœ˜—Jšœ™šœ&˜&šœœ%˜.Jšœ˜Jšœ+˜+Jšœ5˜5—Jšœ˜—J™Qšœœœ˜*JšœN˜NJšœ;œ˜C—J™Jšœ>˜>J™-Jšœ;˜;Jšœœœ?˜UJšœ˜J˜�—šžœœ˜,Jšœ œœœ0˜RJšœ5˜5——™Jšœ/™/J™šžœœ œœœœ œœœ˜‹Jšœ'˜'Jšœœ9˜GJšœœœœ˜Jšœœœ˜5Jšœ!œœ˜Jšœ˜JšœB˜BJšœœœ˜2—Jšœœ˜Jšœœ˜——™šžœœœ œ˜-Jšœ˜šœœ˜Jšœœ(˜DJšœ˜ —J˜�—š žœœ œœœ˜;Jšœœœ˜%Jšœ'˜'Jš œœœœœ˜3JšœF˜FJšœœ˜J˜�—š žœœ œœœ˜<Jš œ œœœœ˜.Jšœœœ˜*š œœ/œœ˜FJšœœœœ˜#šœœ˜"Jšœ>œœ˜P—Jšœœ˜Jšœ˜—Jšœœœ2˜CJ˜�—šžœœœ˜0Jšœ˜Jšœ*œ˜/Jšœ*œ˜/Jšœ=œ˜BšœH˜HJšœœ?˜F—J˜�—JšÏb™šžœœœœœœ˜Aš œœœœ˜(Jšœœ˜Jšœœœœœœœœ˜…Jšœ˜ —J˜�—šžœœœ œœœœ˜YJšœœ˜Jšœœœ˜ Jšœ˜šœ œ˜Jšœ`˜`šœœ˜Jšœ<˜<Jšœ"œ˜BJšœœ˜-—J˜Jšœ˜—šœœ˜JšœA˜Ašœœ˜9Jšœœ˜"JšœA˜AJšœ˜ ——Jšœ'˜'——™Jšœœœœœœ˜2Jšžœœ,˜QJšžœœ˜@Jšž œœ$˜DJšž œœ+˜LJšžœœ˜@Jšžœœ˜@Jšž œœ ˜Ašžœœ;˜^J˜�—šžœœ œœœœœ˜TJšœœ˜Jšœ(œ˜-Jšœ,œ˜1Jšœ6œ˜;Jšœ/œ˜4šœœœCœœ˜lJšœœ˜šœœ˜šœ˜Jšœœ+˜4Jšœ+œœ˜GJšœœ ˜J˜—šœ˜Jšœœ˜!Jšœœ ˜)Jšœœ)˜2Jšœ@œœ˜\Jšœ,˜,JšœS˜S—šœ˜Jšœœ+˜5Jšœ@œœ ˜]Jšœ'œŸ.˜[Jšœ-˜-JšœS˜S—šœ˜Jšœœ+˜5Jšœ@œœ ˜]Jšœ-˜-JšœX˜X—šœœ˜+JšœWœœ˜xJšœœ˜—šœ˜JšœZœœ˜{Jšœœ˜—šœ˜Jšœœ˜!Jšœœ ˜)Jšœœ˜(Jšœœ˜(Jšœœa˜jJšœ+œœ˜GJšœœ˜—Jšœœ ˜$—Jšœ˜—Jšœ;˜;Jšœœ+œYœœœ,˜îJšœ(œœ(œœzœ˜îš œœ5œœ˜UJšœœ˜šœœ˜šœœœœœœœœ˜¤Jšœ=˜=—Jšœ ˜—Jšœ˜ —J˜�—šžœœ ˜-Jšœœ˜ šžœ ˜'šžœ˜$Jšœ6˜6Jš œœœSœ œ˜˜—Jšœœ ˜*Jšœœ%˜:Jš œœœQœ œ˜•Jšœœœœ˜&Jšœ/˜/—Jšœ2˜2Jšœ8˜8J˜�—šžœœ ˜4J™eJšœœ˜ Jšœœ˜Jš œœœœœ˜0šž œ!˜*šœ0œŸ˜PJšœ/œŸ˜MJšœ)œŸ˜GJšœŸ ˜ Jšœ œ˜)——Jšœœœ˜Jšœ*œœ˜7šœœœŸ=˜QJ˜Jšœ@œœœ˜QJšœ˜Jšœ˜—JšœDœ ˜P——™šžœœ˜Jšœœ˜Jšœ˜šœ3˜3Jšœ)œ ˜6——J˜�šž œ™ Jšœœœ™C—K™ šœ˜Jšœc˜c—šœ˜Jšœž˜ž—K™&Jšœ™Jšœ+œ˜0Jšœ5˜5Jšœ5˜5Jšœ=˜=Jšœ=˜=K™ JšœC˜CJšœG˜GJšœ1˜1Jšœ-œgŸ(™¾K™JšœH˜HJšœG˜GJšœL˜LJšœD˜DK™Jšœ[˜[JšœX˜XK™%JšœE˜EJšœ2˜2Jšœ5˜5K™JšœQ˜QJšœT˜TJšœX˜XJšœO˜OJšœS˜SJšœV˜VJ˜�—Jšœ ˜—�…—����jè��Œ��