DIRECTORY AbSets, BasicTime, BiRels, FS, IntStuff, IO, LichenDataStructure, LichenIntBasics, LichenPrinting, Rope, SetBasics, StructuredStreams, TiogaAccess, UnparserBuffer; LichenPrintingImpl: CEDAR PROGRAM IMPORTS AbSets, BasicTime, BiRels, FS, IntStuff, IO, LichenDataStructure, LichenIntBasics, Rope, SetBasics, StructuredStreams, TiogaAccess, UnparserBuffer EXPORTS LichenPrinting = BEGIN OPEN IB:LichenIntBasics, IB, LichenDataStructure, LichenPrinting, Ints:IntStuff, Sets:AbSets, SS:StructuredStreams, UB:UnparserBuffer; printStep: INT _ 2; printWidth: INT _ 74; sortTops: BOOL _ TRUE; 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]; RETURN}; PrintRope: PROC [to: IO.STREAM, united: BOOL, rope: ROPE] = { SS.Bp[to, IF united THEN united ELSE lookLeft, printStep]; SS.Begin[to]; to.PutRope[rope !UNWIND => SS.End[to]]; SS.End[to]; RETURN}; PrintDesignOnFiles: PUBLIC PROC [d: Design, nameGen: NameGenerator _ NIL, fnPrefix, fnSuffix: ROPE _ NIL, tioga: BOOL _ FALSE, pacify: IO.STREAM _ NIL, Filter: CellTypeFilter _ NIL] = { realFNPrefix: ROPE ~ IF fnPrefix#NIL THEN fnPrefix ELSE Describe[d: d, subject: d, nameGen: nameGen]; realFNSuffix: ROPE ~ IF fnSuffix#NIL THEN fnSuffix ELSE "design"; n: NAT _ 0; order: Sets.Order ~ BiRels.MapOrder[d.ctName, leftToRight, Sets.fwd, Sets.alleq]; CtPrint: PROC [ctv: Sets.Value] RETURNS [BOOL] = { ct: CellType = NARROW[ctv.VA]; ctName: ROPE ~ ct.ACtName[]; realFileName: ROPE ~ Rope.Cat[realFNPrefix, "/", ctName.Translate[translator: BlandifyChar], ".", realFNSuffix]; ss, fs: IO.STREAM; taw: TiogaAccess.Writer; start: BasicTime.Pulses; IF tioga THEN { taw _ TiogaAccess.Create[]; ss _ SS.Create[UB.NewInittedHandle[[output: [access[taw, printStep]], margin: printWidth]]]; } ELSE { fs _ FS.StreamOpen[fileName: realFileName, accessOptions: create, keep: 10]; ss _ SS.Create[UB.NewInittedHandle[[output: [stream[fs]], margin: printWidth]]]; }; IF pacify#NIL THEN { pacify.PutF["%g: %g ", [integer[n _ n+1]], [rope[Describe[d, ct, d, nameGen]]]]; start _ BasicTime.GetClockPulses[]}; PrintCellType[ss, ct, nameGen]; ss.PutRope["\n"]; IF pacify#NIL THEN { stop: BasicTime.Pulses ~ BasicTime.GetClockPulses[]; pacify.PutF[" %g\n", [real[BasicTime.PulsesToSeconds[stop-start]]]]}; IF tioga THEN TiogaAccess.WriteFile[taw, realFileName] ELSE IO.Close[fs]; ss.Close[]; RETURN [FALSE]}; IF pacify#NIL THEN { pacify.PutF["Total: %g\nCrossed=", [integer[d.cellTypes.Size.EN]]]; d.crossedCellTypes.PrintSet[pacify]; pacify.PutRope[".\n"]}; IF d.cellTypes.Scan[CtPrint, order].found THEN ERROR; RETURN}; BlandifyChar: PROC [old: CHAR] RETURNS [new: CHAR] ~ { SELECT old FROM IN ['a .. 'z], IN ['A .. 'Z], IN ['0 .. '9], '., '- => RETURN [old]; ', => RETURN ['.]; ': => RETURN ['~]; ENDCASE => RETURN ['$]}; PrintDesignOnFile: PUBLIC PROC [d: Design, nameGen: NameGenerator _ NIL, fileName: ROPE _ NIL, tioga: BOOL _ FALSE, pacify: IO.STREAM _ NIL, Filter: CellTypeFilter _ NIL] = { realFileName: ROPE = IF fileName # NIL THEN fileName ELSE Rope.Cat[Describe[d: d, subject: d, nameGen: nameGen], ".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[fileName: realFileName, accessOptions: create, keep: 10]; ss _ SS.Create[UB.NewInittedHandle[[output: [stream[fs]], margin: printWidth]]]; }; PrintDesignSubset[ss, d, nameGen, pacify, Filter]; IF tioga THEN TiogaAccess.WriteFile[taw, realFileName] ELSE IO.Close[fs]; ss.Close[]; RETURN}; PrintDesign: PUBLIC PROC [to: IO.STREAM, d: Design, nameGen: NameGenerator _ NIL, pacify: IO.STREAM _ NIL] = { PrintDesignSubset[to, d, nameGen, pacify, NIL]; RETURN}; PrintDesignSubset: PUBLIC PROC [to: IO.STREAM, d: Design, nameGen: NameGenerator _ NIL, pacify: IO.STREAM _ NIL, Filter: CellTypeFilter _ NIL] = { n: NAT _ 0; order: Sets.Order ~ BiRels.MapOrder[d.ctName, leftToRight, Sets.fwd, Sets.alleq]; CTPrint: PROC [ra: REF ANY] = { ct: CellType = NARROW[ra]; Inner: PROC = { start: BasicTime.Pulses; IF pacify#NIL THEN { pacify.PutF["%g: %g ", [integer[n _ n+1]], [rope[Describe[d, ct, d, nameGen]]]]; start _ BasicTime.GetClockPulses[]}; PrintCellType[to, ct, nameGen]; IF pacify#NIL THEN { stop: BasicTime.Pulses ~ BasicTime.GetClockPulses[]; pacify.PutF[" %g\n", [real[BasicTime.PulsesToSeconds[stop-start]]]]}; RETURN}; IF Filter=NIL OR Filter[ct] THEN PrintObject[to, TRUE, Inner]; RETURN}; IF pacify#NIL AND Filter=NIL THEN pacify.PutF["Total: %g\n", [integer[d.cellTypes.Size.EN]]]; IF NOT SS.IsAnSS[to] THEN to _ SS.Create[UB.NewInittedHandle[[output: [stream[to]], margin: printWidth]]]; to.PutF["%g: Design {", [rope[Describe[d: d, subject: d, nameGen: nameGen]]]]; IF d.scale#0.0 THEN to.PutF["linear unit = %g microns, ", [real[d.scale*1.0E6]]]; d.cellTypes.EnumA[CTPrint, order]; to.PutF["}"]; RETURN}; PrintNameAndAliases: PROC [to: IO.STREAM, names: Set--of SteppyName--, nonrelnames: Set _ nilSet] ~ { first, second: BOOL _ TRUE; prefix: ROPE _ NIL; PerName: PROC [val: Sets.Value] ~ { name: SteppyName ~ VSn[val]; IF first THEN first _ FALSE ELSE { IF second THEN {to.PutRope["(a.k.a."]; second _ FALSE} ELSE to.PutRope[","]; SS.Bp[to, width, printStep, " "]; }; to.PutRope[prefix]; to.PutRope[UnparseSteppyName[name]]; RETURN}; names.Enumerate[PerName]; IF nonrelnames#nilSet THEN { prefix _ "/"; nonrelnames.Enumerate[PerName]}; IF NOT second THEN to.PutRope[")"]; RETURN}; PrintCellType: PUBLIC PROC [to: IO.STREAM, ct: CellType, nameGen: NameGenerator _ NIL] = { CrossPrint: PROC ~ {to.PutRope[IF ct.d.crossedCellTypes.HasMemA[ct] THEN "crossed" ELSE "uncrossed"]}; BBPrint: PROC ~ {to.PutF["bbox: [%g,%g,%g,%g]", [integer[ct.bbox[X].min]], [integer[ct.bbox[Y].min]], [integer[ct.bbox[X].maxPlusOne]], [integer[ct.bbox[Y].maxPlusOne]]]}; PortPrint: PROC = { tops: Set ~ ct.TopParts[p]; sep: ROPE _ NIL; PrintAPort: PROC [pv: Sets.Value] RETURNS [BOOL] ~ { p: Port ~ NARROW[pv.VA]; PPrint: PROC ~ {PrintPW[to, ct, p, p, NIL, nameGen]}; to.PutRope[sep]; PrintObject[to, FALSE, PPrint]; sep _ ", "; RETURN [FALSE]}; to.PutRope["ports: ["]; IF tops.Scan[PrintAPort, IF sortTops THEN ct.nameOrder[p] ELSE Sets.alleq].found THEN ERROR; to.PutRope["]"]; RETURN}; IWPrint: PROC = { tops: Set ~ ct.TopParts[w]; sep: ROPE _ NIL; PrintAWire: PROC [wv: Sets.Value] RETURNS [BOOL] ~ { w: Wire ~ NARROW[wv.VA]; WPrint: PROC ~ {PrintPW[to, ct, w, w, NIL, nameGen]}; to.PutRope[sep]; PrintObject[to, FALSE, WPrint]; sep _ ", "; RETURN [FALSE]}; to.PutRope["internal wires: ["]; IF tops.Scan[PrintAWire, IF sortTops THEN ct.nameOrder[w] ELSE Sets.alleq].found THEN ERROR; to.PutRope["]"]; RETURN}; CIPrint: PROC = { to.PutF["connection sites: "]; PrintCells[to, ct, ct.Subcells, ct, nameGen]; RETURN}; 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.d, ct, ct.d, nameGen]]; to.PutRope[": CellType["]; PrintObject[to, FALSE, CrossPrint]; to.PutRope[", "]; IF ct.d.physd THEN {PrintObject[to, FALSE, BBPrint]; to.PutRope[", "]}; PrintObject[to, TRUE, PortPrint]; IF ct.asu # 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["]"]; }; PrintPW: PROC [to: IO.STREAM, ct: CellType, class: PWClass, pw: PW, parent: PW _ NIL, nameGen: NameGenerator _ NIL] ~ { [] _ ct.d.SteppyDescribe[pw, IF parent#NIL THEN parent ELSE ct, nameGen]; {fullNames: Set ~ ct.fullName[class].MappingA[pw]; IF parent#NIL THEN { relNames: Set ~ RelativeNames[ct, class, parent, pw]; reldNames: Set ~ SNsCat[ct.fullName[class].MappingA[parent], relNames]; nonRelNames: Set ~ fullNames.Difference[reldNames]; PrintNameAndAliases[to, relNames, nonRelNames]; to _ to} ELSE PrintNameAndAliases[to, fullNames]; IF ct.d.Atomic[pw] THEN RETURN; {shape: LOI ~ Shape[ct, class, pw]; IF shape#NIL THEN { IF shape.rest=NIL THEN ERROR; FOR dims: LOI _ shape, dims.rest WHILE dims.rest#NIL DO to.PutF["*%g", [integer[dims.first]]]; ENDLOOP; RETURN}; {kids: Seq ~ BiRels.DeRef[ct.d.sub.ApplyA[pw].MA]; first: BOOL _ TRUE; to.PutRope["["]; FOR i: INT IN [0 .. kids.Size.EN) DO kid: PW ~ kids.ApplyI[i].MA; PWPrint: PROC ~ {PrintPW[to, ct, class, kid, pw, nameGen]}; IF first THEN first _ FALSE ELSE to.PutRope[", "]; PrintObject[to, FALSE, PWPrint]; ENDLOOP; to.PutRope["]"]; RETURN}}}}; listOne: LOI ~ LIST[1]; Shape: PROC [ct: CellType, class: PWClass, pw: PW] RETURNS [LOI] ~ { IF ct.d.Atomic[pw] THEN RETURN [listOne]; {kids: Seq ~ BiRels.DeRef[ct.d.sub.ApplyA[pw].MA]; width: LNAT ~ kids.Size.EN; subShape: LOI _ NIL; FOR i: INT IN [0 .. width) DO kid: PW ~ kids.ApplyI[i].MA; thissub: LOI; AcceptIndex: PROC [sn: SteppyName] RETURNS [BOOL] ~ { IF sn.grade.nonsubs#0 OR sn.grade.subs#1 THEN RETURN [FALSE]; IF NARROW[sn.steps.first, REF INT]^ # i THEN RETURN [FALSE]; RETURN [TRUE]}; IF NOT ct.ScanRelativeNames[class, pw, kid, AcceptIndex].found THEN RETURN [NIL]; thissub _ Shape[ct, class, kid]; IF thissub=NIL THEN RETURN [NIL]; IF subShape=NIL THEN subShape _ thissub ELSE IF NOT LoiEqual[subShape, thissub] THEN RETURN [NIL]; ENDLOOP; RETURN [CONS[width, subShape]]}}; LoiEqual: PROC [l1, l2: LOI] RETURNS [BOOL] ~ { WHILE l1#l2 DO IF l1=NIL OR l2=NIL OR l1.first#l2.first THEN RETURN [FALSE]; l1 _ l1.rest; l2 _ l2.rest; ENDLOOP; RETURN [TRUE]}; PrintNeighborhood: PROC [to: IO.STREAM, cct: CellType, of: Set--of Wire--, radius: NAT] ~ { d: Design ~ cct.d; notPub: Set--of Wire-- ~ cct.asu.publics.Negate[]; transes: Set--of CellInstance-- ~ d.ciType.Image[d.transistorCellTypes, rightToLeft]; wires: Set--of Wire-- ~ of.CreateHashCopy[]; cells: Set--of CellInstance-- _ Sets.CreateHashSet[d.eSpace]; frontier: Set--of Wire-- _ wires; FOR i: NAT IN [1 .. radius] DO cis: Set ~ d.iwConns.Image[frontier, rightToLeft]; IF NOT cells.AddSet[cis].new.some THEN EXIT; IF i=radius THEN EXIT; {newXstrs: Set ~ cis.Intersection[transes]; condWires: Set ~ d.iwConns.Image[newXstrs, leftToRight]; frontier _ condWires.Difference[wires].CreateHashCopy[]; IF frontier.Empty THEN EXIT; IF NOT wires.AddSet[frontier].new.some THEN ERROR; }ENDLOOP; }; PrintCells: PUBLIC PROC [to: IO.STREAM, cct: CellType, set: Set--OF Cell--, and: Cell _ NIL, nameGen: NameGenerator _ NIL] = { order: Sets.Order ~ cct.nameOrder[i]; first: BOOL _ TRUE; PrintIt: PROC [cell: Cell] = { IPrint: PROC = {PrintCell[to, cct, cell, nameGen]}; IF first THEN first _ FALSE ELSE to.PutRope[", "]; PrintObject[to, TRUE, IPrint]; }; to.PutRope["["]; set.EnumA[PrintIt, order]; IF and#NIL THEN PrintIt[and]; to.PutRope["]"]; }; PrintCell: PUBLIC PROC [to: IO.STREAM, cct: CellType, cell: Cell, nameGen: NameGenerator _ NIL] = { WITH cell SELECT FROM ct: CellType => { IF ct # cct THEN ERROR; to.PutRope["exports"]; PrintForPorts[to, ct.asu.exports, cct.d.sub, cct.d.parent, ct, BiRels.EnumSeqOfSet[ct.TopParts[p], IF sortTops THEN ct.nameOrder[p] ELSE Sets.alleq], ct, cct.d.eSpace, nameGen]; RETURN}; ci: CellInstance => { ict: CellType ~ cct.d.CiT[ci]; xfm: Transform ~ IF cct.d.physd THEN VXfm[cct.d.ciXfm.ApplyA[ci].Val] ELSE []; [] _ cct.d.SteppyDescribe[ci, cct, nameGen]; PrintNameAndAliases[to, cct.INames[ci]]; to.PutF[": %g", [rope[cct.d.Describe[ict, cct.d, nameGen]]] ]; IF cct.d.physd THEN to.PutF["{%g %g,%g}", [rope[FormatTransform[xfm]]], [integer[ci.offset[X]]], [integer[ci.offset[Y]]]]; PrintForPorts[to, ci.conns, cct.d.sub, cct.d.parent, ict, BiRels.EnumSeqOfSet[ict.TopParts[p], IF sortTops THEN ict.nameOrder[p] ELSE Sets.alleq], ict, cct.d.eSpace, nameGen]; RETURN}; ENDCASE => ERROR; }; PrintForPorts: PROC [to: IO.STREAM, conns, sub, parent: BiRel, pct: CellType, ports: Seq--of Port--, rel: REF ANY, wSpace: Sets.Space, nameGen: NameGenerator] = { first: BOOL _ TRUE; PrintForPort: PROC [pair: BiRels.Pair] RETURNS [BOOL] ~ { p: Port ~ NARROW[pair[right].VA]; CPrint: PROC ~ { wmv: Sets.MaybeValue ~ conns.ApplyA[p]; to.PutRope[pct.d.Describe[p, rel, nameGen]]; to.PutRope[": "]; IF wmv.found THEN {to.PutRope[wSpace.SFormat[wmv.it]]; RETURN}; {pkids: Seq--of Port-- ~ BiRels.DeRef[pct.d.sub.ApplyA[p].MDA]; IF pkids=nilBiRel THEN {to.PutRope["??"]; RETURN}; {wkids: Seq--of Wire-- ~ pkids.Compose[conns]; nwkids: NATURAL ~ wkids.Size.EN; npkids: NATURAL ~ pkids.Size.EN; IF nwkids#npkids THEN GOTO NotEasy; {ws: Set--of Wire-- ~ wkids.SetOn[right]; IF ws.Size=Ints.one THEN {to.PutF["%g*%g", [rope[wSpace.SFormat[ws.TheElt]]], [integer[pkids.Size.EN]]]; RETURN}; {wparents: Set--of Wire-- ~ parent.Image[ws]; IF wparents.Size#Ints.one THEN GOTO NotEasy; {wparent: Sets.Value ~ wparents.TheElt; allwkids: Seq--of Wire-- ~ BiRels.VB[sub.Apply[wparent].Val]; mi: Sets.MaybeValue ~ allwkids.Index[wkids]; IF NOT mi.found THEN GOTO NotEasy; {base: NATURAL ~ mi.it.VI; to.PutRope[wSpace.SFormat[wparent]]; IF base#0 OR allwkids.Size.EN#npkids THEN to.PutF["[%g..%g]", [integer[base]], [integer[base+npkids-1]] ]; RETURN}}}}; EXITS NotEasy => NULL}; PrintForPorts[to, conns, sub, parent, pct, pkids, p, wSpace, nameGen]; RETURN}}; IF first THEN first _ FALSE ELSE to.PutRope[", "]; PrintObject[to, FALSE, CPrint]; RETURN [FALSE]}; to.PutRope["["]; IF ports.Scan[PrintForPort].found THEN ERROR; to.PutRope["]"]; RETURN}; printStatRep: BOOL _ TRUE; printDumbRep: BOOL _ FALSE; printStatExports: BOOL _ TRUE; PrintArray: PUBLIC PROC [to: IO.STREAM, act: CellType, nameGen: NameGenerator _ NIL] = { a: Array = act.asArray; ect: CellType ~ act.EltType[]; BasePrint: PROC = { to.PutF["base period = [%g, %g]", [integer[a.basePeriod[X]]], [integer[a.basePeriod[Y]]]]}; StatPrint: PROC = { to.PutRope["static graph = ["]; PrintStatRep[to, act, nameGen]; to.PutRope["]"]}; PhysPrint: PROC ~ { first: BOOL _ TRUE; to.PutRope["transforms = ["]; FOR fx: Int IN [0 .. a.basePeriod[X]) DO FOR fy: Int IN [0 .. a.basePeriod[Y]) DO f: Int2 ~ [fx, fy]; cf: NATURAL ~ ComposePhase[a, f]; IF first THEN first _ FALSE ELSE {to.PutRope[";"]; SS.Bp[to, width, printStep, " "]}; to.PutF["{%g,%g :", [integer[fx]], [integer[fy]]]; to.PutChar[' ]; to.PutRope[VXfm[a.fXfm.Apply[I2V[f]].Val].FormatTransform]; to.PutF[" %g,%g", [integer[a.offsets[cf].o0[X]]], [integer[a.offsets[cf].o0[Y]]] ]; IF a.size2#a.basePeriod THEN to.PutF[" + %g,%g", [integer[a.offsets[cf].o1[X]]], [integer[a.offsets[cf].o1[Y]]] ]; to.PutRope["}"]; ENDLOOP ENDLOOP; to.PutRope["]"]}; StatExpPrint: PROC = { to.PutRope["static exports = "]; PrintStatExp[to, act, nameGen]; RETURN}; to.PutF["{%g BY %g OF %g, ", [integer[a.size2[X]]], [integer[a.size2[Y]]], [rope[act.d.Describe[ect, act.d, nameGen]]] ]; PrintObject[to, FALSE, BasePrint]; IF act.d.physd THEN { to.PutRope[", "]; PrintObject[to, TRUE, PhysPrint]}; IF printStatRep THEN { to.PutRope[", "]; PrintObject[to, TRUE, StatPrint]; }; IF printStatExports THEN { to.PutRope[", "]; PrintObject[to, TRUE, StatExpPrint]; }; IF printDumbRep THEN ERROR nyet; to.PutRope["}"]; }; PrintStatRep: PROC [to: IO.STREAM, act: CellType, nameGen: NameGenerator] ~ { a: Array = act.asArray; ect: CellType ~ act.EltType[]; firstEdge: BOOL _ TRUE; EnsureNamed: PROC [part: Part] ~ { [] _ act.d.SteppyDescribe[part, ect, nameGen]; RETURN}; PrintEdge: PROC [val: Sets.Value] ~ { IF firstEdge THEN firstEdge _ FALSE ELSE to.PutRope[", "]; PrintRope[to, TRUE, a.statrep.edgeSpace.SFormat[val]]; RETURN}; ect.EnumCTParts[p, TRUE, TRUE, EnsureNamed]; a.statrep.edges.Enumerate[PrintEdge, a.statrep.edgeNameOrder]; RETURN}; PrintStatExp: PROC [to: IO.STREAM, act: CellType, nameGen: NameGenerator] ~ { a: Array = act.asArray; ect: CellType ~ act.EltType[]; first: BOOL _ TRUE; EnsureNamed: PROC [part: Part] ~ { [] _ act.d.SteppyDescribe[part, ect, nameGen]; RETURN}; IF NOT printStatRep THEN ect.EnumCTParts[p, TRUE, TRUE, EnsureNamed]; PrintForPorts[to, a.dumrep.apToWire, a.dumrep.dwSub, a.dumrep.dwParent, act, BiRels.EnumSeqOfSet[act.TopParts[p], IF sortTops THEN act.nameOrder[p] ELSE Sets.alleq], act, a.dumrep.dwSpace, nameGen]; RETURN}; IsArray: PROC [ct: CellType] RETURNS [pass: BOOL] = {pass _ ct.asArray # NIL}; Is1D: PROC [ct: CellType] RETURNS [BOOL] ~ {RETURN [ct.asArray#NIL AND (ct.asArray.size2[X]=1 OR ct.asArray.size2[Y]=1)]}; Is2D: PROC [ct: CellType] RETURNS [BOOL] ~ {RETURN [ct.asArray#NIL AND ct.asArray.size2[X]#1 AND ct.asArray.size2[Y]#1]}; PrintArrays: PROC [to: IO.STREAM, d: Design, nameGen: NameGenerator _ NIL, pacify: IO.STREAM _ NIL] = { PrintDesignSubset[to, d, nameGen, pacify, IsArray]; }; END. ^LichenPrintingImpl.Mesa Last tweaked by Mike Spreitzer on April 12, 1989 4:00:36 pm PDT Ê+˜šœ™Icode™?—J˜KšÏk œœ œx˜­K˜šÏnœœ˜!Kšœœ œg˜šKšœ˜Kšœ˜—K˜Kšœœœœ'žœ žœ œœ˜ŒK˜Kšœ œ˜Kšœ œ˜Kšœ œœ˜K˜šž œœœœ œžœœ˜BKšœœœœ˜:Kšœ ˜ Kšœ œœ ˜Kšœ ˜ Kšœ˜—K˜š ž œœœœ œœ˜=Kšœœœœ˜:Kšœ ˜ Kšœœœ ˜'Kšœ ˜ Kšœ˜—K˜šžœœœ&œœœ œœ œœœžœœ˜¹Kš œœœ œœ œ.˜eKš œœœ œœ œ ˜AKšœœ˜ KšœQ˜Qšžœœœœ˜2Kšœœœ˜Kšœœ˜Kšœœ^˜pKšœœœ˜K˜Kšœ˜šœ˜šœ˜Kšœ˜KšœœœK˜\K˜—šœ˜KšœœE˜LKšœœœ?˜PK˜——šœœœ˜KšœP˜PKšœ$˜$—Kšœ˜K˜šœœœ˜Kšœ4˜4KšœE˜E—Kšœœ*œœ ˜IK˜ Kšœœ˜—šœœœ˜Kšœ=œ˜CKšœ$˜$K˜—Kšœ(œœ˜5Kšœ˜—K˜š ž œœœœœ˜6šœ˜Kšœ œ œœ˜DKšœœ˜Kšœœ˜Kšœœ˜——K˜šžœœœ&œ œœ œœ œœœžœœ˜®Kš œœœ œœ œC˜|Kšœœœ˜K˜šœ˜šœ˜Kšœ˜KšœœœK˜\K˜—šœ˜KšœœE˜LKšœœœ?˜PK˜——Kšœ2˜2Kšœœ*œœ ˜IK˜ Kšœ˜—K˜šž œœœœœ&œ œœœ˜nKšœ*œ˜/Kšœ˜—K˜šžœœœœœ&œ œœœžœœ˜’Kšœœ˜ KšœQ˜Qšžœœœœ˜Kšœœ˜šžœœ˜Kšœ˜šœœœ˜KšœP˜PKšœ$˜$—Kšœ˜šœœœ˜Kšœ4˜4KšœE˜E—Kšœ˜—Kš œœœ œœ ˜>Kšœ˜—Kš œœœœœ6œ˜]Kš œœœ œœœ?˜jKšœN˜NKšœ œ>˜QKšœ"˜"K˜ Kšœ˜—K˜š žœœœœ Ïcœ ˜eKšœœœ˜Kšœœœ˜šžœœ˜#Kšœ˜šœœ œœ˜"Kšœœ"œœ˜LKšœ˜!K˜—Kšœ˜Kšœ$˜$Kšœ˜—K˜šœœ˜K˜ Kšœ ˜ —Kšœœœ˜#Kšœ˜—K˜š ž œœœœœ)œ˜ZKš ž œœœ#œ œ˜fKšžœœž˜«šž œœ˜Kšœ˜Kšœœœ˜šž œœœœ˜4Kšœ œœ˜Kšžœœœ ˜5Kšœ!œ ˜0Kšœ œœ˜—K˜Kš œœ œœœœ˜\K˜Kšœ˜—šžœœ˜Kšœ˜Kšœœœ˜šž œœœœ˜4Kšœ œœ˜Kšžœœœ ˜5Kšœ!œ ˜0Kšœ œœ˜—K˜ Kš œœ œœœœ˜\K˜Kšœ˜—šžœœ˜K˜Kšœ-˜-Kšœ˜—šžœœ˜K˜Kšœ˜K˜—Kš œœœ œœœ?˜jKšœ.˜.Kšœ˜Kšœœ˜#Kšœ˜Kšœ œœ˜GKšœœ ˜!šœ œœ˜Kšœ"œ ˜1Kšœ"œ ˜1K˜—šœœœ˜Kšœ"œ ˜1K˜—K˜K˜—K˜šžœœœœ$œ œœœ˜wKš œœœœœ˜IKšœ2˜2šœœœ˜K˜5KšœG˜GKšœ3˜3Kšœ/˜/K˜—Kšœ$˜(Kšœœœ˜Kšœœ˜#šœœœ˜Kšœ œœœ˜š œœœ œ˜7K˜&Kšœ˜—Kšœ˜—Kšœ.œ˜2Kšœœœ˜K˜š œœœœ˜$Kšœœœ˜Kšžœœ.˜;Kšœœ œœ˜2Kšœœžœ˜ Kšœ˜—K˜Kšœ˜ —K˜Kšœ œœ˜K˜š žœœ$œœœ˜DKšœœœ ˜)Kšœ.œ˜2Kšœœ œ˜Kšœ œœ˜šœœœ˜Kšœœœ˜Kšœ œ˜ šž œœœœ˜5Kš œœœœœ˜=Kšœœœœœœœ˜˜>Kšœ œg˜zKšœ_œ œœ*˜¯Kšœ˜—Kšœœ˜—K˜—K˜šž œœœœ6Ÿ œœœ1˜¢Kšœœœ˜šž œœœœ˜9Kšœ œ œ˜!šžœœ˜Kšœ'˜'Kšœ,˜,K˜Kšœ œ&œ˜?Kšœ Ÿ œ$œ˜?Kšœœœ˜2Kšœ Ÿ œ˜.Kšœœœ˜ Kšœœœ˜ Kšœœœ ˜#KšœŸ œ˜)KšœœJœœ˜qKšœŸ œ˜-Kšœœœ ˜,Kšœ'˜'Kšœ Ÿ œ œ˜=K˜,Kšœœ œœ ˜"Kšœœ œ˜Kšœ$˜$KšœœœœA˜jKšœ˜ Kšœ œ˜KšœF˜FKšœ˜ —Kšœœ œœ˜2Kšœœ ˜Kšœœ˜—K˜Kšœ œœ˜-K˜Kšœ˜—K˜Kšœœœ˜Kšœœœ˜Kšœœœ˜K˜š ž œœœœœ*œ˜XKšœ˜Kšœ˜šž œœ˜Kšœ[˜[—šž œœ˜K˜Kšœ˜K˜—šž œœ˜Kšœœœ˜K˜šœÏgÏdœœœœ ¡œœ˜QKš œ  ¡œ ¡œ˜Kšœ œœ œ˜!Kš œœ œœœ ˜UKšœ ¡œ  ¡œ˜2K˜Kšœ œ œ œ˜;Kšœ& œ œ ˜SKšœœ) œ œ ˜rK˜Kšœœ˜—K˜—šž œœ˜K˜ Kšœ˜Kšœ˜—˜K˜-Kšœ+˜+K˜—Kšœœ ˜"šœ œ˜K˜Kšœœ˜"—šœœ˜K˜Kšœœ ˜!K˜—šœœ˜K˜Kšœœ˜$K˜—Kšœœœ˜ K˜K˜—K˜šž œœœœ,˜MKšœ˜Kšœ˜Kšœ œœ˜šž œœ˜"Kšœ.˜.Kšœ˜—šž œœ˜%Kšœ œ œœ˜:Kšœœ$˜6Kšœ˜—Kšœœœ˜,Kšœ>˜>Kšœ˜—K˜šž œœœœ,˜MKšœ˜Kšœ˜Kšœœœ˜šž œœ˜"Kšœ.˜.Kšœ˜—Kš œœœœœ˜EKšœrœ œœ.˜ÆKšœ˜—K˜Kš žœœœœœ˜NK˜šžœœœœ˜(Kš œœ œœœ˜Q—K˜šžœœœœ˜(Kš œœ œœœ˜P—K˜šž œœœœ&œ œœœ˜gKšœ3˜3Kšœ˜—K˜Kšœ˜—…—A4V½