DIRECTORY Basics, Bend, Heap, List, Sweep; AccurateIntersectImpl: CEDAR PROGRAM IMPORTS Basics, Bend, Heap, List, Sweep EXPORTS Sweep = BEGIN OPEN Sweep; XOR: PROC [a, b: BOOL] RETURNS [BOOL] ~ INLINE { RETURN[(a OR b) AND (NOT a OR NOT b)] }; IntersectEvent: TYPE = REF IntersectEventRec; IntersectEventRec: TYPE = RECORD [ time: Point, new: BOOLEAN _ FALSE, swap: BOOLEAN _ FALSE, isALine: BOOLEAN _ TRUE, line: Line, lineCarrier, lineRight: LineCarrier, next: IntersectEvent _ NIL]; CompareLL: PROC [e1, e2: Heap.Event] RETURNS[r: Basics.Comparison] ~ { event1: IntersectEvent _ NARROW[e1]; event2: IntersectEvent _ NARROW[e2]; r _ Basics.CompareINT[event1.time.y, event2.time.y]; IF r = equal THEN { IF event1.swap THEN RETURN[greater]; IF event2.swap THEN RETURN[less]; IF event1.new THEN RETURN[greater]; IF event2.new THEN RETURN[less]; r _ Basics.CompareINT[event1.time.x, event2.time.x]; }; RETURN[r]; }; CompareHL: PROC [e1, e2: Heap.Event] RETURNS[r: Basics.Comparison] ~ { event1: IntersectEvent _ NARROW[e1]; event2: IntersectEvent _ NARROW[e2]; r _ Basics.CompareINT[event1.time.y, event2.time.y]; IF r = equal THEN { IF event1.swap THEN RETURN[greater]; --swaps IF event2.swap THEN RETURN[less]; IF event1.new AND event1.isALine THEN RETURN[greater]; --new lines IF event2.new AND event2.isALine THEN RETURN[less]; IF NOT event1.new AND NOT event1.isALine THEN RETURN[greater]; --old hooks IF NOT event2.new AND NOT event2.isALine THEN RETURN[less]; IF event1.new AND NOT event1.isALine THEN { --new hooks IF event2.new AND NOT event2.isALine THEN RETURN[Basics.CompareINT[event1.time.x, event2.time.x]]; RETURN[greater] }; IF event2.new AND NOT event2.isALine THEN RETURN[less]; r _ Basics.CompareINT[event1.time.x, event2.time.x]; --both must be line removals }; RETURN[r]; }; CompareRC: PROC [e1, e2: Heap.Event] RETURNS[r: Basics.Comparison] ~ { event1: IntersectEvent _ NARROW[e1]; event2: IntersectEvent _ NARROW[e2]; r _ ComparePoints[event1.time, event2.time]; IF r = equal THEN { r _ IF event1.new THEN greater ELSE less; }; RETURN[r]; }; LineCarrier: TYPE = REF LineCarrierRec; LineCarrierRec: TYPE = RECORD[ isALine: BOOLEAN _ TRUE, carried: Line, lineLeft, lineRight: LineCarrier _ NIL ]; LineState: TYPE = REF LineStateRec; LineStateRec: TYPE = RECORD[ clientState: REF ANY, hooks: List.LORA _ NIL ]; NilCopy: PUBLIC PROC [stateIn: REF ANY] RETURNS [stateOut: REF ANY] ~ { RETURN[stateIn] }; NilCombine: PUBLIC PROC [state1, state2: REF ANY] RETURNS [state: REF ANY] ~ { RETURN[NIL] }; NilFlip: PUBLIC PROC [stateIn: REF ANY] RETURNS [stateOut: REF ANY] ~ { RETURN[NIL] }; Intersect: PUBLIC PROC [in: Graph, Copy: CopyLineProc _ NilCopy, Combine: CombineLineProc _ NilCombine, Flip: FlipLineProc _ NilFlip] RETURNS [out: Graph] ~ { FlipLine: PROC [line: Line] ~ { OPEN line; temp: Point _ above; above _ below; below _ temp; state _ Flip[state]; }; freeLC: LineCarrier _ NIL; NewLC: PROC [carried: Line, lineLeft, lineRight: LineCarrier _ NIL, isALine: BOOLEAN _ TRUE] RETURNS [alive: LineCarrier] ~ INLINE { IF freeLC = NIL THEN RETURN[NEW[LineCarrierRec_ [carried: carried, lineLeft: lineLeft, lineRight: lineRight, isALine: isALine]]] ELSE { alive _ freeLC; freeLC _ alive.lineRight; alive.carried _ carried; alive.lineLeft _ lineLeft; alive.lineRight _ lineRight; alive.isALine _ isALine; } }; TrashFreeLC: PROC [] ~ { UNTIL freeLC = NIL DO freeLC.lineLeft _ NIL; freeLC _ freeLC.lineRight; ENDLOOP; }; freeE: IntersectEvent _ NIL; NewE: PROC [time: Point _ NIL, line: Line _ NIL, isALine: BOOLEAN _ TRUE, new: BOOLEAN _ FALSE, swap: BOOLEAN _ FALSE] RETURNS [alive: IntersectEvent] ~ INLINE { IF freeE = NIL THEN RETURN[NEW[IntersectEventRec_ [time: time, line: line, isALine: isALine, new: new, swap: swap]]] ELSE { alive _ freeE; freeE _ alive.next; alive.time _ time; alive.line _ line; alive.isALine _ isALine; alive.new _ new; alive.swap _ swap; } }; TrashFreeE: PROC [] ~ { UNTIL freeE = NIL DO freeE.line _ NIL; freeE.lineCarrier _ freeE.lineRight _ NIL; freeE.time _ NIL; freeE _ freeE.next; ENDLOOP; }; InitialScanLines: PROC [l: Line] RETURNS [quit: BOOL _ FALSE] ~ { event:IntersectEvent _ NEW[IntersectEventRec _ [time: l.above, new: TRUE, line: l]]; YQ.InsertEvent[event]; l.state _ NEW[LineStateRec _ [clientState: l.state]]; }; LineLineProcessEvent: PROC [] ~ { OrderInsert: PROC [e: IntersectEvent] ~ { l: Line _ e.line; p: Point _ l.above; lc: LineCarrier; scan: LineCarrier _ XO; prev: LineCarrier _ NIL; UNTIL scan = NIL DO IF ComparePointLine[p, scan.carried] = greater THEN EXIT; prev _ scan; scan _ scan.lineLeft; ENDLOOP; e.lineCarrier _ lc _ NewLC[carried: l, lineLeft: scan, lineRight: prev]; e.time _ l.below; e.new _ FALSE; YQ.InsertEvent[e]; IF scan # NIL THEN {scan.lineRight _ lc; TestIntersect[YQ, scan, lc, p]}; IF prev # NIL THEN {prev.lineLeft _ lc; TestIntersect[YQ, lc, prev, p]} ELSE XO _ lc; }; OrderRemove: PROC [e: IntersectEvent] ~ { lc: LineCarrier _ e.lineCarrier; IF lc.lineRight # NIL THEN lc.lineRight.lineLeft _ lc.lineLeft ELSE XO _ lc.lineLeft; IF lc.lineLeft # NIL THEN { lc.lineLeft.lineRight _ lc.lineRight; IF lc.lineRight # NIL THEN TestIntersect[YQ, lc.lineLeft, lc.lineRight, e.time]; }; lc.lineRight _ freeLC; freeLC _ lc; lc.lineLeft _ NIL; e.next _ freeE; freeE _ e; }; OrderSwap: PROC [e: IntersectEvent] ~ { left: LineCarrier _ e.lineCarrier; right: LineCarrier _ e.lineRight; currentPoint: Point _ e.time; IF right.lineLeft = left THEN { hook: Line _ NEW[LineRec _ [above: NEW[PointRec _ [x: currentPoint.x, y: currentPoint.y+1]], below: currentPoint]]; left.lineRight _ right.lineRight; right.lineLeft _ left.lineLeft; left.lineLeft _ right; right.lineRight _ left; IF left.lineRight # NIL THEN { left.lineRight.lineLeft _ left; TestIntersect[YQ, left, left.lineRight, currentPoint]} ELSE XO _ left; IF right.lineLeft # NIL THEN { right.lineLeft.lineRight _ right; TestIntersect[YQ, right.lineLeft, right, currentPoint ]}; AddOriginalHook[hook]; }; e.next _ freeE; freeE _ e; }; AddOriginalHook: PROC [h: Line] ~ { e: IntersectEvent _ NewE[line: h, isALine: FALSE, new: TRUE]; e.time _ h.above; HQ.InsertEvent[e]; }; event: IntersectEvent _ NARROW[YQ.NextEvent[]]; IF event.new THEN OrderInsert[event] ELSE IF event.swap THEN OrderSwap[event] ELSE OrderRemove[event]; }; TestIntersect: PROC [Q: Heap.Queue, left, right: LineCarrier, currentPoint: Point] ~ { p: Point; s: LineRelation; s1, s2: EndPointRelation; leftLine: Line _ left.carried; rightLine: Line _ right.carried; [p, s, s1, s2] _ PairIntersection[leftLine, rightLine]; IF s = intersect AND p.y <= currentPoint.y THEN { IF p.y < currentPoint.y OR CompareSlopes[leftLine, rightLine] = greater THEN { event:IntersectEvent _ NewE[time: p, new: FALSE, line: NIL, swap: TRUE]; event.lineCarrier_left; event.lineRight_right; Q.InsertEvent[event]; }; }; }; HookScanLines: PROC [l: Line] RETURNS [quit: BOOL _ FALSE] ~ { event:IntersectEvent _ NewE[time: l.above, new: TRUE, line: l]; HQ.InsertEvent[event]; }; otherPoint: Point _ NEW[PointRec]; HookLineProcessEvent: PROC [] ~ { OrderInsert: PROC [e: IntersectEvent] ~ { currentPoint: Point _ e.time; lc: LineCarrier; scan: LineCarrier _ XO; prev: LineCarrier _ NIL; IF NOT e.isALine THEN { DO ne: IntersectEvent _ NARROW[HQ.PeekNextEvent]; IF ne.isALine OR NOT ne.new OR ComparePoints[currentPoint, ne.time] # equal THEN EXIT; [] _ HQ.NextEvent[]; ne.next _ freeE; freeE _ ne; ENDLOOP; }; UNTIL scan = NIL DO IF ComparePointLine[currentPoint, scan.carried] = greater THEN EXIT; prev _ scan; scan _ scan.lineLeft; ENDLOOP; e.lineCarrier _ lc _ NewLC[carried: e.line, lineLeft: scan, lineRight: prev]; e.time _ e.line.below; e.new _ FALSE; IF NOT e.isALine THEN { backScan: LineCarrier _ prev; otherPoint.x _ currentPoint.x + 1; otherPoint.y _ currentPoint.y; UNTIL backScan = NIL DO IF ComparePointLine[otherPoint, backScan.carried] # greater THEN EXIT; AddInducedHook[e.line, backScan.carried]; backScan _ backScan.lineRight; ENDLOOP; lc.isALine _ FALSE; }; e.new _ FALSE; HQ.InsertEvent[e]; IF scan # NIL THEN {scan.lineRight _ lc; TestIntersect[HQ, scan, lc, currentPoint]}; IF prev # NIL THEN {prev.lineLeft _ lc; TestIntersect[HQ, lc, prev, currentPoint]} ELSE XO _ lc; }; OrderRemove: PROC [e: IntersectEvent] ~ { lc: LineCarrier _ e.lineCarrier; IF lc.lineRight # NIL THEN lc.lineRight.lineLeft _ lc.lineLeft ELSE XO _ lc.lineLeft; IF lc.lineLeft # NIL THEN { lc.lineLeft.lineRight _ lc.lineRight; IF lc.lineRight # NIL THEN TestIntersect[HQ, lc.lineLeft, lc.lineRight, e.time]; }; IF NOT lc.isALine THEN { backScan: LineCarrier _ lc.lineRight; currentPoint: Point _ e.time; otherPoint.x _ currentPoint.x + 1; otherPoint.y _ currentPoint.y; UNTIL backScan = NIL DO IF ComparePointLine[otherPoint, backScan.carried] # greater THEN EXIT; AddInducedHook[e.line, backScan.carried]; backScan _ backScan.lineRight; ENDLOOP; lc.isALine _ FALSE; }; lc.lineRight _ freeLC; freeLC _ lc; lc.lineLeft _ NIL; e.next _ freeE; freeE _ e; }; OrderSwap: PROC [e: IntersectEvent] ~ { left: LineCarrier _ e.lineCarrier; right: LineCarrier _ e.lineRight; currentPoint: Point _ e.time; IF right.lineLeft = left THEN { IF XOR[left.isALine, right.isALine] THEN { IF left.isALine THEN AddInducedHook[right.carried, left.carried] ELSE AddInducedHook[left.carried, right.carried] }; left.lineRight _ right.lineRight; right.lineLeft _ left.lineLeft; left.lineLeft _ right; right.lineRight _ left; IF left.lineRight # NIL THEN { left.lineRight.lineLeft _ left; TestIntersect[HQ, left, left.lineRight, currentPoint]} ELSE XO _ left; IF right.lineLeft # NIL THEN { right.lineLeft.lineRight _ right; TestIntersect[HQ, right.lineLeft, right, currentPoint ]}; }; e.next _ freeE; freeE _ e; }; AddInducedHook: PROC [h: Line, l: Line] ~ { ls: LineState _ NARROW[l.state]; IF h.state = NIL THEN { h.state _ ComputeHead[h.below]}; ls.hooks _ CONS[h.state, ls.hooks]; }; ComputeHead: PROC [p: Point] RETURNS [np: Point] ~ INLINE { OddBump: PROC [i: INT] RETURNS [o: INT] ~ INLINE {RETURN[(i+1)/2]}; np _ NEW[PointRec _ [x: OddBump[p.x], y: OddBump[p.y]]]; }; event: IntersectEvent _ NARROW[HQ.NextEvent[]]; IF event.new THEN OrderInsert[event] ELSE IF event.swap THEN OrderSwap[event] ELSE OrderRemove[event]; }; intermediate: Graph _ NewGraph[in.points.size]; BendScanLines: PROC [l: Line] RETURNS [quit: BOOLEAN _ FALSE] ~ { ls: LineState _ NARROW[l.state]; dy: INT _ l.above.y - l.below.y; --automatically negateY dx: INT _ l.below.x - l.above.x; negateX: BOOLEAN _ ( dx < 0 ); exchangeXY: BOOLEAN; originX, currentX: INT _ l.above.x; originY, currentY: INT _ l.above.y; SegmentOutput: PROC [incrementX, incrementY: INT] ~ { IF exchangeXY THEN { temp: INT _ incrementX; incrementX _ incrementY; incrementY _ temp }; IF negateX THEN incrementX _ - incrementX; currentX _ currentX + incrementX; currentY _ currentY - incrementY; intermediate _ intermediate.LineTo[currentX, currentY, Copy[ls.clientState], Flip]; }; NextHook: PROC [] RETURNS [down: BOOL _ FALSE, break: INT _ 0, quit: BOOLEAN _ FALSE] ~ { hook: Point; clockwise: BOOLEAN; IF ls.hooks = NIL THEN RETURN[quit: TRUE]; hook _ NARROW[ls.hooks.first]; ls.hooks _ ls.hooks.rest; clockwise _ ComparePointLine[hook, l] = greater; break _ IF exchangeXY THEN originY - hook.y ELSE IF negateX THEN originX - hook.x ELSE hook.x - originX; down _ XOR[XOR[negateX, exchangeXY], clockwise]; }; DiagonalNextHook: PROC [] RETURNS [down: BOOL _ FALSE, break: INT _ 0, quit: BOOLEAN _ FALSE] ~ { hook: Point; breakY: INT; IF ls.hooks = NIL THEN RETURN[quit: TRUE]; hook _ NARROW[ls.hooks.first]; ls.hooks _ ls.hooks.rest; break _ hook.x - originX; breakY _ originY - hook.y; down _ NOT break = breakY; }; HookCompare: PROC[ref1: REF ANY, ref2: REF ANY] RETURNS [res: Basics.Comparison] ~ { hook1: Point _ NARROW[ref1]; hook2: Point _ NARROW[ref2]; cX: Basics.Comparison _ Basics.CompareINT[hook1.x, hook2.x]; cY: Basics.Comparison _ Basics.CompareINT[hook2.y, hook1.y]; --auto negateY Flip: PROC [in: Basics.Comparison] RETURNS [out: Basics.Comparison] ~ { IF in = less THEN RETURN[greater]; IF in = greater THEN RETURN[less]; RETURN[equal]; }; res _ IF exchangeXY THEN cY ELSE IF negateX THEN Flip[cX] ELSE cX; IF res = equal THEN { res _ IF NOT exchangeXY THEN cY ELSE IF negateX THEN Flip[cX] ELSE cX; }; }; IF negateX THEN dx _ - dx; exchangeXY _ ( dy > dx ); IF exchangeXY THEN {temp: INT _ dx; dx _ dy; dy _ temp}; ls.hooks _ List.UniqueSort[ls.hooks, HookCompare]; intermediate _ intermediate.NewPoint[currentX, currentY]; IF dx = dy AND NOT negateX THEN -- Special Diagonal Case Bend.DiagonalToHooks[dx, dy, DiagonalNextHook, SegmentOutput] ELSE Bend.BendToHooks[dx, dy, NextHook, SegmentOutput]; }; FinalScanLines: PROC [l: Line] RETURNS [quit: BOOL _ FALSE] ~ { event:IntersectEvent; IF ComparePoints[l.above, l.below] = equal THEN ERROR; event _ NewE[time: l.above, new: TRUE, line: l]; YQ.InsertEvent[event]; }; RemoveColinearProcessEvent: PROC [] ~ { PointOnLineFix: PROC [p: Point, nl: Line] RETURNS [rpl: Basics.Comparison] ~ { rpl _ ComparePointLine[p, nl]; IF rpl = equal THEN { IF ComparePoints[p, nl.above] = equal THEN { IF p # nl.above THEN MergePoints[nl.above, p]; } ELSE { IF ComparePoints[p, nl.below] = equal THEN { IF p # nl.below THEN MergePoints[nl.below, p]; } ELSE { -- mid line newAboveHalf: Line _ NEW[LineRec _ [above: nl.above, below: p, state: Copy[nl.state]]]; RemoveLineFromPointAbove[nl]; nl.above _ p; InsertLineInPointAbove[nl]; InsertLineInEndPoints[newAboveHalf]; }; }; }; }; AddToOut: PROC [p: Point] ~ { OPEN out.points; IF size > 0 THEN { IF ComparePoints[p, data[size-1]] = equal THEN { IF data[size-1].incoming = NIL AND data[size-1].outgoing = NIL THEN data[size-1]_p; RETURN[]; }; }; data[size] _ p; size _ size + 1; }; e: IntersectEvent _ NARROW[YQ.NextEvent[]]; l: Line _ e.line; lc: LineCarrier _ e.lineCarrier; rpl: Basics.Comparison; scan: LineCarrier; IF e.new THEN { p: Point _ l.above; prev: LineCarrier _ NIL; AddToOut[l.above]; scan _ XO; UNTIL scan = NIL DO neighborLine: Line _ scan.carried; rpl _ PointOnLineFix[l.above, neighborLine]; IF rpl = greater THEN EXIT; IF rpl = equal THEN { IF l.above # neighborLine.below THEN { rll: Basics.Comparison _ CompareSlopes[l, neighborLine]; IF rll = greater THEN EXIT; IF rll = equal THEN { rpp: Basics.Comparison _ ComparePoints[l.below, neighborLine.below]; IF rpp = greater THEN { ne: IntersectEvent _ NewE[time: l.below, new: TRUE, line: neighborLine]; YQ.InsertEvent[ne]; scan.carried _ NIL; --obsolete future event scan _ scan.lineLeft; --remove current entry RemoveLineFromPointAbove[neighborLine]; neighborLine.above _ l.below; InsertLineInPointAbove[neighborLine]; l.state _ Combine[l.state, neighborLine.state]; EXIT; } ELSE IF rpp = less THEN { RemoveLineFromPointAbove[l]; l.above _ neighborLine.below; InsertLineInPointAbove[l]; neighborLine.state _ Combine[neighborLine.state, l.state]; e.time _ l.above; YQ.InsertEvent[e]; RETURN[]; } ELSE {neighborLine.state _ Combine[neighborLine.state, l.state]; RemoveLineFromEndPoints[l]; RETURN[]; }; }; }; }; prev _ scan; scan _ scan.lineLeft; ENDLOOP; e.lineCarrier _ lc _ NewLC[carried: l, lineLeft: scan, lineRight: prev]; e.time _ l.below; e.new _ FALSE; YQ.InsertEvent[e]; IF scan # NIL THEN {scan.lineRight _ lc}; IF prev # NIL THEN {prev.lineLeft _ lc} ELSE XO _ lc; } ELSE { IF lc.carried # l THEN RETURN[]; --Obsolete Event AddToOut[l.below]; IF lc.lineRight # NIL THEN lc.lineRight.lineLeft _ lc.lineLeft ELSE XO _ lc.lineLeft; IF lc.lineLeft # NIL THEN lc.lineLeft.lineRight _ lc.lineRight; scan _ lc.lineRight; UNTIL scan = NIL DO rpl _ PointOnLineFix[l.below, scan.carried]; IF rpl = greater THEN EXIT; scan _ scan.lineRight; ENDLOOP; scan _ lc.lineLeft; UNTIL scan = NIL DO rpl _ PointOnLineFix[l.below, scan.carried]; IF rpl = less THEN EXIT; scan _ scan.lineRight; ENDLOOP; lc.lineRight _ freeLC; freeLC _ lc; e.next _ freeE; freeE _ e; }; }; YQ: Heap.Queue _ Heap.CreateQueue[CompareLL, in.points.size]; HQ: Heap.Queue _ Heap.CreateQueue[CompareHL, in.points.size]; XO: LineCarrier _ NIL; ExpandPoint: PROC [p: Point] ~ INLINE {p.x _ p.x*2; p.y _ p.y*2}; ContractPoint: PROC [p: Point] ~ INLINE {p.x _ p.x/2; p.y _ p.y/2}; FOR i: CARDINAL IN [0..in.points.size) DO ExpandPoint[in.points.data[i]] ENDLOOP; [] _ EnumerateLines[in, InitialScanLines]; UNTIL YQ.Empty[] DO LineLineProcessEvent[] ENDLOOP; [] _ EnumerateLines[in, HookScanLines]; UNTIL HQ.Empty[] DO HookLineProcessEvent[] ENDLOOP; FOR i: CARDINAL IN [0..in.points.size) DO ContractPoint[in.points.data[i]] ENDLOOP; [] _ EnumerateLines[in, BendScanLines]; out _ NewGraph[intermediate.points.size]; out.status _ planar; IF XO # NIL THEN ERROR; Heap.ChangeCompareProc[YQ, CompareRC]; [] _ EnumerateLines[intermediate, FinalScanLines]; UNTIL YQ.Empty[] DO RemoveColinearProcessEvent[] ENDLOOP; DestroyGraph[in]; TrashFreeLC[]; TrashFreeE[]; }; END. ΖAccurateIntersectImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Greene, October 3, 1986 6:12:02 pm PDT negateX is FALSE; exchangeXY is FALSE Break neighborLine Break l ΚV˜šœ™Icodešœ Οmœ1™Kšœ˜Kšžœ˜K˜—˜K˜——Kšœžœžœ˜/Kšžœ žœ˜$Kšžœžœ žœ˜(Kšžœ˜K˜K˜šŸ œžœŸœ@˜VKšœ4˜4K˜@K˜7šžœžœžœ˜1šžœžœ.žœ˜NKšœ*žœžœžœ˜HKšœ.˜.Kšœ˜K˜—K˜—K˜—K˜š Ÿ œžœ žœžœžœ˜>Kšœ0žœ ˜?Kšžœ˜K˜—K˜Kšœžœ ˜"K˜šŸœžœ˜!K˜šŸ œžœ˜)K˜.Kšœžœžœ˜0šžœžœ žœ˜šž˜Kšœžœžœ˜.Kš žœ žœžœžœ.žœžœ˜VKšœžœ ˜K˜Kšžœ˜—K˜—šžœžœž˜Kšžœ8žœžœ˜DK˜"Kšžœ˜—KšœM˜MKšœžœ˜%šžœžœ žœ˜Kšœ˜K˜Bšžœ žœž˜Kšžœ:žœžœ˜FK˜HKšžœ˜—Kšœ žœ˜K˜—Kšœžœ˜Kšžœ˜Kšžœžœžœ%žœ˜TKš žœžœžœ$žœžœžœ˜`K˜—K˜šŸ œžœ˜)Kšœ ˜ Kš žœžœžœ%žœžœ˜Ušžœžœžœ˜K˜%Kšžœžœžœžœ%˜PK˜—šžœžœ žœ˜Kšœ%˜%K˜K˜Bšžœ žœž˜Kšžœ:žœžœ˜FK˜HKšžœ˜—Kšœ žœ˜K˜—Kšœ2žœ˜6K˜K˜—K˜KšŸ œžœ˜'K˜"K˜!šœ˜šžœžœ˜šžœžœžœ˜*Kšžœžœ-žœ,˜qK˜—K˜AK˜.šžœžœžœ˜K˜Kšœžœ&˜6—Kšžœžœ˜šžœžœžœ˜K˜!Kšœžœ)˜9—K˜K˜—K˜K˜—K˜šŸœžœ˜+Kšœžœ ˜ šžœ žœžœ˜Kšœ ˜ —Kšœ žœ˜#K˜—K˜šŸ œžœ žœžœ˜;KšŸœžœžœžœžœžœžœ ˜CKšœžœ0˜8K˜—K˜K˜—Kšœžœžœ˜/Kšžœ žœ˜$Kšžœžœ žœ˜(Kšžœ˜K˜K˜K˜/K˜š Ÿ œžœ žœžœžœ˜AKšœžœ ˜ Kšœžœ ˜9Kšœžœ˜ Kšœ žœ˜Kšœ žœ˜K˜Kšœžœ!žœ ˜GK˜šŸ œžœžœ˜5šžœ žœ˜Kšœžœ9˜BK˜—Kšžœ žœ˜*K˜DK˜SK˜—K˜šŸœžœžœžœžœ žœ žœžœ˜YKšœžœ˜ Kš žœ žœžœžœžœ˜*K˜Kšœžœ,˜9K˜0Kš œžœ žœžœžœ žœžœ˜hKšœžœžœ"˜0K˜—K˜šŸœžœžœžœžœ žœ žœžœ˜aKšœžœ˜Kš žœ žœžœžœžœ˜*Kšœžœ,˜9K˜Kšœ%™%K˜K˜Kšœžœ˜K˜—K˜šŸ œžœžœžœžœžœžœ˜TKšœžœ˜Kšœžœ˜Kšœ<˜ ˜LK˜šŸœžœžœ˜GKšžœ žœžœ ˜"Kšžœžœžœ˜"Kšžœ˜K˜—K˜Kšœžœ žœž˜ Kšžœ žœ žœ˜!K˜šžœ žœ˜Kšœžœžœ žœž˜$Kšžœ žœ žœ˜!K˜—K˜—K˜Kšžœ žœ ˜K˜Kšžœ žœžœ˜8K˜K˜2K˜K˜9š žœ žœžœ žœ ˜8Kšœ=˜=—Kšžœ3˜7K˜K˜—š Ÿœžœ žœžœžœ˜?Kšœ˜Kšžœ)žœžœ˜6Kšœ!žœ ˜0Kšžœ˜K˜—K˜KšŸœžœ˜'K˜šŸœžœžœ˜NK˜šžœ žœ˜šžœ$žœ˜,Kšžœžœ˜.K˜—šžœ˜šžœ$žœ˜,Kšžœžœ˜.K˜—šžœ  ˜Kšœžœ?˜WK˜K˜ K˜K˜$K˜—K˜—K˜—K˜—K˜K˜KšŸœžœ˜šžœ ˜šžœ žœ˜šžœ(žœ˜0Kš žœžœžœžœžœ˜SKšžœ˜ K˜—K˜—K˜ K˜—˜K˜Kšœžœžœ˜+K˜2Kšœ˜Kšœ˜K˜šžœžœ˜Kšœ(žœ˜,Kšœ˜Kšœžœ˜ šžœžœž˜Kšœ"˜"Kšœ,˜,Kšžœžœžœ˜šžœ žœ˜šžœžœ˜'Kšœ8˜8Kšžœžœžœ˜šžœ žœ˜KšœD˜Dšžœžœ˜Kšœ™Kšœ.žœ˜HKšžœ!žœ ˜?Kšœ ˜-Kšœ'˜'Kšœ˜Kšœ%˜%Kšœ/˜/Kšžœ˜K˜—šžœžœ žœ˜Kšœ™K˜K˜K˜K˜:Kšœ˜Kšžœ˜Kšžœ˜ K˜—šžœ˜Kšœ;˜;K˜Kšžœ˜ K˜—K˜—K˜—˜K˜——K˜"Kšžœ˜—KšœH˜HKšœ˜Kšœžœ˜Kšžœ˜Kšžœžœžœ˜)Kš žœžœžœžœžœ˜5K˜—šžœ˜Kšžœžœžœ ˜2Kšœ˜Kš žœžœžœ%žœžœ˜UKšžœžœžœ&˜?K˜šžœžœž˜Kšœ,˜,Kšžœžœžœ˜K˜Kšžœ˜—K˜šžœžœž˜Kšœ,˜,Kšžœ žœžœ˜K˜Kšžœ˜—K˜#K˜K˜—K˜—K˜J˜Jšžœ;˜=Jšžœ;˜=Jšžœžœ˜J˜KšŸ œžœžœ˜AK˜šŸ œžœžœ˜CK˜—Kš žœžœžœžœ žœ˜QKšœ*˜*Kšžœžœ žœžœ˜3K˜Kšœ'˜'Kšžœžœ žœžœ˜3K˜Kš žœžœžœžœ"žœ˜SKšœ'˜'K˜K˜>Kš žœžœžœžœžœ˜Kšœžœ ˜&Kšœ2˜2Kšžœžœ žœžœ˜9K˜K˜K˜K˜K˜J˜Jšžœ˜J˜J˜J˜Jšœ˜—…—B"X>