DIRECTORY AMBridge, Asserting, Basics, Convert, FS, GList, InterpreterOps, IntHashTable, IO, LichenArrayStuff, Collections, LichenDataOps, LichenDataStructure, IntFunctions, IntStuff, LichenNavigation, PairCollections, LichenPrinting, List, Rope, StructuredStreams, SymTab, TiogaAccess, UnparserBuffer, ViewerIO; LichenData2Impl: CEDAR PROGRAM IMPORTS AMBridge, Asserting, Convert, FS, InterpreterOps, IO, LichenArrayStuff, Collections, LichenDataOps, LichenDataStructure, IntFunctions, LichenNavigation, PairCollections, List, Rope, StructuredStreams, TiogaAccess, UnparserBuffer EXPORTS LichenDataStructure, LichenPrinting = BEGIN OPEN LichenDataOps, LichenDataStructure, LichenArrayStuff, Colls:Collections, PairColls:PairCollections, Ints:IntStuff, IntFns:IntFunctions, SS:StructuredStreams, UB:UnparserBuffer; DimName: ARRAY Dim OF ROPE = [Foo: "Foo", Bar: "Bar"]; EndName: ARRAY End OF ROPE = [low: "low", high: "high"]; step: ROPE = "."; Describe: PUBLIC PROC [subject: REF ANY, relativeTo: REF ANY _ NIL, nameGen: NameGenerator _ NIL] RETURNS [name: ROPE] = { name _ UnparseSteppyName[SteppyDescribe[subject, relativeTo, nameGen]]; RETURN}; SteppyDescribe: PUBLIC PROC [subject: REF ANY, relativeTo: REF ANY _ NIL, nameGen: NameGenerator _ NIL] RETURNS [name: SteppyName] = { GetShort: PROC [oldAssns: Assertions] RETURNS [newAssns: Assertions, name: ROPE] = { name _ NARROW[Asserting.FnVal[nameReln, newAssns _ oldAssns]]; IF name = NIL THEN { name _ nameGen.GenerateName[nameGen.data, subject]; WITH subject SELECT FROM v: Vertex => KnowVertexName[v, LIST[name]]; ENDCASE => newAssns _ Asserting.Assert1[nameReln, name, newAssns]; name _ name}; RETURN}; IF nameGen = NIL THEN nameGen _ defaultNameGen; IF subject = relativeTo THEN name _ NIL ELSE WITH subject SELECT FROM d: Design => { short: ROPE; [d.other, short] _ GetShort[d.other]; name _ LIST[short]; RETURN}; ct: CellType => { short: ROPE; [ct.otherPublic, short] _ GetShort[ct.otherPublic]; name _ LIST[short]; IF ct.designs.HasMember[relativeTo] OR ct.designs.Size[]=0 THEN NULL ELSE name _ List.Append[SteppyDescribe[GetADesign[ct], relativeTo, nameGen], name]; RETURN}; v: Vertex => { parent: REF ANY; IF v.VertexNames.Size[]=0 THEN KnowVertexName[v, name _ LIST[nameGen.GenerateName[nameGen.data, subject]]] ELSE name _ NARROW[v.VertexNames.First[].val]; WITH v SELECT FROM ci: CellInstance => parent _ v.containingCT; im: Intermediary => parent _ ImParent[im]; w: Wire => parent _ WireContainer[w]; ENDCASE => ERROR; IF relativeTo#parent AND parent#NIL THEN name _ List.Append[SteppyDescribe[parent, relativeTo, nameGen], name]; RETURN}; port: Port => { parent: REF ANY ~ port.parent; IF port.PortNames.Size[]=0 THEN [] _ port.PortNames.AddElt[name _ LIST[nameGen.GenerateName[nameGen.data, subject]]] ELSE name _ NARROW[port.PortNames.First[].val]; IF relativeTo#parent AND parent#NIL THEN name _ List.Append[SteppyDescribe[parent, relativeTo, nameGen], name]; RETURN}; ENDCASE => ERROR; }; GetADesign: PROC [ct: CellType] RETURNS [d: Design] = { See: PROC [ra: REF ANY] = {d _ NARROW[ra]}; IF ct.designs.Size[] = 0 THEN RETURN [NIL]; ct.designs.Enumerate[See]; }; WireContainer: PROC [w: Wire] RETURNS [container: REF ANY] = { container _ SELECT w.containingWire FROM NIL => w.containingCT, ENDCASE => w.containingWire; }; defaultNameGen: NameGenerator = NEW [NameGeneratorPrivate _ [ GenerateBlandName, NEW [NameCountsPrivate _ []] ]]; NameCounts: TYPE = REF NameCountsPrivate; NameCountsPrivate: TYPE = RECORD [ design, cellType, port, vertex: INT _ 0 ]; GenerateBlandName: PROC [data, subject: REF ANY] RETURNS [name: ROPE] = { nc: NameCounts = NARROW[data]; name _ GenByCount[nc, subject]; }; TVNameGenerator: TYPE = REF TVNameGeneratorPrivate; TVNameGeneratorPrivate: TYPE = RECORD [ nc: NameCounts, symTab: SymTab.Ref ]; MakeTVNameGen: PROC [symTab: SymTab.Ref] RETURNS [ng: NameGenerator] = { ng _ NEW [NameGeneratorPrivate _ [ GenerateTVName, NEW [TVNameGeneratorPrivate _ [ nc: NEW [NameCountsPrivate _ []], symTab: symTab ]] ]]; }; GenerateTVName: PROC [data, subject: REF ANY] RETURNS [name: ROPE] = { tvng: TVNameGenerator = NARROW[data]; name _ Rope.Concat["&", GenByCount[tvng.nc, subject]]; TRUSTED {InterpreterOps.RegisterTV[ name: name, tv: AMBridge.TVForReferent[WITH subject SELECT FROM d: Design => NEW [Design _ d], ct: CellType => NEW [CellType _ ct], p: Port => NEW [Port _ p], v: Vertex => NEW [Vertex _ v], ENDCASE => ERROR], symbolsList: LIST[tvng.symTab]]}; }; GenByCount: PROC [nc: NameCounts, subject: REF ANY] RETURNS [name: ROPE] = { n: INT _ 0; WITH subject SELECT FROM d: Design => {n _ nc.design _ nc.design + 1; name _ "D#"}; ct: CellType => {n _ nc.cellType _ nc.cellType + 1; name _ "CT#"}; p: Port => {n _ nc.port _ nc.port + 1; name _ "P#"}; v: Vertex => {n _ nc.vertex _ nc.vertex + 1; name _ "V#"}; ENDCASE => ERROR; name _ name.Concat[Convert.RopeFromInt[n]]; }; PrintObject: PROC [to: IO.STREAM, united: BOOL, PrintIt: PROC] = { SS.Bp[to, IF united THEN united ELSE lookLeft, printStep]; SS.Begin[to]; PrintIt[!UNWIND => SS.End[to]]; SS.End[to]; }; printStep: INT _ 2; printWidth: INT _ 69; PrintDesignOnFile: PUBLIC PROC [design: Design, nameGen: NameGenerator _ NIL, fileName: ROPE _ NIL, tioga: BOOL _ FALSE, pacify: IO.STREAM _ NIL] = { realFileName: ROPE = IF fileName # NIL THEN fileName ELSE Rope.Cat[Describe[design], ".design"]; ss, fs: IO.STREAM; taw: TiogaAccess.Writer; IF tioga THEN { taw _ TiogaAccess.Create[]; ss _ SS.Create[UB.NewInittedHandle[[output: [access[taw, printStep]], margin: printWidth]]]; } ELSE { fs _ FS.StreamOpen[realFileName, create]; ss _ SS.Create[UB.NewInittedHandle[[output: [stream[fs]], margin: printWidth]]]; }; PrintDesign[ss, design, nameGen, pacify]; IF tioga THEN TiogaAccess.WriteFile[taw, realFileName] ELSE IO.Close[fs]; ss.Close[]; }; PrintDesign: PUBLIC PROC [to: IO.STREAM, design: Design, nameGen: NameGenerator _ NIL, pacify: IO.STREAM _ NIL] = { Filter: PROC [CellType] RETURNS [BOOL] = {RETURN [TRUE]}; IF pacify#NIL THEN pacify.PutF["Total: %g\n", [integer[design.cellTypes.Size]]]; PrintDesignSubset[to, design, nameGen, Filter, pacify]; }; PrintDesignSubset: PUBLIC PROC [to: IO.STREAM, design: Design, nameGen: NameGenerator, Filter: PROC [CellType] RETURNS [BOOL], pacify: IO.STREAM _ NIL] = { n: NAT _ 0; CTPrint: PROC [ra: REF ANY] = { ct: CellType = NARROW[ra]; Inner: PROC = { IF pacify#NIL THEN pacify.PutF["%g: %g ", [integer[n _ n+1]], [rope[Describe[ct, design, nameGen]]]]; PrintCellType[to, ct, nameGen]; IF pacify#NIL THEN pacify.PutRope[" .\n"]; }; IF Filter[ct] THEN PrintObject[to, TRUE, Inner]; }; IF NOT SS.IsAnSS[to] THEN to _ SS.Create[UB.NewInittedHandle[[output: [stream[to]], margin: printWidth]]]; to.PutF["%g: Design {", [rope[Describe[design, NIL, nameGen]]]]; design.cellTypes.Enumerate[CTPrint]; to.PutF["}"]; }; PrintNameAndAliases: PROC [to: IO.STREAM, name: ROPE, names: Set--of SteppyName--] ~ { first, second: BOOL _ TRUE; PerName: PROC [val: REF ANY] ~ { name: SteppyName ~ NARROW[val]; IF first THEN first _ FALSE ELSE { IF second THEN second _ FALSE ELSE to.PutRope[","]; SS.Bp[to, width, printStep, " "]; to.PutRope[UnparseSteppyName[name]]; }; RETURN}; to.PutRope[name]; IF names.Size[2]>1 THEN { to.PutRope["(a.k.a."]; names.Enumerate[PerName]; to.PutRope[")"]; }; RETURN}; PrintCellType: PUBLIC PROC [to: IO.STREAM, ct: CellType, nameGen: NameGenerator _ NIL] = { PortPrint: PROC = { to.PutF["port: "]; PrintPort[to, ct.port, nameGen]; }; IWPrint: PROC = { to.PutF["internal wire: "]; PrintWire[to, ct.asUnorganized.internalWire, nameGen]; }; CIPrint: PROC = { to.PutF["contained instances: "]; PrintInstances[to, ct.asUnorganized.containedInstances, ct.asUnorganized.mirror, nameGen]; }; AyPrint: PROC = { to.PutRope["asArray: "]; PrintArray[to, ct, nameGen] }; IF NOT SS.IsAnSS[to] THEN to _ SS.Create[UB.NewInittedHandle[[output: [stream[to]], margin: printWidth]]]; to.PutRope[Describe[ct, GetADesign[ct], nameGen]]; to.PutRope[": CellType["]; PrintObject[to, TRUE, PortPrint]; IF ct.asUnorganized # NIL THEN { to.PutRope[", "]; PrintObject[to, TRUE, IWPrint]; to.PutRope[", "]; PrintObject[to, TRUE, CIPrint]; }; IF ct.asArray # NIL THEN { to.PutRope[", "]; PrintObject[to, TRUE, AyPrint]; }; to.PutRope["]"]; }; limitPort: BOOL _ TRUE; portLimit: NAT _ 69; MaybePrintSeq: PROC [to: IO.STREAM, parent: REF ANY, toKids: Function--parent _ Seq of child--, toName: Function--child _ SteppyName--] RETURNS [did: BOOL] ~ { kids: Seq--of child-- ~ IntFns.DeRef[toKids.Apply[parent].val]; bounds: Ints.Interval ~ kids.GetBounds[]; is: BOOL _ TRUE; FOR i: INT IN [bounds.min .. bounds.max] DO child: REF ANY ~ kids.Apply[i].DVal; IF child=NIL THEN EXIT; {name: SteppyName ~ NARROW[toName.Apply[child].DVal]; IF name#NIL AND name.rest=NIL THEN WITH name.first SELECT FROM x: REF INT => IF x^ = i THEN { grandKids: Seq ~ IntFns.DeRef[toKids.Apply[child].val]; IF grandKids.Size[]=0 THEN LOOP; }; x: ROPE => NULL; ENDCASE => ERROR; EXIT; };REPEAT FINISHED => { IF bounds.min=0 THEN to.PutF["*%g", [integer[bounds.max+1]]] ELSE to.PutF["*%g..%g", [integer[bounds.min]], [integer[bounds.max]]]; RETURN [TRUE]}; ENDLOOP; RETURN [FALSE]}; PrintPort: PUBLIC PROC [to: IO.STREAM, port: Port, nameGen: NameGenerator _ NIL] = { first: BOOL _ TRUE; i: INT _ 0; PrintNameAndAliases[to, Describe[port, port.parent, nameGen], port.PortNames]; IF port.FirstChildPort[] = NIL THEN RETURN; IF MaybePrintSeq[to, port, LichenNavigation.portToChildren, LichenNavigation.bestPortShortName] THEN RETURN; to.PutRope["["]; FOR subPort: Port _ port.FirstChildPort[], subPort.NextChildPort[] WHILE subPort#NIL DO PortPrint: PROC = {PrintPort[to, subPort, nameGen]}; PrintElipsis: PROC = {to.PutF["..%g.., ", [integer[i-portLimit]]]}; IF (NOT limitPort) OR i < portLimit OR subPort.NextChildPort[] = NIL THEN { IF first THEN first _ FALSE ELSE to.PutRope[", "]; IF limitPort AND i > portLimit THEN PrintObject[to, FALSE, PrintElipsis]; PrintObject[to, FALSE, PortPrint] }; i _ i + 1; ENDLOOP; to.PutRope["]"]; }; PrintWire: PUBLIC PROC [to: IO.STREAM, wire: Wire, nameGen: NameGenerator _ NIL] = { first: BOOL _ TRUE; PrintNameAndAliases[to, Describe[wire, WireContainer[wire], nameGen], wire.VertexNames]; IF wire.FirstChildWire[] = NIL THEN RETURN; IF MaybePrintSeq[to, wire, LichenNavigation.wireToChildren, LichenNavigation.bestVertexShortName] THEN RETURN; to.PutRope["["]; FOR subWire: Wire _ wire.FirstChildWire[], subWire.NextChildWire[] WHILE subWire # NIL DO WirePrint: PROC = {PrintWire[to, subWire, nameGen]}; IF first THEN first _ FALSE ELSE to.PutRope[", "]; PrintObject[to, FALSE, WirePrint]; ENDLOOP; to.PutRope["]"]; }; PrintInstances: PUBLIC PROC [to: IO.STREAM, set: Set--OF CellInstance--, mirror: CellInstance, nameGen: NameGenerator _ NIL] = { first: BOOL _ TRUE; PrintIt: PROC [ra: REF ANY] = { ci: CellInstance = NARROW[ra]; IPrint: PROC = {PrintInstance[to, ci, nameGen]}; IF first THEN first _ FALSE ELSE to.PutRope[", "]; PrintObject[to, TRUE, IPrint]; }; to.PutRope["["]; set.Enumerate[PrintIt]; IF printMirror THEN PrintIt[mirror]; to.PutRope["]"]; }; printMirror: BOOL _ FALSE; PrintInstance: PUBLIC PROC [to: IO.STREAM, ci: CellInstance, nameGen: NameGenerator _ NIL] = { PrintConnections: PROC [v: Vertex] = { first: BOOL _ TRUE; PrintConnection: PROC [port: Port, w: Vertex] = { CPrint: PROC = { to.PutF["%g: ", [rope[Describe[port, port.parent, nameGen]]]]; WITH w SELECT FROM im: Intermediary => { subbing, first: BOOL _ TRUE; min, max: INT; parent: Wire; TestConnection: PROC [p: Port, u: Vertex] ~ { ow: Wire ~ WITH u SELECT FROM x: Wire => x, x: Intermediary => NIL, x: CellInstance => ERROR, ENDCASE => ERROR; IF ow=NIL THEN subbing _ FALSE; IF NOT subbing THEN RETURN; {pn: SteppyName ~ NARROW[p.PortNames.First.DVal]; IF pn#NIL AND pn.rest=NIL THEN WITH pn.first SELECT FROM x: REF INT => { wn: SteppyName ~ NARROW[ow.VertexNames.First.DVal]; IF wn#NIL AND wn.rest=NIL THEN WITH wn.first SELECT FROM y: REF INT => IF x^ = y^ THEN {IF first THEN { first _ FALSE; parent _ ow.containingWire; min _ max _ x^; RETURN} ELSE { min _ MIN[min, x^]; max _ MAX[max, x^]; IF parent=ow.containingWire THEN RETURN}; }; y: ROPE => NULL; ENDCASE => ERROR; }; x: ROPE => NULL; ENDCASE => ERROR; subbing _ FALSE; }}; EnumerateImmediateConnections[im, TestConnection, [cellward: FALSE, wireward: TRUE]]; IF subbing THEN { to.PutRope[Describe[parent, ci.containingCT.asUnorganized.internalWire, nameGen]]; to.PutF["[%g..%g]", [integer[min]], [integer[max]]]; } ELSE PrintConnections[im]; }; wire: Wire => { to.PutRope[Describe[wire, ci.containingCT.asUnorganized.internalWire, nameGen]]; }; ci: CellInstance => ERROR; ENDCASE => ERROR; }; IF first THEN first _ FALSE ELSE to.PutRope[", "]; PrintObject[to, FALSE, CPrint]; }; to.PutRope["["]; EnumerateImmediateConnections[v, PrintConnection, [cellward: FALSE, wireward: TRUE]]; to.PutRope["]"]; }; PrintNameAndAliases[to, Describe[ci, ci.containingCT, nameGen], ci.VertexNames]; to.PutF[": %g", [rope[Describe[ci.type, GetADesign[ci.type], nameGen]]] ]; PrintConnections[ci]; }; PrintArray: PUBLIC PROC [to: IO.STREAM, ct: CellType, nameGen: NameGenerator _ NIL] = { a: Array = ct.asArray; groupName: VarFunction = PairColls.CreateHashFn[]; nGroups: NAT _ 0; JPPrint: PROC = { to.PutF["joints period = [%g, %g]", [integer[a.jointsPeriod[Foo]]], [integer[a.jointsPeriod[Bar]]]]}; GMPrint: PROC = { to.PutF["groupingMiddles = [%g, %g]", [rope[FmtGP[a.groupingParmses[Foo]]]], [rope[FmtGP[a.groupingParmses[Bar]]]]]; }; AWPrint: PROC = { to.PutRope["wires = ["]; PrintArrayWires[to, a, groupName, nameGen]; to.PutRope["]"]; }; to.PutF["{%g BY %g OF %g, ", [integer[a.size[Foo]]], [integer[a.size[Bar]]], [rope[Describe[a.eltType, GetADesign[ct], nameGen]]] ]; PrintObject[to, FALSE, JPPrint]; to.PutRope[", "]; PrintObject[to, FALSE, GMPrint]; FOR gif: NAT IN [0 .. a.groupingParmses[Foo].sum) DO FOR gib: NAT IN [0 .. a.groupingParmses[Bar].sum) DO gi: NAT = a.groupingParmses[Bar].sum * gif + gib; gs: Groupings = NARROW[a.groupingses[gi]]; PrintGroups: PROC = { first: BOOL _ TRUE; PrintGroup: PROC [ra: REF ANY] = { g: Group = NARROW[ra]; name: ROPE = IO.PutFR["G%g", [integer[nGroups _ nGroups+1]]]; GPrint: PROC = { to.PutF["%g: ", [rope[name]]]; PrintGroupContents[to, a, g, nameGen]; }; IF NOT groupName.Store[[g, name]].new THEN ERROR; IF first THEN first _ FALSE ELSE to.PutRope[", "]; PrintObject[to, FALSE, GPrint]; }; to.PutF["groups[%g, %g] = [", [integer[gif]], [integer[gib]]]; gs.groups.Enumerate[PrintGroup]; to.PutRope["]"]; }; to.PutRope[", "]; PrintObject[to, TRUE, PrintGroups]; ENDLOOP ENDLOOP; FOR d: Dim IN Dim DO PrintJoints: PROC = { first: BOOL _ TRUE; to.PutF["joints[%g] = [", [rope[DimName[d]]]]; FOR ff: NAT IN [0 .. a.jointsPeriod[Foo]) DO FOR fb: NAT IN [0 .. a.jointsPeriod[Bar]) DO phase: Nat2 = [ff, fb]; JPrint: PROC = { to.PutF["[%g,%g]: ", [integer[ff]], [integer[fb]]]; PrintJoint[to, ct, d, phase, GetArrayJoint[a, d, phase], nameGen, groupName]; }; IF first THEN first _ FALSE ELSE to.PutRope[", "]; PrintObject[to, TRUE, JPrint]; ENDLOOP; ENDLOOP; to.PutRope["]"]; }; to.PutRope[", "]; PrintObject[to, TRUE, PrintJoints]; ENDLOOP; to.PutRope[", "]; PrintObject[to, TRUE, AWPrint]; to.PutRope["}"]; }; PrintArrayWires: PROC [to: IO.STREAM, a: Array, groupName: VarFunction, nameGen: NameGenerator] ~ { first: BOOL _ TRUE; dull: ARRAY Dim OF BOOL ~ [a.size[Foo]=1, a.size[Bar]=1]; twod: BOOL ~ dull=ALL[FALSE]; PrintPerAW: PROC [ra: REF ANY] ~ { aw: ArrayWire ~ NARROW[ra]; AWPrint: PROC ~ { first: BOOL _ TRUE; size1: BOOL ~ aw.members.Size[2]=1; PerGroup: PROC [pair: PairColls.Pair] ~ { g: Group ~ NARROW[pair[left]]; bs: BoolSeq ~ NARROW[pair[right]]; air: Range2 ~ Gi2ToAir[a, g.gi2].air; shape: Nat2 ~ RangeShape[air]; EltPrint: PROC ~ { firstRow: BOOL _ TRUE; f0: NAT _ air[Foo].min; f1, fi0, fi1: NAT _ 0; to.PutRope[NARROW[groupName.Apply[g].val]]; to.PutRope["["]; WHILE f0 < air[Foo].maxPlusOne DO base: NAT ~ shape[Bar] * fi0; RowSame: PROC [fi1: NAT] RETURNS [BOOL] ~ { base1: NAT ~ shape[Bar] * fi1; b: NAT _ air[Bar].min; bi: NAT _ 0; WHILE b < air[Bar].maxPlusOne DO IF bs[base+bi] # bs[base1+bi] THEN RETURN [FALSE]; b _ b+a.jointsPeriod[Bar]; bi _ bi + 1; ENDLOOP; RETURN [TRUE]}; firstCol: BOOL _ TRUE; b0: NAT _ air[Bar].min; b1, bi0, bi1: NAT _ 0; f1 _ f0 + a.jointsPeriod[Foo]; fi1 _ fi0 + 1; UNTIL f1 >= air[Foo].maxPlusOne OR NOT RowSame[fi1] DO f1 _ f1+a.jointsPeriod[Foo]; fi1 _ fi1 + 1; ENDLOOP; WHILE b0 < air[Bar].maxPlusOne DO bit0: BOOL ~ bs[base + bi0]; b1 _ b0+a.jointsPeriod[Bar]; bi1 _ bi0 + 1; UNTIL b1 >= air[Bar].maxPlusOne OR bs[base+bi1] # bit0 DO b1 _ b1 + a.jointsPeriod[Bar]; bi1 _ bi1 + 1; ENDLOOP; IF bit0 THEN { IF firstCol THEN { IF firstRow THEN firstRow _ FALSE ELSE to.PutRope[", "]; SS.Bp[to, lookLeft, printStep]; SS.Begin[to]; firstCol _ FALSE; SELECT dull FROM [FALSE, FALSE] => to.PutF["{%g: ", [rope[FmtRange[[f0, f1]]]]]; [FALSE, TRUE] => to.PutRope[FmtRange[[f0, f1]]]; [TRUE, FALSE] => NULL; [TRUE, TRUE] => to.PutRope["X"]; ENDCASE => ERROR; } ELSE to.PutRope[", "]; IF twod THEN SS.Bp[to, lookLeft, printStep]; IF NOT dull[Bar] THEN to.PutRope[FmtRange[[b0, b1]]]; }; b0 _ b1; bi0 _ bi1; ENDLOOP; IF NOT firstCol THEN { IF twod THEN to.PutRope["}"]; SS.End[to]; }; f0 _ f1; fi0 _ fi1; ENDLOOP; to.PutRope["]"]; }; IF first THEN first _ FALSE ELSE to.PutRope[", "]; PrintObject[to, FALSE, EltPrint]; }; IF NOT size1 THEN to.PutRope["{"]; aw.members.Enumerate[PerGroup]; IF NOT size1 THEN to.PutRope["}"]; }; IF first THEN first _ FALSE ELSE to.PutRope[", "]; PrintObject[to, FALSE, AWPrint]; }; a.wires.Enumerate[PrintPerAW]; }; PrintGroupContents: PROC [to: IO.STREAM, a: Array, g: Group, nameGen: NameGenerator] = { first: BOOL _ TRUE; to.PutRope["{"]; FOR pl: PortList _ g.ports, pl.rest WHILE pl # NIL DO p: Port = pl.first; name: ROPE = Describe[p, a.eltType.port, nameGen]; IF first THEN first _ FALSE ELSE to.PutRope[", "]; SS.Bp[to, lookLeft, printStep]; to.PutRope[name]; ENDLOOP; to.PutRope["}"]; }; PrintJoint: PROC [to: IO.STREAM, act: CellType, d: Dim, phase: Nat2, j: Joint, nameGen: NameGenerator, groupName: VarFunction] = { GPFPrint: PROC = { to.PutF["grouping middles = [%g, %g]", [rope[FmtGP[j.groupingParmses[Foo]]]], [rope[FmtGP[j.groupingParmses[Bar]]]]]}; to.PutRope["{"]; PrintObject[to, FALSE, GPFPrint]; FOR jgif: NAT IN [0 .. j.groupingParmses[Foo].sum) DO FOR jgib: NAT IN [0 .. j.groupingParmses[Bar].sum) DO jgi2: Nat2 = [jgif, jgib]; jgi: NAT = j.groupingParmses[Bar].sum * jgif + jgib; ties: Set = Colls.DeRef[j.ties[jgi]]; GIPrint: PROC = { first: BOOL _ TRUE; PerTie: PROC [ra: REF ANY] = { tie: Tie = NARROW[ra]; TPrint: PROC = {PrintTie[to, act, d, phase, j, jgi2, tie, nameGen, groupName]}; IF first THEN first _ FALSE ELSE to.PutRope[", "]; PrintObject[to, FALSE, TPrint]; }; to.PutF["@[%g, %g] {", [integer[jgif]], [integer[jgib]]]; [] _ ties.Enumerate[PerTie]; to.PutRope["}"]; }; to.PutRope[", "]; PrintObject[to, TRUE, GIPrint]; ENDLOOP ENDLOOP; to.PutRope["}"]; }; printIncompleteness: BOOL _ TRUE; PrintTie: PROC [to: IO.STREAM, act: CellType, d: Dim, phase: Nat2, j: Joint, jgi2: Nat2, tie: Tie, nameGen: NameGenerator, groupName: VarFunction] = { Bitch: PROC = { CPrint: PROC = { to.PutRope[" "]; PrintCliques[to, act, d, phase, j, jgi2, tie, nameGen]; }; to.PutF["(%g/%g incomplete", [integer[tie.completion.nIncomplete]], [integer[tie.completion.length]]]; IF printIncompleteness THEN CPrint[]; to.PutRope[")"]; }; FmtGrp: PROC [g: Group] RETURNS [name: ROPE] = { IF g = NIL THEN RETURN ["?nil?"]; name _ NARROW[groupName.Apply[g].DVal[noName]]; }; to.PutF["%g%g", [rope[FmtGrp[tie.groups[low]]]], [rope[FmtGrp[tie.groups[high]]]]]; IF tie.completion # NIL THEN Bitch[]; }; noName: ROPE ~ "??"; FmtGP: PROC [gp: GroupingParms] RETURNS [asRope: ROPE] = { asRope _ IO.PutFR["[%g..%g]", [integer[gp.middle.min]], [integer[gp.middle.maxPlusOne-1]]]}; PrintCliques: PROC [to: IO.STREAM, act: CellType, d: Dim, phase: Nat2, j: Joint, jgi2: Nat2, tie: Tie, nameGen: NameGenerator] = { a: Array = act.asArray; jSize: Nat2 = Nat2Tweak[a.size, d, -1]; jiir: Range2 = Jgi2ToLair[a, phase, j, jgi2].jiir; jif0, jif1: NAT _ 0; RowSame: PROC [f0, f1: NAT] RETURNS [same: BOOL] = { clai00f: NAT = jSize[Bar] * f0; clai00b: NAT = jiir[Bar].min * a.jointsPeriod[Bar] + phase[Bar]; FOR side: End IN End DO g: Group = tie.groups[side]; IF g # NIL THEN { FOR ports: PortList _ g.ports, ports.rest WHILE ports # NIL DO port: Port = ports.first; rpd: SidedPortData = FetchRPD[a, d, [side, port]]; clai0: NAT _ clai00f + clai00b; clai1: NAT _ jSize[Bar] * f1 + clai00b; IF rpd = NIL THEN ERROR; FOR jib: INT IN [jiir[Bar].min .. jiir[Bar].maxPlusOne) DO IF GetRoot[a, d, rpd, clai0] # GetRoot[a, d, rpd, clai1] THEN RETURN [FALSE]; clai0 _ clai0 + a.jointsPeriod[Bar]; clai1 _ clai1 + a.jointsPeriod[Bar]; ENDLOOP; ENDLOOP; }; ENDLOOP; same _ TRUE; }; to.PutRope["["]; FOR jif0 _ jiir[Foo].min, jif1 WHILE jif0 < jiir[Foo].maxPlusOne DO f0: NAT = jif0 * a.jointsPeriod[Foo] + phase[Foo]; f1: NAT _ f0 + a.jointsPeriod[Foo]; RPrint: PROC = { to.PutRope[FmtRange[[jif0, jif1]]]; to.PutRope[": "]; PrintRowCliques[to, act, d, phase, j, jiir, tie, f0, nameGen]; }; FOR jif1 _ jif0+1, jif1+1 UNTIL jif1 = jiir[Foo].maxPlusOne OR NOT RowSame[f0, f1] DO f1 _ f1 + a.jointsPeriod[Foo]; ENDLOOP; IF jif0 > jiir[Foo].min THEN to.PutRope[", "]; PrintObject[to, FALSE, RPrint]; ENDLOOP; to.PutRope["]"]; }; PrintRowCliques: PROC [to: IO.STREAM, act: CellType, d: Dim, phase: Nat2, j: Joint, jiir: Range2, tie: Tie, f: NAT, nameGen: NameGenerator] = { a: Array = act.asArray; jSize: Nat2 = Nat2Tweak[a.size, d, -1]; claiBase: NAT = jSize[Bar] * f; ColSame: PROC [b0, b1: NAT] RETURNS [same: BOOL] = { FOR side: End IN End DO g: Group = tie.groups[side]; IF g # NIL THEN { FOR ports: PortList _ g.ports, ports.rest WHILE ports # NIL DO port: Port = ports.first; rpd: SidedPortData = FetchRPD[a, d, [side, port]]; IF GetRoot[a, d, rpd, claiBase+b0] # GetRoot[a, d, rpd, claiBase+b1] THEN RETURN [FALSE]; ENDLOOP; }; ENDLOOP; same _ TRUE; }; jib0, jib1: NAT _ 0; to.PutRope["("]; FOR jib0 _ jiir[Bar].min, jib1 WHILE jib0 < jiir[Bar].maxPlusOne DO b0: NAT = jib0 * a.jointsPeriod[Bar] + phase[Bar]; b1: NAT _ b0 + a.jointsPeriod[Bar]; CPrint: PROC = { to.PutRope[FmtRange[[jib0, jib1]]]; to.PutRope[": "]; PrintColCliques[to, act, d, j, tie, [f, b0], nameGen]; }; FOR jib1 _ jib0+1, jib1+1 UNTIL jib1 = jiir[Bar].maxPlusOne OR NOT ColSame[b0, b1] DO b1 _ b1 + a.jointsPeriod[Foo]; ENDLOOP; IF jib0 > jiir[Bar].min THEN to.PutRope[", "]; PrintObject[to, FALSE, CPrint]; ENDLOOP; to.PutRope[")"]; }; cliques: RefTable--root rpd _ member rpd list-- = CreateRefTable[]; PrintColCliques: PROC [to: IO.STREAM, act: CellType, d: Dim, j: Joint, tie: Tie, lai: Nat2, nameGen: NameGenerator] = { a: Array = act.asArray; jSize: Nat2 = Nat2Tweak[a.size, d, -1]; clai: NAT = jSize[Bar] * lai[Foo] + lai[Bar]; to.PutRope["{"]; cliques.Erase[]; FOR side: End IN End DO g: Group = tie.groups[side]; IF g # NIL THEN { FOR ports: PortList _ g.ports, ports.rest WHILE ports # NIL DO port: Port = ports.first; rpd: SidedPortData = FetchRPD[a, d, [side, port]]; rootIndex: NAT = GetRoot[a, d, rpd, clai]; root: SidedPortData = NARROW[a.roles[d].refs[rootIndex]]; members: SidedPortDataList _ NARROW[cliques.Fetch[root].val]; members _ CONS[rpd, members]; [] _ cliques.Store[root, members]; ENDLOOP; }; ENDLOOP; {first: BOOL _ TRUE; PrintClique: PROC [key, val: REF ANY] RETURNS [quit: BOOL _ FALSE] --RefTab.EachPairAction-- = { members: SidedPortDataList = NARROW[val]; CPrint: PROC = { first: BOOL _ TRUE; to.PutRope["("]; FOR rpds: SidedPortDataList _ members, rpds.rest WHILE rpds # NIL DO rpd: SidedPortData = rpds.first; IF first THEN first _ FALSE ELSE to.PutRope[", "]; SS.Bp[to, width, printStep]; to.PutRope[FmtRPD[a, rpd, nameGen]]; ENDLOOP; to.PutRope[")"]; }; IF first THEN first _ FALSE ELSE to.PutRope[", "]; PrintObject[to, FALSE, CPrint]; }; [] _ cliques.Pairs[PrintClique]; to.PutRope["}"]; }}; FmtRPD: PROC [a: Array, rpd: SidedPortData, nameGen: NameGenerator] RETURNS [asRope: ROPE] = { asRope _ EndName[rpd.side].Cat["/", Describe[rpd.port, a.eltType.port, nameGen]]; }; FmtRange: PROC [r: Range] RETURNS [asRope: ROPE] = { asRope _ Convert.RopeFromInt[r.min]; IF r.min+1 # r.maxPlusOne THEN asRope _ asRope.Cat["~", Convert.RopeFromInt[r.maxPlusOne-1]]; }; PrintArrays: PROC [to: IO.STREAM, design: Design, nameGen: NameGenerator _ NIL, pacify: IO.STREAM _ NIL] = { Filter: PROC [ct: CellType] RETURNS [pass: BOOL] = { pass _ ct.asArray # NIL; }; PrintDesignSubset[to, design, nameGen, Filter, pacify]; }; PrintIncompletes: PROC [to: IO.STREAM, design: Design, nameGen: NameGenerator _ NIL, pacify: IO.STREAM _ NIL] = { PrintDesignSubset[to, design, nameGen, IsIncompleteArray, pacify]; }; END. `LichenData2Impl.Mesa Last tweaked by Mike Spreitzer on September 10, 1987 5:42:22 pm PDT Κ u˜™Icode™C—J˜KšΟk œ'œ'œέ˜ΈK˜šΠbxœœ˜Kšœœœ°˜μKšœ$˜+Kšœ˜—K˜Kšœœ7ΟnœŸ œŸœ Ÿœœœ˜»K˜KšŸœœœœ˜6KšŸœœœœ˜8K˜Kšœœ˜K˜šŸœœœ œœœœœœœœ˜zKšœG˜GKšœ˜—K˜šŸœœœ œœœœœœœ˜†šŸœœœœ˜TKšœœ1˜>šœœœ˜K˜3šœ œ˜Kšœœ˜+Kšœ;˜B—K˜ —Kšœ˜—Kšœ œœ˜/š œœœœœ œ˜E˜Kšœœ˜ K˜%Kšœœ˜Kšœ˜—˜Kšœœ˜ Kšœ3˜3Kšœœ˜Kš œ"œœœœO˜˜Kšœ˜—˜Kšœœœ˜Kš œœœ/œœ˜™šœœ˜K˜,Kšœ*˜*Kšœ%˜%Kšœœ˜—KšœœœœG˜oKšœ˜—˜Kšœœœ˜Kš œœ#œ/œœ˜€KšœœœœG˜oKšœ˜—Kšœœ˜—Kšœ˜—K˜šŸ œœœ˜7Kš Ÿœœœœ œ˜+Kšœœœœ˜,K˜K˜—K˜š Ÿ œœ œ œœ˜>šœ œ˜(Kšœ˜Kšœ˜—K˜—K˜šœ œ˜=K˜Kšœ˜K˜—K˜Kšœ œœ˜)šœœœ˜"Kšœ œ˜'K˜—K˜š Ÿœœœœœœ˜IKšœœ˜K˜K˜—K˜Kšœœœ˜3šœœœ˜'K˜K˜K˜—K˜šŸ œœœ˜Hšœœ˜"K˜šœ˜Kšœœ˜!K˜K˜—K˜—K˜—K˜š Ÿœœœœœœ˜FKšœœ˜%K˜6šœ˜#K˜ šœœ œ˜3Kšœ œ˜Kšœœ˜$Kšœ œ ˜Kšœ œ˜Kšœœ˜—Kšœ œ˜!—K˜—K˜š Ÿ œœœœœœ˜LKšœœ˜ šœ œ˜K˜:K˜BK˜4K˜:Kšœœ˜—K˜+K˜—K˜šŸ œœœœ œŸœœ˜BKšœœœœ˜:Kšœ ˜ Kšœ œœ ˜Kšœ ˜ K˜—K˜Kšœ œ˜Kšœ œ˜K˜šŸœœœ+œ œœ œœ œœœ˜•Kš œœœ œœ œ'˜`Kšœœœ˜K˜šœ˜šœ˜Kšœ˜KšœœœK˜\K˜—šœ˜Kšœœ"˜)Kšœœœ?˜PK˜——K˜)Kšœœ*œœ ˜IK˜ K˜—K˜šŸ œœœœœ+œ œœœ˜sKš Ÿœœ œœœœ˜9Kšœœœ>˜PKšœ7˜7Kšœ˜—K˜šŸœœœœœ*Ÿœœ œœ œœœ˜›Kšœœ˜ šŸœœœœ˜Kšœœ˜šŸœœ˜KšœœœS˜eKšœ˜Kšœœœ˜*Kšœ˜—Kšœ œœ ˜0K˜—Kš œœœ œœœ?˜jKšœ/œ˜@Kšœ$˜$K˜ K˜—K˜š Ÿœœœœœ Οcœ˜VKšœœœ˜šŸœœœœ˜ Kšœœ˜šœœ œœ˜"Kšœœ œœ˜3Kšœ˜!Kšœ$˜$K˜—Kšœ˜—Kšœ˜šœœ˜K˜K˜K˜K˜—Kšœ˜—K˜š Ÿ œœœœœ)œ˜ZšŸ œœ˜K˜K˜ K˜—šŸœœ˜K˜Kšœ6˜6K˜—šŸœœ˜K˜!KšœZ˜ZK˜—šŸœœ˜K˜Kšœ˜K˜—Kš œœœ œœœ?˜jKšœ2˜2Kšœ˜Kšœœ ˜!šœœœ˜ Kšœ"œ ˜1Kšœ"œ ˜1K˜—šœœœ˜Kšœ"œ ˜1K˜—K˜K˜—K˜Kšœ œœ˜Kšœ œ˜K˜šŸ œœœœ œœ  Πcm œ ‘  œœœ˜ŸKšœ   œ*˜?Kšœ)˜)Kšœœœ˜šœœœ˜+Kšœœœ˜$Kšœœœœ˜Kšœœ˜5šœœœ œœœ œ˜>š œœœœœ˜Kšœ7˜7Kšœœœ˜ K˜—Kšœœœ˜Kšœœ˜—Kšœ˜šœœœ˜šœ ˜Kšœ(˜,KšœB˜F—Kšœœ˜—Kšœ˜—Kšœœ˜—K˜š Ÿ œœœœœ'œ˜TKšœœœ˜Kšœœ˜ KšœN˜NKšœœœœ˜+Kšœ^œœ˜lK˜šœ@œ œ˜WKšŸ œœ%˜4KšŸ œœ1˜Cš œœ œœœœ˜KKšœœ œœ˜2Kšœ œœœ˜IKšœœ ˜!Kšœ˜—K˜ Kšœ˜—K˜K˜—K˜š Ÿ œœœœœ'œ˜TKšœœœ˜KšœX˜XKšœœœœ˜+Kšœ`œœ˜nK˜šœ@œ œ˜YKšŸ œœ%˜4Kšœœ œœ˜2Kšœœ ˜"Kšœ˜—K˜K˜—K˜šŸœœœœœ  œ1œ˜€Kšœœœ˜šŸœœœœ˜Kšœœ˜KšŸœœ$˜0Kšœœ œœ˜2Kšœœ ˜K˜—K˜K˜Kšœ œ˜$K˜K˜Kšœ œœ˜—K˜š Ÿ œœœœœ-œ˜^šŸœœ˜&Kšœœœ˜šŸœœ˜1šŸœœ˜K˜>šœœ˜˜Kšœœœ˜Kšœ œ˜K˜ šŸœœ˜-šœ œœ˜K˜ Kšœœ˜Kšœœ˜Kšœœ˜—Kšœœœ œ˜Kšœœ œœ˜Kšœœ˜1šœœœ œœœ œ˜8šœœœ˜Kšœœ˜3šœœœ œœœ œ˜8š œœœœ œœ˜'šœ˜Kšœœ˜Kšœ˜Kšœ˜Kšœ˜—šœ˜Kšœœ ˜Kšœœ ˜Kšœœœ˜)—K˜—Kšœœœ˜Kšœœ˜—K˜—Kšœœœ˜Kšœœ˜—Kšœ œ˜K˜—Kšœ"Ÿœ œ œ˜Ušœ œ˜KšœR˜RK˜4K˜—Kšœ˜K˜—˜KšœP˜PK˜—Kšœœ˜Kšœœ˜—K˜—Kšœœ œœ˜2Kšœœ ˜K˜—K˜Kšœ=œ œ˜UK˜K˜—KšœP˜PKšœJ˜JK˜K˜—K˜š Ÿ œœœœœ)œ˜WKšœ˜Kšœ2˜2Kšœ œ˜šŸœœ˜K˜e—šŸœœ˜Kšœt˜tK˜—šŸœœ˜K˜K˜+K˜K˜—˜K˜/Kšœ4˜4K˜—Kšœœ ˜ K˜Kšœœ ˜ šœΟdœœœ#œœ’œœœ#˜iKšœœ"’œ’œ˜1Kšœœ˜*šŸ œœ˜Kšœœœ˜šŸ œœœœ˜"Kšœ œ˜Kšœœœ.˜=šŸœœ˜K˜Kšœ&˜&K˜—Kšœœ œœ˜1Kšœœ œœ˜2Kšœœ ˜K˜—Kšœ)’œ’œ˜>K˜ K˜K˜—K˜Kšœœ˜#Kšœœ˜—šœœ˜šŸ œœ˜Kšœœœ˜K˜.š œΟg’œœœ˜,š œ£’œœœ˜,Kšœ£’œ£’œ˜šŸœœ˜Kšœ£’œ £’œ˜3KšœM˜MK˜—Kšœœ œœ˜2Kšœœ ˜Kšœ˜—Kšœ˜—K˜K˜—K˜Kšœœ˜#Kšœ˜—K˜Kšœœ ˜K˜K˜—K˜šŸœœœœ?˜cKšœœœ˜Kšœœœœ"˜9Kšœœœœ˜šŸ œœœœ˜"Kšœœ˜šŸœœ˜Kšœœœ˜Kšœœ˜#šŸœœ˜)Kšœ œ ˜Kšœœ˜"Kšœ%˜%Kšœ˜šŸœœ˜Kšœ œœ˜Kšœœ˜Kšœœ˜Kšœ œ˜+K˜šœ˜!Kšœœ˜š Ÿœœœœœ˜+Kšœœ˜Kšœœ˜Kšœœ˜ šœ˜ Kšœœœœ˜2Kšœ˜K˜ Kšœ˜—Kšœœ˜—Kšœ œœ˜Kšœœ˜Kšœœ˜Kšœ˜K˜šœœœ˜6Kšœ˜K˜Kšœ˜—šœ˜!Kšœœ˜Kšœ˜K˜šœœ˜9Kšœ˜K˜Kšœ˜—šœœ˜šœ œ˜Kšœ œ œœ˜8Kšœ˜Kšœ ˜ Kšœ œ˜šœ˜Kšœœœ2˜?Kšœœœ$˜0Kšœœœœ˜Kšœœœ˜ Kšœœ˜—K˜—Kšœ˜Kšœœœ˜,Kšœœ œ ˜5K˜—K˜K˜ Kšœ˜—šœœ œ˜Kšœœ˜Kšœ ˜ Kšœ˜—K˜K˜ Kšœ˜—K˜Kšœ˜—Kšœœ œœ˜2Kšœœ ˜!K˜—Kšœœœ˜"Kšœ˜Kšœœœ˜"K˜—Kšœœ œœ˜2Kšœœ ˜ K˜—Kšœ˜K˜—K˜šŸœœœœ1˜XKšœœœ˜K˜šœ!œœ˜5K˜Kšœœ(˜2Kšœœ œœ˜2Kšœ˜K˜Kšœ˜—K˜K˜—K˜šŸ œœœœc˜‚šŸœœ˜Kšœv˜v—K˜Kšœœ ˜!šœ’œœœ#œœ’œœœ#˜kKšœ’œ’œ˜Kšœœ#’œ’œ˜4Kšœ%˜%šŸœœ˜Kšœœœ˜šŸœœœœ˜Kšœ œ˜KšŸœœC˜OKšœœ œœ˜2Kšœœ ˜K˜—Kšœ#’œ’œ˜9Kšœ˜K˜K˜—K˜Kšœœ ˜Kšœœ˜—K˜K˜—K˜Kšœœœ˜!K˜šŸœœœœy˜–šŸœœ˜šŸœœ˜K˜Kšœ7˜7K˜—Kšœf˜fKšœœ ˜%K˜Kšœ˜—šŸœœ œœ˜0Kšœœœœ ˜!Kšœœ"˜/Kšœ˜—KšœT˜TKšœœœ ˜%K˜Kšœœ˜—K˜šŸœœœ œ˜:Kšœ œQ˜\—K˜šŸ œœœœa˜‚K˜K˜'Kšœ2˜2Kšœ’œ’œœ˜š Ÿœœ œœœ˜4Kšœ’œœ˜Kšœ’œœ4˜@šœ œ˜K˜šœœœ˜šœ'œ œ˜>K˜K˜2Kšœœ ’œ ’œ˜Kšœœ’œ˜'Kšœœœœ˜š œ’œœœ)˜:Kšœ7œœœ˜MKšœ$˜$Kšœ$˜$Kšœ˜—Kšœ˜—K˜—Kšœ˜—Kšœœ˜ K˜—K˜š œ’œ’œœ’œ˜CKšœœ’œ%˜2Kšœœ˜#šŸœœ˜Kšœ’œ’œ˜#K˜Kšœ>˜>Kšœ˜—šœ’œ’œ’œœ’œœœ˜UKšœ˜Kšœ˜—Kšœ’œœ˜.Kšœœ ˜Kšœ˜—K˜K˜—K˜š ŸœœœœKœ˜K˜K˜'Kšœ œ˜š Ÿœœ œœœ˜4šœ œ˜K˜šœœœ˜šœ'œ œ˜>K˜K˜2KšœCœœœ˜YKšœ˜—K˜—Kšœ˜—Kšœœ˜ K˜—Kšœ’œ’œœ˜K˜š œ’œ’œœ’œ˜CKšœœ+˜2Kšœœ˜#šŸœœ˜Kšœ’œ’œ˜#K˜Kšœ6˜6Kšœ˜—šœ’œ’œ’œœ’œœœ˜UKšœ˜Kšœ˜—Kšœ’œœ˜.Kšœœ ˜Kšœ˜—K˜K˜—K˜Kšœ  ‘ œ˜CK˜šŸœœœœS˜wK˜K˜'Kšœœ$˜-K˜Kšœ˜šœ œ˜K˜šœœœ˜šœ'œ œ˜>K˜K˜2Kšœ œ˜*Kšœœ˜9Kšœœ˜=Kšœ œ˜K˜"Kšœ˜—K˜—Kšœ˜—Kšœœœ˜šŸ œœ œœœœœ œ˜`Kšœœ˜)šŸœœ˜Kšœœœ˜K˜šœ.œœ˜DK˜ Kšœœ œœ˜2Kšœ˜K˜$Kšœ˜—K˜K˜—Kšœœ œœ˜2Kšœœ ˜K˜—Kšœ ˜ K˜K˜—K˜šŸœœ8œ œ˜^K˜QK˜—K˜šŸœœ œ œ˜4K˜$Kšœœ?˜]K˜—K˜šŸ œœœœ+œ œœœ˜lšŸœœœœ˜4Kšœœ˜Kšœ˜—Kšœ7˜7Kšœ˜—K˜šŸœœœœ+œ œœœ˜qKšœB˜BKšœ˜—K˜Kšœ˜—…—`μΑ