DIRECTORY CD, CDCells, CMos, CDPinObjects, Convert, EuControl, EuGen, EUtils, PW, PWCmos, PWDescr, PWPins, Rope; EUtilsImpl: CEDAR PROGRAM IMPORTS CD, CDCells, CMos, CDPinObjects, Convert, EuControl, EuGen, PW, PWCmos, PWDescr, PWPins, Rope EXPORTS EUtils = BEGIN OPEN EUtils; ctTopCell, ctOpRBus, ctOpLBus, ctBSBus, ctAPBus, ctKBus, ctCBus, ctRBus, ctAnyBusComplement, basicTstDriver: PW.ObPtr; regsInitialised: BOOL _ FALSE; CtTopFiller : PROC [design: CD.Design, obj: PW.ObPtr, height: INT, selectNameProc: PW.SelectNamesProc _ PW.KeepAll] RETURNS [filler: PW.ObPtr] = BEGIN PutContact: PW.ForEachPinProc = BEGIN layer: CD.Layer _ CDPinObjects.GetLayer[app]; SELECT TRUE FROM ~selectNameProc[CDPinObjects.GetName[app]] => obj _ NIL; layer=CMos.pol => obj _ contactAndPolyWire; ENDCASE => obj _ PWCmos.Rect[layer, [app.ob.size.x, height]]; END; minDy: INT; polyM2Contact, contactAndPolyWire: PW.ObPtr; polyM2Contact _ PW.Get[design, "polyM2Contact"]; minDy _ PW.Size[polyM2Contact].y; contactAndPolyWire _ PW.AbutY[design, polyM2Contact, PWCmos.Rect[CMos.pol, [4, height-minDy]]]; minDy _ PW.Size[polyM2Contact].y; SELECT height FROM <0 => ERROR; =0 => filler _ NIL; filler _ PW.TopFillerCell[design, obj, height, selectNameProc]; ENDCASE => filler _ PW.TransferCell[design, obj, PWPins.top, height, PutContact]; END; ContactFiller: PUBLIC PROC [design: CD.Design, ctrl, data: PW.ObPtr, selectNameProc: PW.SelectNamesProc _ PW.KeepAll] RETURNS [filler: PW.ObPtr] = BEGIN dy: INT _ PW.Size[data].y-PW.Size[ctrl].y; filler _ CtTopFiller[design, ctrl, dy, selectNameProc]; END; CtrlFiller: PUBLIC PROC [design: CD.Design, ctrl, data: PW.ObPtr, selectNameProc: PW.SelectNamesProc _ PW.KeepAll] RETURNS [filler: PW.ObPtr] = BEGIN filler _ ContactFiller[design, ctrl, data, selectNameProc]; END; Assemble: PUBLIC PROC [design: CD.Design, ctrl, data: PW.ObPtr, selectNameProc: PW.SelectNamesProc _ PW.KeepAll, fillerPos: Position _ Center] RETURNS [hSlice: PW.ObPtr] = BEGIN filler, wholeCtrl: PW.ObPtr; SELECT fillerPos FROM Top => {filler _ CtrlFiller[design, ctrl, data, selectNameProc]; wholeCtrl _ IF filler=NIL THEN ctrl ELSE PW.AbutY[design, ctrl, filler]; }; Bottom => {filler _ CtrlFiller[design, ctrl, data, selectNameProc]; wholeCtrl _ IF filler=NIL THEN ctrl ELSE PW.AbutY[design, filler, ctrl]; }; Center => {topFiller, botFiller: PW.ObPtr; dyTop, dyBot: INT; dy: INT _ PW.Size[data].y-PW.Size[ctrl].y; IF dy<0 THEN ERROR; dyBot _ dy/2; dyTop _ dy-dyBot; topFiller _ IF dyTop=0 THEN NIL ELSE CtTopFiller[design, ctrl, dyTop, selectNameProc]; botFiller _ IF dyBot=0 THEN NIL ELSE PW.TopFillerCell[design, ctrl, dyBot, selectNameProc]; wholeCtrl _ PW.AbutY[design, botFiller, ctrl, topFiller]; }; ENDCASE => ERROR; hSlice _ PW.AbutX[design, wholeCtrl, QadCR[design, wholeCtrl, data, EuGen.glueWidth], data]; END; InitMakeReg: PUBLIC PROC [design: CD.Design] = BEGIN IF regsInitialised THEN RETURN ELSE regsInitialised _ TRUE; ctAnyBusComplement _ PW.Get[design, "ctAnyBusComplement"]; ctTopCell _ PW.AbutX[design, PW.Get[design, "ctTopCell"], ctAnyBusComplement]; ctOpRBus _ PW.AbutX[design, PW.Get[design, "ctOpRBus"], ctAnyBusComplement]; ctOpLBus _ PW.AbutX[design, PW.Get[design, "ctOpLBus"], ctAnyBusComplement]; ctBSBus _ PW.AbutX[design, PW.Get[design, "ctBSBus"], ctAnyBusComplement]; ctAPBus _ PW.AbutX[design, PW.Get[design, "ctAPBus"], ctAnyBusComplement]; ctKBus _ PW.AbutX[design, PW.Get[design, "ctKBus"], ctAnyBusComplement]; ctCBus _ PW.AbutX[design, PW.Get[design, "ctCBus"], ctAnyBusComplement]; ctRBus _ PW.AbutX[design, PW.Get[design, "ctRBus"], ctAnyBusComplement]; basicTstDriver _ PW.Get[design, "basicTstDriver"]; END; BusNameToMuxObj: PROC [name: ROPE] RETURNS [obj: PW.ObPtr] = BEGIN obj _ SELECT TRUE FROM Rope.Equal[name, "r"] => ctRBus, Rope.Equal[name, "c"] => ctCBus, Rope.Equal[name, "k"] => ctKBus, Rope.Equal[name, "ap"] => ctAPBus, Rope.Equal[name, "bs"] => ctBSBus, Rope.Equal[name, "opL"] => ctOpLBus, Rope.Equal[name, "opR"] => ctOpRBus, Rope.Equal[name, "top"] => ctTopCell, ENDCASE => ERROR; END; MakeRegDP: PUBLIC PROC [design: CD.Design, regD: RegDescr] RETURNS [reg: PW.ObPtr] = BEGIN basicReg, interruptBuses: PW.ObPtr; revListOb, listOb: PW.ListOb _ NIL; flip: BOOL _ FALSE; keepInReg: LIST OF ROPE _ CONS[regD.out]; InitMakeReg[design]; IF ~regD.cutTopBot THEN keepInReg _ CONS["topBus", keepInReg]; basicReg _ PW.Inst[design, PW.Get[design, "basicRegister"], keepInReg, FALSE]; IF regD.interruptBuses#NIL THEN { interruptBuses _ PW.Inst[design, PW.Get[design, "interruptBusses"], regD.interruptBuses]; basicReg _ PW.AbutY[design, interruptBuses, basicReg];}; FOR l: LIST OF ROPE _ regD.inListOb, l.rest WHILE l#NIL DO revListOb _ CONS[BusNameToMuxObj[l.first], revListOb]; ENDLOOP; -- revListOb is the list of objects, from bottom to top, no flip FOR l: PW.ListOb _ revListOb, l.rest WHILE l#NIL DO listOb _ CONS[IF flip THEN PW.FlipY[design, l.first] ELSE l.first, listOb]; flip _ ~flip; ENDLOOP; -- listOb is the list of objects, from top to bottom, correct flip revListOb _ CONS[basicReg, PW.Reverse[listOb]]; -- add the register reg _ PW.ArrayX[design, PW.AbutListY[design, revListOb], EuGen.nbSlices]; END; MakeReg: PUBLIC PROC [design: CD.Design, regD: RegDescr] RETURNS [reg: PW.ObPtr] = BEGIN regDP, ctrl: PW.ObPtr; regDP _ MakeRegDP[design, regD]; ctrl _ PW.AbutListY[design, regD.ctrlListOb]; reg _ Assemble[design, ctrl, regDP,, regD.fillerPos]; END; MakeTstDriver: PUBLIC PROC [design: CD.Design, in: ROPE, out: ROPE, ctrlListOb: PW.ListOb _ NIL] RETURNS [tstDriver: PW.ObPtr] = BEGIN driver, ctrl: PW.ObPtr; InitMakeReg[design]; driver _ PW.Inst[design, basicTstDriver, LIST[in, out], FALSE]; ctrl _ PW.AbutListY[design, ctrlListOb]; tstDriver _ Assemble[design, ctrl, PW.ArrayX[design, driver, EuGen.nbSlices]]; END; MakeDBus: PUBLIC PROC [design: CD.Design, in: ROPE, dStAd: INT] RETURNS [dBus: PW.ObPtr] = BEGIN dBusGadget, ctrl: PW.ObPtr; regscdpd, regscdpu: PWDescr.Descriptor; dBusGadget _ PW.Inst[design, basicTstDriver, LIST[in, "kOut"], FALSE]; regscdpd _ EuGen.EmptyDescrRegsPD[]; regscdpu _ EuGen.EmptyDescrRegsPU[]; PWDescr.SetBit[regscdpu, "nPhB", TRUE]; PWDescr.SetBit[regscdpu, "Vbias", TRUE]; PWDescr.SetBit[regscdpd, "DExecute", TRUE]; PWDescr.SetInt[regscdpd, "DStateAddress", dStAd]; ctrl _ EuControl.Nand[design, regscdpd, regscdpu]; dBus _ Assemble[design, ctrl, PW.ArrayX[design, dBusGadget, EuGen.nbSlices]]; END; MakeRegWithDBus: PUBLIC PROC [design: CD.Design, regD: RegDescr, dStAd: INT] RETURNS [both: PW.ObPtr] = BEGIN reg, dBus: PW.ObPtr; reg _ MakeReg[design, regD]; dBus _ MakeDBus[design, regD.out, dStAd]; both _ PW.AbutY[design, reg, dBus]; END; QadCR, QuickandDirtyChannelRouter: PUBLIC PROC [design: CD.Design, left, right: PW.ObPtr, width: INT, useGnd: BOOL _ TRUE] RETURNS [channel: PW.ObPtr] = BEGIN ParseLeft: PWPins.AppEnumerator = BEGIN side: PWPins.Side _ PWPins.GetSide[left, app].side; IF side#PWPins.right THEN RETURN; IF Rope.Equal[CDPinObjects.GetName[app], powerName] THEN RETURN; IF Rope.Equal[CDPinObjects.GetName[app], otherPower] THEN RETURN; leftPins[nbL] _ app; nbL _ nbL+1; END; ParseRightAndGnd: PWPins.AppEnumerator = BEGIN side: PWPins.Side _ PWPins.GetSide[left, app].side; IF side#PWPins.left THEN RETURN; IF Rope.Equal[CDPinObjects.GetName[app], otherPower] THEN RETURN; IF Rope.Equal[CDPinObjects.GetName[app], powerName] THEN {gndPins[nbG] _ app; nbG _ nbG+1} ELSE {rightPins[nbR] _ app; nbR _ nbR+1}; END; SortArray: PROC [pins: ArrayPins, nb: INT] RETURNS [sortedPins: ArrayPins] = BEGIN MinY: PROC RETURNS [minPin: CD.ApplicationPtr] = BEGIN minY: INT _ LAST[INT]; -- y-coord of minPin minN: INT _ 0; -- location of minPin in array FOR i: INT IN [0..nb) DO IF pins[i]#NIL THEN IF pins[i].location.y=prevRightY+okDY) OR (~wasGoingUp AND rightY>=prevLeftY+okDY); IF reset THEN {IF goingUp THEN trackX _ initTackX ELSE trackX _ 6} ELSE {IF goingUp THEN trackX _ trackX-incrTrackX ELSE trackX _ trackX+incrTrackX}; PW.IncludeInCell[design, channel, PWCmos.Rect[CMos.met2, [6, 8]], [width-6, rightY]]; PW.IncludeInCell[design, channel, PWCmos.Contact[CMos.met2, CMos.met], [width-16, rightY-1]]; PW.IncludeInCell[design, channel, PWCmos.Rect[CMos.met, [width-trackX-16, 8]], [trackX, rightY]]; PW.IncludeInCell[design, channel, PWCmos.Rect[CMos.met, [8, ABS[rightY-leftY]+8]], [trackX, MIN[leftY, rightY]]]; PW.IncludeInCell[design, channel, PWCmos.Rect[CMos.met, [trackX, leftPin.ob.size.y]], [0, leftY]]; END; ArrayPins: TYPE = ARRAY[0..50) OF CD.ApplicationPtr; leftPins, rightPins, gndPins: ArrayPins; nbL, nbR, nbG: INT _ 0; initTackX: INT _ width-24; incrTrackX: INT _ 16; -- 8 lambdas okDY: INT _ 16; -- 8 lambdas trackX, prevLeftY, prevRightY, leftY, rightY: INT; powerName, otherPower: ROPE; goingUp, wasGoingUp, firstTime: BOOL _ TRUE; iRectL, iRectR: CD.Rect; IF useGnd THEN {powerName _ "gnd"; otherPower _ "vdd"} ELSE {powerName _ "vdd"; otherPower _ "gnd"}; IF PW.Size[left].y#PW.Size[right].y THEN ERROR; channel _ PW.CreateEmptyCell[]; iRectL _ CD.InterestRect[left]; iRectR _ CD.InterestRect[right]; CDCells.SetInterestRect[channel, [0, 0, width, PW.Size[left].y]]; -- set interestRect of channel [] _ PWPins.EnumerateEdgePins[left, ParseLeft]; [] _ PWPins.EnumerateEdgePins[right, ParseRightAndGnd]; IF nbL#nbR THEN ERROR; leftPins _ SortArray[leftPins, nbL]; rightPins _ SortArray[rightPins, nbR]; FOR i: INT IN [0..nbG) DO PW.IncludeInCell[design, channel, PWCmos.Rect[CMos.met2, [width, gndPins[i].ob.size.y]], [0, gndPins[i].location.y-iRectR.y1]]; -- where it lands ENDLOOP; FOR i: INT IN [0..nbL) DO RouteTrack[leftPins[i], rightPins[i]]; ENDLOOP; PW.IncludeInDirectory[design, channel, "channel"]; END; TreeRouter: PUBLIC PROC [design: CD.Design, template: PW.ObPtr, height: INT] RETURNS [channel: PW.ObPtr] = BEGIN Level: PROC [index: INT] RETURNS [level: INT] = BEGIN FOR i: INT IN [0..31) DO IF PW.XthBitOfN[i, index] THEN {level _ i; EXIT}; ENDLOOP; END; ParsePins: PWPins.AppEnumerator = BEGIN side: PWPins.Side _ PWPins.GetSide[template, app].side; IF side#PWPins.top THEN RETURN; IF Rope.Equal[CDPinObjects.GetName[app], "bus"] THEN PW.IncludeInCell[design, channel, bus, [app.location.x-IRect.x1, 0]] ELSE { val, d, index, lr: INT; [val, d, lr] _ ParseName[app]; index _ 6*val+2*d+lr; -- just a unique id IF otherPins[index]#NIL THEN ERROR; IF firstPins[index]=NIL THEN firstPins[index] _ app ELSE otherPins[index] _ app;}; END; ParseName: PROC [pin: CD.ApplicationPtr] RETURNS [val, d, lr: INT] = BEGIN s, length: INT; name: ROPE; IF pin=NIL THEN RETURN; name _ CDPinObjects.GetName[pin]; s _ Rope.Index[name, 0, "["]; SELECT TRUE FROM Rope.Match["g*", name] => {d _ 0}; Rope.Match["p*", name] => {d _ 1}; Rope.Match["c*", name] => {d _ 2}; ENDCASE => ERROR; SELECT TRUE FROM Rope.Match["*0[*", name] => {lr _ 0}; Rope.Match["*1[*", name] => {lr _ 1}; ENDCASE => ERROR; length _ Rope.Length[name]; name _ Rope.Substr[name, s+1, length-s-2]; -- now only the number is left val _ Convert.IntFromRope[name]; END; RouteTrack: PROC [pin1, pin2: CD.ApplicationPtr] = BEGIN n, p, val, d, x1, x2, y: INT; m1Track, m2Track, ct: PW.ObPtr; IF pin1=NIL OR pin2=NIL THEN RETURN; [val, d] _ ParseName[pin1]; n _ Level[val]; p _ 3*n+d; -- p is the number of the track, start from the ground x1 _ pin1.location.x-IRect.x1; x2 _ pin2.location.x-IRect.x1; y _ (p-3 )*spacing; m1Track _ PWCmos.Rect[CMos.met, [pin1.ob.size.x, y]]; ct _ PWCmos.Contact[CMos.met, CMos.met2]; m2Track _ PWCmos.Rect[CMos.met2, [ABS[x1-x2], 8]]; PW.IncludeInCell[design, channel, m1Track, [x1, 0]]; PW.IncludeInCell[design, channel, m1Track, [x2, 0]]; PW.IncludeInCell[design, channel, ct, [x1, y]]; PW.IncludeInCell[design, channel, ct, [x2, y]]; PW.IncludeInCell[design, channel, m2Track, [MIN[x1, x2], y]]; END; spacing: INT = 18; -- use PWCmos to make it more meta ArrayPins: TYPE = ARRAY[0..400) OF CD.ApplicationPtr; firstPins, otherPins: ArrayPins; -- pairs to route together IRect: CD.Rect _ CD.InterestRect[template]; bus: PW.ObPtr _ PWCmos.Rect[CMos.met, [6, height]]; channel _ PW.CreateEmptyCell[]; CDCells.SetInterestRect[channel, [0, 0, PW.Size[template].x, height]]; [] _ PWPins.EnumerateEdgePins[template, ParsePins]; FOR i: INT IN [0..200) DO RouteTrack[firstPins[i], otherPins[i]]; ENDLOOP; PW.IncludeInDirectory[design, channel, "channel"]; END; END. zEUtilsImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Last Edited by: Monier, July 8, 1985 4:37:36 pm PDT -- Cells for making registers -- Control descriptors -- A special filler for the control: if there is enough space, inserts contacts poly/m2 on every poly wire ContactFiller: PUBLIC PROC [design: CD.Design, ctrl, data: PW.ObPtr, selectNameProc: PW.SelectNamesProc _ PW.KeepAll] RETURNS [filler: PW.ObPtr] = BEGIN PutContact: PW.ForEachPinProc = BEGIN layer: CD.Layer _ CDPinObjects.GetLayer[app]; SELECT TRUE FROM ~selectNameProc[CDPinObjects.GetName[app]] => obj _ NIL; layer=CMos.pol => obj _ contactAndPolyWire; ENDCASE => obj _ PWCmos.Rect[layer, [app.ob.size.x, dy]]; END; minDy: INT = 20; polyM2Contact: PW.ObPtr _ PW.Get[design, "polyM2Contact"]; contactAndPolyWire: PW.ObPtr _ PW.AbutY[design, polyM2Contact, PWCmos.Rect[CMos.pol, [4, dy-minDy]]]; dy: INT _ PW.Size[data].y-PW.Size[ctrl].y; SELECT dy FROM <0 => ERROR; =0 => filler _ NIL; filler _ PW.TopFillerCell[design, ctrl, dy, selectNameProc]; ENDCASE => filler _ PW.TransferCell[design, ctrl, PWPins.top, dy, PutContact]; END; -- Returns a filler for the control: ctrl is the template, data shows the height; CtrlFiller: PUBLIC PROC [design: CD.Design, ctrl, data: PW.ObPtr, selectNameProc: PW.SelectNamesProc _ PW.KeepAll] RETURNS [filler: PW.ObPtr] = BEGIN dy: INT _ PW.Size[data].y-PW.Size[ctrl].y; IF dy<0 THEN ERROR; filler _ IF dy=0 THEN NIL ELSE PW.TopFillerCell[design, ctrl, dy, selectNameProc]; END; -- Makes a very common assembly: control, data, filler(s) and routing; -- Must be run before making any register -- Register only, no control -- Keep only one contact to output -- Add a short cell which interrupts some of the buses, if required -- Form the multiplexer -- "out" should be "r", "c", "k", "ap", "bs", "opL", "opR", or "down" -- "inListOb" and "ctrlListOb" must be specified from TOP to BOTTOM -- Returns a register with its control -- Control -- The assembly -- Make a cell with the correct input bus, and output on kBus -- Control -- The assembly -- Make a cell with the correct input bus, and output on kBus -- Control PWDescr.SetBit[regscdpd, "DHold", TRUE]; -- The assembly -- Route the control to the datapath; -- Initialize -- Decide if we reset the track position, and if so do it -- Draw the m2 wire on the right side -- via: centered on the m2 wire -- "top" horizontal m1 wire -- vertical m1 wire (track) -- "bottom" horizontal m1 wire -- Get the three sets of pins in their respective arrays -- Sort them by y-coordinate -- The gnd pins: a straight m2 wire -- For each pair, put 3 wires of m1, one via, one wire m2, and update the x-coord of the vertical track -- Used by the carry propagator to route cells in a tree-like topology -- The level is the position of the rightmost zero in the binary representation of the index -- level starts at zero -- a pin at level n will use track p=3*n+d where d=0 (g), d=1 (p), d=2 (c) -- Routes the busses and stick the pins of the tree in two arrays -- A pin named "p1[17]" returns val=17, d=1 (p), and lr=1 -- Find the opening bracket -- Distinguish g, p, and c -- Distinguish g0 from g1 -- Recover the index 17 from "p1[17]" -- Both pins carry the same name, and correspond to a track -- Prepare empty channel -- Get the pins, and place the vertical busses unrelated to the routing -- For each pair of pins, put 2 wires of m1, two vias, and one wire m2 Κœ˜– "Cedar" stylešœ™Jšœ Οmœ1™Jšœ žœžœ*žœ˜OJ™Cšžœžœžœ˜!šœžœ˜!Jšžœ!˜#Jšœ˜—Jšœ žœ,˜9—J™š žœžœžœžœžœžœž˜:Jšœ žœ'˜7JšžœΟc@˜I—š žœžœžœžœž˜3Jš œ žœžœžœžœžœ˜LJšœ ˜ Jšžœ B˜K—Jšœ žœ žœ ˜CJšœžœžœ/˜IJšžœ˜——J˜J˜J™EšœC™CJ™&š Ÿœžœžœ žœžœžœŸ˜RJšž˜Jšœ žœ˜Jšœ ˜ J™ Jšœžœ$˜-J™Jšœ5˜5Jšžœ˜—J˜šŸ œžœžœ žœ žœžœ žœ žœžœ žœ ˜Jšž˜Jšœžœ˜Jšœ˜J™=Jšœ žœžœ žœ˜@J™ Jšœžœ˜(J™Jšœ#žœ)˜NJšžœ˜—J˜šŸœžœžœ žœ žœ žœžœžœ ˜[Jšž˜Jšœžœ˜Jšœ'˜'J™=Jšœ žœžœžœ˜GJ™ Jšœ$˜$Jšœ$˜$Jšœ!žœ˜'Jšœ"žœ˜(Jšœ%žœ˜+Jšœ"žœ™(Jšœ1˜1Jšœ2˜2J™Jšœžœ-˜MJšžœ˜——˜šŸœžœžœ žœ žœžœžœ ˜hJšž˜Jšœ žœ˜Jšœ˜Jšœ)˜)Jšœžœ˜#Jšžœ˜——J˜J˜šœ&™&šŸœŸœžœžœ žœžœžœ žœžœžœ žœ ˜™Jšž˜šŸ œ˜"Jšž˜Jšœ3˜3Jšžœžœžœ˜!Jšžœ2žœžœ˜@Jšžœ3žœžœ˜AJšœ!˜!Jšžœ˜—šŸœ˜)Jšž˜Jšœ3˜3Jšžœžœžœ˜ Jšžœ3žœžœ˜Ašžœ2˜4Jšžœ#˜'—Jšžœ%˜)Jšžœ˜—J˜šŸ œžœžœžœ˜MJšž˜šŸœžœžœ žœ˜1Jšž˜Jšœžœžœžœ ˜+Jšœžœ  ˜0šžœžœžœ ž˜š žœ žœžœžœžœ˜4Jšœ7˜7—Jšžœ˜—Jšœ žœ˜Jšžœ˜—šžœžœžœ ž˜Jšœ˜Jšžœ˜—Jšžœ˜—šŸ œžœžœ˜:Jšž˜Jšœžœžœ˜Jšœ'˜'Jšœ'˜'Jšœ%˜%J™šžœ žœ˜Jšœ žœ˜Jšœ%˜%Jšœ'˜'Jšžœ žœžœ ˜4—šžœ˜Jšœ0˜0—J™9Jšœžœžœžœ˜]Jš žœžœžœ žœžœ ˜BJšžœžœ žœžœ˜RJ™%šžœ˜Jšœ ˜ Jšœ ˜ Jšœ˜—J™šžœ˜Jšœ ˜ Jšœ%˜%Jšœ˜—J™šžœ˜Jšœ ˜ Jšœ-˜-Jšœ˜—J™šžœ˜Jšœ ˜ Jšœžœ˜1Jšœ žœ˜—J™šžœ˜Jšœ ˜ Jšœ4˜4Jšœ ˜ —Jšžœ˜—J˜Jš Ÿ œžœžœžœžœ˜4Jšœ(˜(Jšœžœ˜Jšœ žœ ˜Jšœ žœ  ˜#Jšœžœ  ˜Jšœ.žœ˜2J˜Jšœžœ˜Jšœ ž œ˜,J˜J˜Jšžœžœ)˜7Jšžœ)˜-Jš žœžœžœžœžœ˜/J˜Jšœ žœ˜Jšœ˜Jšœ ˜ Jšœ/žœ ˜`J™8Jšœ/˜/Jšœ7˜7J˜J™Jšžœ žœžœ˜Jšœ$˜$Jšœ&˜&J™#šžœžœžœ ž˜šžœ˜Jšœ ˜ Jšœ7˜7Jšœ) ˜:—Jšžœ˜—J™gšžœžœžœ ž˜Jšœ&˜&Jšžœ˜—J˜Jšžœ0˜2Jšžœ˜——J™™FšŸ œž œ žœžœžœžœ žœ ˜kJšž˜J˜J™\J™J™Jš Ÿœžœ žœžœ žœ˜0Jšž˜šžœžœžœ ž˜Jšžœžœžœ žœ˜1Jšžœ˜—Jšžœ˜—J•StartOfExpansion[]™AšŸ œ˜"Jšž˜Jšœ7˜7Jšžœžœžœ˜šžœ.˜0JšžœžœB˜I—šžœ˜Jšœžœ˜Jšœ˜Jšœ ˜)Jšžœžœžœžœ˜#Jšžœžœžœžœ˜R—Jšžœ˜—J™9š Ÿ œžœžœžœžœ˜EJšž˜Jšœ žœ˜Jšœžœ˜ Jšžœžœžœžœ˜Jšœ!˜!J™Jšœ˜J™šž˜Jšœ#˜#Jšœ#˜#Jšœ#˜#Jšžœžœ˜—J™šž˜Jšœ&˜&Jšœ&˜&Jšžœžœ˜—J™%Jšœ˜Jšœ+ ˜IJšœ ˜ Jšžœ˜—J™;šŸ œžœžœ˜3Jšž˜Jšœžœ˜Jšœžœ˜Jš žœžœžœžœžœžœ˜$Jšœ˜Jšœ˜Jšœ  6˜AJšœ˜Jšœ˜Jšœ˜Jšœ5˜5Jšœ)˜)Jšœ"žœ ˜2J˜Jšžœ2˜4Jšžœ2˜4Jšžœ-˜/Jšžœ-˜/Jšžœ*žœ˜=J˜Jšžœ˜—J˜Jšœ žœΟgœ "˜5Jš œ žœžœ žœžœ˜5Jšœ! ˜;Jšœžœžœ˜+Jšœžœ,˜3J˜J™Jšœ žœ˜Jšœ(žœ˜FJ™GJšœ3˜3J™Fšžœžœžœ ž˜Jšœ'˜'Jšžœ˜—J˜Jšžœ0˜2Jšžœ˜——Jšžœ˜——…—2ΰRφ