DIRECTORY CD, Convert, DABasics, IO, Rope, Route, RouteChannel, RouteDiGraph, RoutePrivate, RouteUtil, RTBasic, TerminalIO; RouteChannelUtilImpl: CEDAR PROGRAM IMPORTS Convert, IO, Rope, Route, RouteChannel, RouteDiGraph, RouteUtil, TerminalIO EXPORTS RouteChannel SHARES Route = { trackSequenceName: PUBLIC ARRAY RouteChannel.TrackSequence OF Rope.ROPE _ ["start", "outsideInTop", "outsideInBottom", "botToTop", "topToBot"]; directionSequenceName: PUBLIC ARRAY RouteChannel.DirectionSequence OF Rope.ROPE _ ["start", "leftToRight", "rightToLeft", "alternateLeft", "alternateRight"]; EnumPins: PUBLIC PROC [pinPosition: RouteChannel.PinPosition, eachAction: RouteChannel.EachPinActionProc] RETURNS [quit: BOOLEAN _ FALSE]= { pin: RouteChannel.ChanPin; IF pinPosition = NIL THEN RETURN; pin _ pinPosition.pins[chanBottom]; IF pin # NIL AND pin.kindOfPin # noPin THEN { quit _ eachAction[pinPosition, pin]; IF quit THEN RETURN; }; pin _ pinPosition.pins[chanTop]; IF pin # NIL AND pin.kindOfPin # noPin THEN { quit _ eachAction[pinPosition, pin]; IF quit THEN RETURN; }; FOR interiorList: RouteChannel.ChanPinList _ pinPosition.innerPins, interiorList.rest WHILE interiorList # NIL DO quit _ eachAction[pinPosition, interiorList.first]; IF quit THEN RETURN; ENDLOOP; }; EnumPinsOnSeg: PUBLIC PROC [seg: RouteChannel.Segment, eachAction: RouteChannel.EachPinActionProc] RETURNS [quit: BOOLEAN _ FALSE]= { pin: RouteChannel.ChanPin; IF seg = NIL THEN RETURN; pin _ seg.exteriorPins[chanLeft]; IF pin # NIL THEN { quit _ eachAction[pin.pinPosition, pin]; IF quit THEN RETURN; }; pin _ seg.exteriorPins[chanRight]; IF pin # NIL THEN { quit _ eachAction[pin.pinPosition, pin]; IF quit THEN RETURN; }; FOR interiorList: RouteChannel.ChanPinList _ seg.interiorPins, interiorList.rest WHILE interiorList # NIL DO quit _ eachAction[pin.pinPosition, interiorList.first]; IF quit THEN RETURN; ENDLOOP; }; EnumTracks: PUBLIC PROC [chanTracks: RouteChannel.RoutingChannelTracks, eachAction: RouteChannel.EachTrackActionProc] RETURNS [quit: BOOLEAN _ FALSE] = { FOR trackIndex: RouteChannel.ZMaxTracks IN [1..chanTracks.count] WHILE ~quit DO quit _ eachAction[chanTracks.tracks[trackIndex], trackIndex]; ENDLOOP; }; EnumPinPositions: PUBLIC PROC [chanPins: RouteChannel.RoutingChannelPins, eachAction: RouteChannel.EachPinPositionActionProc] RETURNS [quit: BOOLEAN _ FALSE] = { FOR pinIndex: RouteChannel.ZMPinsOnCh IN [1..chanPins.count] WHILE ~quit DO quit _ eachAction[chanPins.sides[pinIndex], pinIndex]; ENDLOOP; }; Destroy: PUBLIC PROC [chanData: RouteChannel.ChannelData] ~ { RouteChannel.DestroyOldConstraints[chanData]; RouteChannel.ClearChan[chanData]; }; ClearChan: PUBLIC PROCEDURE[chanData: RouteChannel.ChannelData] = { EachPin: RouteChannel.EachPinActionProc = { pin.conctSeg[chanLeft] _ pin.conctSeg[chanRight] _ NIL; pin.altConctSeg[chanLeft] _ pin.altConctSeg[chanRight] _ NIL; pin.pinPosition _ NIL; pin.pin _ NIL}; ClearTrack: RouteChannel.EachTrackActionProc = { nextSeg: RouteChannel.Segment; FOR seg: RouteChannel.Segment _ track.firstSeg, nextSeg WHILE seg # NIL DO [] _ RouteChannel.EnumPinsOnSeg[seg, EachPin]; seg.constraintNode _ NIL; seg.exteriorPins[chanLeft] _ seg.exteriorPins[chanRight] _ NIL; seg.interiorPins _ NIL; nextSeg _ seg.nextSeg; seg.nextSeg _ NIL; ENDLOOP; track.firstSeg _ NIL}; ClearPinPositions: RouteChannel.EachPinPositionActionProc = { [] _ RouteChannel.EnumPins[pinPosition, EachPin]; pinPosition.pins[chanBottom] _ pinPosition.pins[chanTop] _ NIL; pinPosition.innerPins _ NIL}; [] _ RouteChannel.EnumTracks[chanData.chanTracks, ClearTrack]; [] _ RouteChannel.EnumPinPositions[chanData.chanPins, ClearPinPositions]}; TrackLoc: PUBLIC PROC [chanTracks: RouteChannel.RoutingChannelTracks, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, track: RouteChannel.ZMaxTracks] RETURNS [loc: DABasics.Number _ 0] = { IF track <= 0 THEN RETURN; SELECT parms.routerUsed FROM channel => { trackNum: RouteChannel.ZMaxTracks _ chanTracks.tracks[track].trackNum; tMinusOne: DABasics.Number _ trackNum - 1; --to coerce to 32 bits loc _ rules.trunkToEdge + tMinusOne*rules.trunkToTrunk; }; switchBox => loc _ chanTracks.tracks[track].trackPos; ENDCASE => ERROR; --??? call the implementor }; TrackSeg: PUBLIC PROC [chanTracks: RouteChannel.RoutingChannelTracks, track: RouteChannel.MaxTracks] RETURNS [RouteChannel.Segment] = { trackNum: RouteChannel.ZMaxTracks _ chanTracks.tracks[track].trackNum; RETURN[chanTracks.tracks[trackNum].firstSeg]}; TrackSegAbs: PUBLIC PROC [chanTracks: RouteChannel.RoutingChannelTracks, track: RouteChannel.MaxTracks] RETURNS [RouteChannel.Segment] = { RETURN[chanTracks.tracks[track].firstSeg]}; ChannelWidth: PUBLIC PROC [chanTracks: RouteChannel.RoutingChannelTracks, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules] RETURNS [loc: DABasics.Number _ 0] = { SELECT parms.routerUsed FROM channel => { countMinusOne: DABasics.Number _ chanTracks.count-1; -- to coerce to 32 bits loc _ 2*rules.trunkToEdge + countMinusOne * rules.trunkToTrunk; }; switchBox => loc _ chanTracks.tracks[chanTracks.count].trackPos + rules.trunkToEdge; ENDCASE => ERROR; --??? call the implementor... }; ExtSideToIntSide: PUBLIC PROC [rules: Route.DesignRules, extSide: DABasics.Side] RETURNS [intSide: RouteChannel.ChanSide] = { chanDirection: DABasics.Direction _ rules.trunkDirection; IF chanDirection = horizontal THEN SELECT extSide FROM bottom => intSide _ chanBottom; right => intSide _ chanRight; top => intSide _ chanTop; left => intSide _ chanLeft; ENDCASE ELSE SELECT extSide FROM bottom => intSide _ chanLeft; right => intSide _ chanTop; top => intSide _ chanRight; left => intSide _ chanBottom; ENDCASE}; IntSideToExtSide: PUBLIC PROC [rules: Route.DesignRules, intSide: RouteChannel.ChanSide] RETURNS [extSide: DABasics.Side] = { chanDirection: DABasics.Direction _ rules.trunkDirection; IF chanDirection = horizontal THEN SELECT intSide FROM chanBottom => extSide _ bottom; chanRight => extSide _ right; chanTop => extSide _ top; chanLeft => extSide _ left; ENDCASE ELSE SELECT intSide FROM chanBottom => extSide _ left; chanRight => extSide _ top; chanTop => extSide _ right; chanLeft => extSide _ bottom; ENDCASE}; InfluenceTracks: PUBLIC PROC [rules: Route.DesignRules, wireWidth: NAT] RETURNS [tracks: NAT] = { spacing: DABasics.Number _ rules.trunkToTrunk - MAX[rules.trunkWidth, rules.contactSize]; tracks _ (wireWidth + spacing + rules.trunkToTrunk -1) /rules.trunkToTrunk; }; WriteResult: PUBLIC PROC [result: Route.ResultData, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, method: RouteChannel.Method] = { lambda: DABasics.Number _ parms.lambda; width: INT _ IF rules.trunkDirection = horizontal THEN result.routingRect.y2 - result.routingRect.y1 ELSE result.routingRect.x2 - result.routingRect.x1; TerminalIO.PutRope[Rope.Cat["\n channel width: ", Convert.RopeFromInt[width/lambda]]]; TerminalIO.PutRope[Rope.Cat[", number tracks: ", Convert.RopeFromInt[result.numTrunkTracks], "\n"]]; IF result.polyLength > 0 THEN TerminalIO.PutRope[Rope.Cat["\n poly length: ", Convert.RopeFromInt[result.polyLength/lambda], ", "]]; IF result.metalLength > 0 THEN TerminalIO.PutRope[Rope.Cat[" metal1 length: ", Convert.RopeFromInt[result.metalLength/lambda], ", "]]; IF result.metal2Length > 0 THEN TerminalIO.PutRope[Rope.Cat[" metal2 length: ", Convert.RopeFromInt[result.metal2Length/lambda], ", "]]; IF result.polyToMetal > 0 THEN TerminalIO.PutRope[Rope.Cat["\n number contacts: ", Convert.RopeFromInt[result.polyToMetal], ", "]]; IF result.metalToMetal2 > 0 THEN TerminalIO.PutRope[Rope.Cat["\n number vias: ", Convert.RopeFromInt[result.metalToMetal2], ", "]]; TerminalIO.PutF1[" number fails: %g", IO.int[result.numIncompletes]]; TerminalIO.PutRope[Rope.Cat["\n method: ", trackSequenceName[method.trackSequence],", ", directionSequenceName[method.directionSequence], "\n"]]}; FindConstraintLimits: PUBLIC PROC [ chanPins: RouteChannel.RoutingChannelPins, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, nextLower, nextHigher: RouteChannel.MPinsOnCh, pinAction: RouteChannel.EachPinActionProc] RETURNS [minLimit, maxLimit: RouteChannel.MPinsOnCh] = { testWidth: DABasics.Number _ RouteUtil.GetWidthWithContact[rules, parms.widestPin] + rules.branchSpacing; iPos: DABasics.Number _ chanPins.sides[nextLower].pLoc; minLimit _ nextLower; FOR limitIndex: RouteChannel.MPinsOnCh DECREASING IN [1 .. nextLower] WHILE chanPins.sides[limitIndex].pLoc + testWidth > iPos DO constraining: BOOLEAN _ RouteChannel.EnumPins[chanPins.sides[limitIndex], pinAction]; IF constraining THEN minLimit _ MIN[minLimit, limitIndex]; ENDLOOP; iPos _ chanPins.sides[nextHigher].pLoc; maxLimit _ nextHigher; FOR limitIndex: RouteChannel.MPinsOnCh IN [nextHigher .. chanPins.count] WHILE chanPins.sides[limitIndex].pLoc - testWidth < iPos DO constraining: BOOLEAN _ RouteChannel.EnumPins[chanPins.sides[limitIndex], pinAction]; IF constraining THEN maxLimit _ MAX[maxLimit, limitIndex]; ENDLOOP}; CheckPins: PUBLIC PROCEDURE[seg: RouteChannel.Segment, pin: RouteChannel.ChanPin, sideOfSeg: RouteChannel.ChanLRSide] = { IF seg = NIL THEN Route.Error[programmingError, "Pin data inconsistant"] ELSE IF pin = NIL THEN Route.Error[programmingError, "Pin data inconsistant"] ELSE { found: BOOLEAN _ FALSE; IF pin.conctSeg[sideOfSeg] # NIL THEN found _ pin.conctSeg[sideOfSeg] = seg; IF pin.altConctSeg[sideOfSeg] # NIL THEN found _ found OR pin.altConctSeg[sideOfSeg] = seg; IF ~found THEN Route.Error[programmingError, "Pin data inconsistant"]}}; CheckSegs: PUBLIC PROC [seg: RouteChannel.Segment, pin: RouteChannel.ChanPin] = { IF seg = NIL THEN Route.Error[programmingError, "Segment data inconsistant"] ELSE IF pin = NIL THEN Route.Error[programmingError, "Segment data inconsistant"] ELSE IF seg = pin.conctSeg[chanLeft] OR seg = pin.conctSeg[chanRight] THEN RETURN ELSE IF seg = pin.altConctSeg[chanLeft] OR seg = pin.altConctSeg[chanRight] THEN RETURN ELSE { found: BOOLEAN _ FALSE; FOR testPins: RouteChannel.ChanPinList _ seg.interiorPins, testPins.rest WHILE testPins # NIL AND ~found DO testPin: RouteChannel.ChanPin _ testPins.first; IF seg = testPin.conctSeg[chanLeft] OR seg = testPin.conctSeg[chanRight] THEN found _ TRUE; IF seg = testPin.altConctSeg[chanLeft] OR seg = testPin.altConctSeg[chanRight] THEN found _ TRUE; ENDLOOP; IF ~found THEN Route.Error[programmingError, "Segment data inconsistant"]}; }; AuditPins: PUBLIC PROC [chanPins: RouteChannel.RoutingChannelPins] = { EachPin: RouteChannel.EachPinActionProc = { segList: RouteChannel.SegmentList _ RouteChannel.GetSegsOnPin[pin]; IF segList = NIL THEN Route.Error[programmingError, "Pin not attatched to any segment"]; FOR segs: RouteChannel.SegmentList _ segList, segs.rest WHILE segs # NIL DO RouteChannel.CheckSegs[segs.first, pin]; ENDLOOP}; FOR index: RouteChannel.MPinsOnCh IN [1 .. chanPins.count] DO [] _ RouteChannel.EnumPins[chanPins.sides[index], EachPin]; ENDLOOP; }; AuditSegs: PUBLIC PROC [chanTracks: RouteChannel.RoutingChannelTracks] = { EachTrack: RouteChannel.EachTrackActionProc = { FOR seg: RouteChannel.Segment _ track.firstSeg, seg.nextSeg WHILE seg # NIL DO EachPin: RouteChannel.EachPinActionProc = { found: BOOLEAN _ FALSE; IF pin.conctSeg[chanLeft] # NIL THEN found _ pin.conctSeg[chanLeft] = seg; IF pin.conctSeg[chanRight] # NIL THEN found _ found OR pin.conctSeg[chanRight] = seg; IF pin.altConctSeg[chanLeft] # NIL THEN found _ found OR pin.altConctSeg[chanLeft] = seg; IF pin.altConctSeg[chanRight] # NIL THEN found _ found OR pin.altConctSeg[chanRight] = seg; IF ~found THEN Route.Error[programmingError, "Pin data inconsistant"]}; [] _ RouteChannel.EnumPinsOnSeg[seg, EachPin]; ENDLOOP}; [] _ RouteChannel.EnumTracks[chanTracks, EachTrack]; }; WriteConstraints: PUBLIC PROC [graph: RouteDiGraph.Graph] = { NodeProc: RouteDiGraph.EnumNodeProc = { nodeInfo: RouteChannel.SegmentConstraint _ NARROW[node.nodeInfo]; TerminalIO.PutRope[Rope.Cat["\n", " name: ", nodeInfo.name]]}; TerminalIO.PutRope[Rope.Cat["\n Constraint Graph: ", RouteDiGraph.SimpleRefAny[graph.graphInfo], "\n"]]; RouteDiGraph.WriteNodes[graph, NodeProc, RouteDiGraph.SimpleListArcNodeProc]; RouteDiGraph.WriteArcs[graph, RouteDiGraph.SimpleListArcProc, NodeProc]}; GetSegsOnPin: PUBLIC PROC [pin: RouteChannel.ChanPin] RETURNS [segList: RouteChannel.SegmentList _ NIL] = { cSegL: RouteChannel.Segment _ pin.conctSeg[chanLeft]; cSegR: RouteChannel.Segment _ pin.conctSeg[chanRight]; aSegL: RouteChannel.Segment _ pin.altConctSeg[chanLeft]; aSegR: RouteChannel.Segment _ pin.altConctSeg[chanRight]; IF cSegL # NIL THEN segList _ CONS[cSegL, segList]; IF cSegR # NIL AND cSegR # cSegL THEN segList _ CONS[cSegR, segList]; IF aSegL # NIL THEN segList _ CONS[aSegL, segList]; IF aSegR # NIL AND aSegR # aSegL THEN segList _ CONS[aSegR, segList]}; GetPinsOnSeg: PUBLIC PROC [seg: RouteChannel.Segment] RETURNS [pinList: RouteChannel.ChanPinList] = { pinList _ CONS[seg.exteriorPins[chanLeft], seg.interiorPins]; pinList _ CONS[seg.exteriorPins[chanRight], pinList] }; ComputeDensity: PUBLIC PROC [chanPins: RouteChannel.RoutingChannelPins, rules: Route.DesignRules] RETURNS [density: RouteChannel.Density] = { GetDensity: RouteChannel.EachPinActionProc = { leftSeg: RouteChannel.Segment _ pin.conctSeg[chanLeft]; rightSeg: RouteChannel.Segment _ pin.conctSeg[chanRight]; pinIndex: RouteChannel.MPinsOnCh _ pinPosition.pinIndex; IF rightSeg # NIL THEN IF rightSeg.exteriorPins[chanLeft] = pin THEN {lastDensity _ lastDensity + MAX[rules.trunkToTrunk, rightSeg.qWidth + rules.trunkSpacing]}; density.maxDensity _ MAX[density.maxDensity, lastDensity]; density.values[pinIndex] _ MAX[density.values[pinIndex], lastDensity]; IF leftSeg # NIL THEN IF leftSeg.exteriorPins[chanRight] = pin THEN {lastDensity _ lastDensity - MAX[rules.trunkToTrunk, leftSeg.qWidth + rules.trunkSpacing]}}; lastDensity: DABasics.Number _ 0; density _ NEW[RouteChannel.DensityRec]; FOR index: RouteChannel.MPinsOnCh IN [1 .. chanPins.count] DO pinPosition: RouteChannel.PinPosition _ chanPins.sides[index]; density.values[index] _ lastDensity; [] _ RouteChannel.EnumPins[pinPosition, GetDensity]; ENDLOOP; }; Combine: PUBLIC PROC [l1, l2, l3: RouteChannel.ChanPinList] RETURNS [RouteChannel.ChanPinList] = { RETURN[Union[l1, Union[l2, l3]]]}; Union: PROC [l1, l2: RouteChannel.ChanPinList] RETURNS[RouteChannel.ChanPinList] = { l: RouteChannel.ChanPinList _ NIL; UNTIL l2 = NIL DO IF l2.first # NIL THEN l _ CONS[l2.first, l]; l2 _ l2.rest; ENDLOOP; UNTIL l1 = NIL DO IF l1.first # NIL THEN IF ~MembChanPinList[l1.first, l] THEN l _ CONS[l1.first, l]; l1 _ l1.rest; ENDLOOP; RETURN[l]; }; -- of Union MembChanPinList: PROC [ref: RouteChannel.ChanPin, list: RouteChannel.ChanPinList] RETURNS [BOOL] = { UNTIL list = NIL DO IF list.first = ref THEN RETURN[TRUE]; list _ list.rest; ENDLOOP; RETURN[FALSE]; }; MembRopeList: PUBLIC PROC [ref: Rope.ROPE, list: LIST OF Rope.ROPE] RETURNS [BOOL] = { UNTIL list = NIL DO IF list.first = ref THEN RETURN[TRUE]; list _ list.rest; ENDLOOP; RETURN[FALSE]; }; GetRange: PUBLIC PROC [pinList: RouteChannel.ChanPinList] RETURNS [range: RTBasic.Range] = { range.l _ LAST[INT]; range.r _ - LAST[INT]; FOR list: RouteChannel.ChanPinList _ pinList, list.rest WHILE list # NIL DO pos: DABasics.Number _ list.first.pinPosition.pLoc; range.l _ MIN[range.l, pos]; range.r _ MAX[range.r, pos]; ENDLOOP}; PinsOnSide: PUBLIC PROC [seg: RouteChannel.Segment] RETURNS [left, top, right, bottom: BOOLEAN _ FALSE] ~ { EachPin: RouteChannel.EachPinActionProc = { IF pin.pinSide = chanBottom THEN bottom _ TRUE; IF pin.pinSide = chanTop THEN top _ TRUE; IF pin.pinSide = chanLeft THEN left _ TRUE; IF pin.pinSide = chanRight THEN right _ TRUE}; [] _ RouteChannel.EnumPinsOnSeg[seg, EachPin]; }; SegRange: PUBLIC PROC [seg: RouteChannel.Segment] RETURNS [range: RTBasic.Range] = { RETURN[[seg.exteriorPins[chanLeft].pinPosition.pLoc, seg.exteriorPins[chanRight].pinPosition.pLoc]] }; Length: PUBLIC PROC [seg: RouteChannel.Segment] RETURNS [length: DABasics.Number] = { length _ seg.exteriorPins[chanRight].pinPosition.pLoc - seg.exteriorPins[chanLeft].pinPosition.pLoc }; }. όRouteChannelUtilImpl.mesa Christian Le Cocq December 4, 1987 4:50:29 pm PST Copyright Σ 1985, 1986, 1987 by Xerox Corporation. All rights reserved. by Bryan Preas July 10, 1985 6:57:00 pm PDT last edited by Bryan Preas April 21, 1987 11:32:28 pm PDT try the bottom pin try the top pin try the interior pins try the left pin try the right pin try the interior pins Remove circular references so garbage collection can work remove circular references in channel routing empty all of the tracks of their segments convert an external side to an internal side. convert an internal side to an external side. find how far a track can influence another track ( in tracks) write the results TerminalIO.PutRope[Rope.Cat["\n Routing area: ", routingArea.name, ", channel width: ", Convert.RopeFromInt[width/lambda]]]; find the limits for constraints NOTE: needs more sophistication: keep track of maximun branch width count down from index to find the pin that can still effect index count up from index to find the pin that can still effect index make sure a pin points back to segment make sure a segment points back to pin make sure pin data is consistent make sure seg data is consistent find all of the segments attached to a pin NOTE: segs in conctSeg should never be same as in altConctSeg find all of the pins attached to a seg compute the track density for the current channel get the range of the pins in the pinList return range of line segment from pos1 to pos2. return range of line segment from pos1 to pos2. ΚL˜codešœ™K™1—˜KšœH™HKšœ.™.Kšœ;™;—K˜šΟk ˜ Kšœo˜qK˜—KšΠlnœœ˜#˜KšœL˜SKšœ ˜šœ ˜K˜—Kš œœœœœH˜Kš œœœ œœN˜K˜š ΟnœœœUœœœ˜ŒKšœ˜K˜Kšœœœœ˜!Kšœ™Kšœ#˜#šœœœœ˜-Kšœ$˜$Kšœœœ˜K˜—Kšœ™Kšœ ˜ šœœœœ˜-Kšœ$˜$Kšœœœ˜K˜—Kšœ™šœSœœ˜qKšœ3˜3Kšœœœ˜Kšœ˜—Kšœ˜K˜—š Ÿ œœœIœœœ˜…Kšœ˜K˜Kšœœœœ˜Kšœ™Kšœ!˜!šœœœ˜Kšœ(˜(Kšœœœ˜K˜—Kšœ™Kšœ"˜"šœœœ˜Kšœ(˜(Kšœœœ˜˜K˜——Kšœ™šœNœœ˜lKšœ7˜7Kšœœœ˜Kš˜—Kšœ˜K˜—š Ÿ œœœ_œœœ˜™šœ%œœ˜OKšœ=˜=Kš˜—Kšœ˜K˜—š Ÿœœœaœœœ˜‘šœ#œœ˜KKšœ6˜6Kš˜—Kšœ˜K˜—šŸœœœ)˜=Kšœ9™9K˜Kšœ-˜-Kšœ!˜!Kšœ˜K˜—šŸ œœ œ(˜CKšœ-™-K˜Kšœ)™)šŸœ$˜+K˜Kšœ3œ˜7Kšœ9œ˜=Kšœœ˜Kšœ œ˜K˜—šŸ œ&˜0K˜Kšœ˜šœ5œœ˜JKšœ.˜.Kšœœ˜Kšœ;œ˜?Kšœœ˜Kšœ˜Kšœœ˜Kšœ˜—Kšœœ˜K˜—šŸœ,˜=Kšœ1˜1Kšœ;œ˜?Kšœœ˜K˜—Kšœ>˜>K˜KšœJ˜JK˜—šŸœœœ‘œ˜ΜKšœ œœ˜šœ˜šœ ˜ KšœF˜FKšœ+Οc˜AKšœ7˜7Kšœ˜—Kšœ5˜5Kšœœ ˜,—Kšœ˜K˜—šŸœœœPœ˜‡KšœF˜FKšœ(˜.K˜—šŸ œœœPœ˜ŠKšœ%˜+K˜—šŸ œœœqœ˜°šœ˜šœ ˜ Kšœ5 ˜LKšœ?˜?K˜—KšœT˜TKšœœ ˜/—K˜K˜—šŸœœœ4œ%˜}K™-K™Kšœ9˜9šœ˜"šœ ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kš˜——š˜šœ ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜ ———šŸœœœ<œ˜}K™-K™Kšœ9˜9šœ˜"šœ ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kš˜——š˜šœ ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜ ——K˜—š Ÿœœœ'œœ œ˜aKšœ=™=K˜Kšœ0œ&˜YKšœK˜KKšœ˜K˜—šŸ œœœ˜4Kšœ&˜&Kšœ˜Kšœ ˜ Kšœ™Kšœ'˜'Kš œœœ#œ/œ/˜˜Kšœ™KšœY˜YKšœe˜ešœ˜Kšœl˜l—šœ˜Kšœi˜i—šœ˜Kšœi˜i—šœ˜Kšœj˜j—šœ˜ Kšœh˜h—KšœE˜EKšœ•˜•K˜K˜—šŸœœœ˜#Kšœ+˜+Kšœ&˜&KšœI˜IKšœ+˜+Kšœ1˜8Kšœ™K™CK˜Kšœi˜iK˜KšœA™AKšœ7˜7Kšœ˜š œ$ œœœ4˜Kšœœ@˜UKšœœ œ˜:Kšœ˜—K˜Kšœ?™?Kšœ'˜'Kšœ˜šœ$œ œ4˜„Kšœœ@˜UKšœœ œ˜:Kšœ˜ —K˜—šŸ œœ œ˜6Kšœ˜Kšœ'˜'Kšœ&™&K˜Kšœœœ7˜HKšœœœœ7˜Mšœ˜Kšœœœ˜šœœ˜%Kšœ&˜&—šœœ˜(Kšœœ"˜2—K˜Kšœœ:˜H—K˜—šŸ œœœ:˜QKšœ&™&K˜Kšœœœ;˜LKšœœœœ;˜QKš œœœœ˜QKš œœ!œ"œ˜Wšœ˜Kšœœœ˜š œFœ œœ˜kKšœ/˜/Kšœ"œ#œ œ˜[Kšœ%œ&œ œ˜aKšœ˜—Kšœœ=˜K—Kšœ˜K˜—šŸ œœœ0˜FKšœ ™ K˜šŸœ$˜+KšœC˜CKšœ œœC˜Xšœ5œœ˜KKšœ(˜(Kšœ˜ —K˜—šœœ˜=Kšœ;˜;Kšœ˜—K˜K˜—šŸ œœœ4˜JKšœ ™ K˜šŸ œ&˜/šœ8˜;Kšœœ˜K˜šŸœ$˜+Kšœœœ˜šœœ˜$Kšœ%˜%—šœœ˜%Kšœœ˜/—šœœ˜'Kšœœ!˜1—šœœ˜(Kšœœ"˜2—K˜Kšœœ9˜GK˜—Kšœ.˜.Kšœ˜ ——K˜Kšœ4˜4K˜—K˜šŸœœœ ˜=K˜šŸœ˜'Kšœ+œ˜AKšœB˜BK˜—Kšœh˜hKšœM˜MKšœI˜IK˜—š Ÿ œœœœ&œ˜kKšœ*™*Kšœ=™=K˜Kšœ5˜5Kšœ6˜6Kšœ8˜8Kšœ9˜9Kšœ œœ œ˜3Kš œ œœœ œ˜EKšœ œœ œ˜3Kš œ œœœ œ˜FK˜—šŸ œœœœ(˜eKšœ&™&K˜Kšœ œ/˜=Kšœ œ&˜4Kšœ˜K˜—šŸœœœGœ$˜K™1K˜šŸ œ$˜.Kšœ7˜7Kšœ9˜9Kšœ8˜8šœ œ˜šœ'˜-Kšœœ<˜\——Kšœœ"˜:Kšœœ(˜Fšœ œ˜šœ'˜-Kšœœ<˜\——K˜—Kšœ!˜!Kšœ œ˜'K˜šœœ˜=Kšœ>˜>Kšœ$˜$Kšœ4˜4Kšœ˜—Kšœ˜K˜—šŸœœœ(œ˜bKšœ˜"K˜—šŸœœ$œ˜TK˜Kšœœ˜"šœœ˜šœ œœ˜Kšœœ˜—Kšœ ˜ Kšœ˜—šœœ˜šœ œœ˜Kšœœœœ˜=—K˜ Kšœ˜—Kšœ˜ Kšœ  ˜K˜—šŸœœ=œœ˜dšœœ˜Kšœœœœ˜&Kšœ˜Kšœ˜—Kšœœ˜Kšœ˜K˜K˜—šŸ œœœ œœœœœœ˜Všœœ˜Kšœœœœ˜&Kšœ˜Kšœ˜—Kšœœ˜Kšœ˜K˜K˜—šŸœœœ%œ˜\K™(K˜Kšœ œœ˜Kšœ œœ˜šœ5œœ˜KKšœ3˜3Kšœ œ˜Kšœ œ˜Kšœ˜ —K˜—š Ÿ œœœœœœ˜kšŸœ$˜+Kšœœ œ˜/Kšœœœ˜)Kšœœœ˜+Kšœœ œ˜.K˜—Kšœ.˜.K˜—K˜šŸœœœœ˜TK™/K™Kšœc˜cKšœ˜K˜—šŸœœœœ˜UK™/K™Kšœc˜cKšœ˜——Kšœ˜—…—?nVΆ