DIRECTORY Basics USING [Comparison], WaterlilyOrderedSymbolTable USING[Node, Key, GetKey, Compare, Table, ErrorType]; WaterlilyRedBlackTreeImpl: CEDAR MONITOR IMPORTS WaterlilyOrderedSymbolTable EXPORTS WaterlilyOrderedSymbolTable SHARES WaterlilyOrderedSymbolTable = BEGIN OPEN WaterlilyOrderedSymbolTable; Comparison: TYPE = Basics.Comparison; RedBlack: TYPE = BOOL; Red: BOOL = TRUE; Black: BOOL = FALSE; DuplicateKey: PUBLIC ERROR = CODE; Error: PUBLIC ERROR [ec: ErrorType] = CODE; doChecking: BOOLEAN = TRUE; y: Node; z: Node _ NIL; Initialize: PUBLIC ENTRY PROC [sentinel1, sentinel2: Node] = { sentinel1.rbColor _ Red; sentinel1.rbLLink _ sentinel1.rbRLink _ NIL; sentinel2.rbColor _ Black; sentinel2.rbLLink _ sentinel2.rbRLink _ sentinel1; y _ sentinel1; z _ sentinel2 }; CreateTable: PUBLIC ENTRY PROC[header: Node] RETURNS[Table] = { IF z = NIL THEN ERROR Error[notInitialized]; header.rbColor _ Black; header.rbLLink _ NIL; header.rbRLink _ z; RETURN [[header]] }; Insert: PUBLIC ENTRY PROC[self: Table, nodeToInsert: Node, insertKey: Key] = { x, gg, g, f: Node; keyAlreadyPresent: BOOLEAN _ TRUE; c: Comparison _ greater; --since actual tree sits in right subtree of header node... IF doChecking AND self.rbLLink # NIL THEN ERROR Error[badTable]; f _ self; x _ f.rbRLink; DO IF (x.rbLLink.rbColor=Red) AND (x.rbRLink.rbColor=Red) THEN { IF x=z THEN { IF c = equal THEN EXIT; x _ nodeToInsert; keyAlreadyPresent _ FALSE; x.rbLLink _ z; x.rbRLink _ z; IF c = less THEN f.rbLLink _ x ELSE f.rbRLink _ x; c _ equal; };--IF x is external x.rbLLink.rbColor _ Black; x.rbRLink.rbColor _ Black; x.rbColor _ Red; IF f.rbColor=Red THEN { g _ Balance[gg, g, f, x]; x _ g; };--IF parent is red };--IF both children are red IF c = equal THEN EXIT; gg _ g; g _ f; f _ x; x _ IF (c _ Compare[insertKey, x]) = less THEN x.rbLLink ELSE x.rbRLink; ENDLOOP; self.rbRLink.rbColor _ Black; --root is always black IF keyAlreadyPresent THEN RETURN WITH ERROR DuplicateKey; }; Delete: PUBLIC ENTRY PROC[self: Table, deleteKey: Key] RETURNS [deletedNode: Node] = { f, result, parentOfResult: Node; x, g, b: Node; c: Comparison; result _ NIL; IF doChecking AND self.rbLLink # NIL THEN ERROR Error[badTable]; f _ self; x _ f.rbRLink; IF x = z THEN RETURN[NIL]; y.rbColor _ Black; --children of external nodes have no red to contribute to rebalancing. IF (x.rbLLink.rbColor = Black) AND (x.rbRLink.rbColor = Black) THEN x.rbColor _ Red; IF (c _ Compare[deleteKey, x]) = equal THEN { result _ x; parentOfResult _ f; }; DO BEGIN g _ f; f _ x; IF c = less THEN { b _ x.rbRLink; x _ x.rbLLink; } ELSE { b _ x.rbLLink; x _ x.rbRLink; }; IF (c _ Compare[deleteKey, x]) = equal AND x # z THEN { result _ x; parentOfResult _ f; }; IF x.rbColor=Red OR x.rbLLink.rbColor=Red OR x.rbRLink.rbColor=Red THEN LOOP; IF b.rbColor=Red THEN { IF b = f.rbLLink THEN { f.rbLLink _ b.rbRLink; b.rbRLink _ f; } ELSE { f.rbRLink _ b.rbLLink; b.rbLLink _ f; }; f.rbColor _ Red; b.rbColor _ Black; IF f = g.rbLLink THEN g.rbLLink _ b ELSE g.rbRLink _ b; x _ b; GOTO FixCompare; };--IF b.rbColor=Red IF x=z THEN EXIT; x.rbColor _ Red; IF b.rbLLink.rbColor = Red THEN { b.rbLLink.rbColor _ Black; x _ Balance[g, f, b, b.rbLLink]; GOTO FixCompare; }; IF b.rbRLink.rbColor = Red THEN { b.rbRLink.rbColor _ Black; x _ Balance[g, f, b, b.rbRLink]; GOTO FixCompare; }; f.rbColor _ Black; b.rbColor _ Red; EXITS FixCompare => c _ Compare[deleteKey, x]; END ENDLOOP; self.rbRLink.rbColor _ Black; z.rbColor _ Black; y.rbColor _ Red;--undo the color mess IF result # NIL THEN { IF g.rbLLink = f THEN g.rbLLink _ z ELSE g.rbRLink _ z; IF f # result THEN { IF parentOfResult.rbLLink = result THEN parentOfResult.rbLLink _ f ELSE parentOfResult.rbRLink _ f; f.rbLLink _ result.rbLLink; f.rbRLink _ result.rbRLink; f.rbColor _ result.rbColor; };--IF f # result };--IF result # NIL RETURN[result]; }; Lookup: PUBLIC ENTRY PROC[self: Table, lookupKey: Key] RETURNS [equalNode: Node] = { c: Comparison; IF doChecking AND self.rbLLink # NIL THEN ERROR Error[badTable]; equalNode _ self.rbRLink; DO IF equalNode = z THEN RETURN [NIL]; IF (c _ Compare[lookupKey, equalNode]) = equal THEN RETURN [equalNode]; IF c = less THEN equalNode _ equalNode.rbLLink ELSE equalNode _ equalNode.rbRLink; ENDLOOP }; Lookup3: PUBLIC ENTRY PROC[self: Table, lookupKey: Key] RETURNS[leftNode, equalNode, rightNode: Node] = { c: Comparison; IF doChecking AND self.rbLLink # NIL THEN ERROR Error[badTable]; equalNode _ self.rbRLink; DO IF equalNode = z THEN RETURN[leftNode, NIL, rightNode]; IF (c _ Compare[lookupKey, equalNode]) = equal THEN EXIT; IF c = less THEN { rightNode _ equalNode; equalNode _ equalNode.rbLLink } ELSE { leftNode _ equalNode; equalNode _ equalNode.rbRLink; }; ENDLOOP; IF equalNode.rbLLink # z THEN { leftNode _ equalNode.rbLLink; WHILE leftNode.rbRLink # z DO leftNode _ leftNode.rbRLink ENDLOOP }; IF equalNode.rbRLink # z THEN { rightNode _ equalNode.rbRLink; WHILE rightNode.rbLLink # z DO rightNode _ rightNode.rbLLink ENDLOOP }; RETURN[leftNode, equalNode, rightNode] }; LookupSmallest: PUBLIC ENTRY PROC[self: Table] RETURNS[smallestNode: Node] = { IF doChecking AND self.rbLLink # NIL THEN ERROR Error[badTable]; smallestNode _ self.rbRLink; IF smallestNode=z THEN RETURN[NIL]; UNTIL smallestNode.rbLLink=z DO smallestNode _ smallestNode.rbLLink ENDLOOP; RETURN[smallestNode] }; LookupNextLarger: PUBLIC ENTRY PROC[self: Table, lookupKey: Key] RETURNS[largerNode: Node] = { x: Node _ self.rbRLink; IF doChecking AND self.rbLLink # NIL THEN ERROR Error[badTable]; largerNode _ NIL; UNTIL x=z DO IF Compare[lookupKey, x] = less THEN { largerNode _ x; x _ x.rbLLink } ELSE x _ x.rbRLink; ENDLOOP; RETURN[largerNode] }; LookupLargest: PUBLIC ENTRY PROC[self: Table] RETURNS[largestNode: Node] = { IF doChecking AND self.rbLLink # NIL THEN ERROR Error[badTable]; largestNode _ self.rbRLink; IF largestNode=z THEN RETURN[NIL]; UNTIL largestNode.rbRLink=z DO largestNode _ largestNode.rbRLink ENDLOOP; RETURN[largestNode] }; LookupNextSmaller: PUBLIC ENTRY PROC [self: Table, lookupKey: Key] RETURNS[smallerNode: Node] = { x: Node _ self.rbRLink; IF doChecking AND self.rbLLink # NIL THEN ERROR Error[badTable]; smallerNode _ NIL; UNTIL x=z DO IF Compare[lookupKey, x] = greater THEN { smallerNode _ x; x _ x.rbRLink } ELSE x _ x.rbLLink; ENDLOOP; RETURN[smallerNode] }; DestroyTable: PUBLIC--EXTERNAL--PROC [self: Table] = { IF doChecking AND self.rbLLink # NIL THEN ERROR Error[badTable]; [] _ CreateTable[self] }; EnumerateIncreasing: PUBLIC ENTRY PROC [ self: Table, procToApply: PROC [Node] RETURNS [--stop--BOOLEAN]] = { VisitSubtree: INTERNAL PROC [root: Node] RETURNS [--stop--BOOLEAN] = { IF root.rbLLink # z AND VisitSubtree[root.rbLLink] THEN RETURN [TRUE]; IF procToApply[root] THEN RETURN [TRUE]; IF root.rbRLink # z THEN RETURN [VisitSubtree[root.rbRLink]] ELSE RETURN [FALSE] }; IF doChecking AND self.rbLLink # NIL THEN ERROR Error[badTable]; IF self.rbRLink = z THEN RETURN; [] _ VisitSubtree [self.rbRLink] }; Assert: PROC[p: BOOLEAN] = { IF NOT p THEN ERROR Error[badTable] }; CheckTable: PUBLIC PROC [self: Table] = { Check1: PROC[x: Node, maxKey: Key] RETURNS[Key, INTEGER, BOOLEAN] = { dl, dr: INTEGER; redChild: BOOLEAN; IF x = z THEN BEGIN RETURN[maxKey, 0, FALSE]; END; [maxKey, dl, redChild] _ Check1[x.rbLLink, maxKey]; Assert[~(redChild AND (x.rbColor=Red))]; Assert[Compare[maxKey,x] = (IF count=0 THEN equal ELSE less)]; count _ count + 1; [maxKey, dr, redChild] _ Check1[x.rbRLink, GetKey[x]]; Assert[~(redChild AND (x.rbColor=Red))]; Assert[dl=dr]; RETURN[maxKey, dl+(IF x.rbColor=Black THEN 1 ELSE 0), x.rbColor=Red]; };--Check1 count: LONG INTEGER _ 0; Assert[self.rbLLink=NIL]; Assert[z.rbLLink=y]; Assert[z.rbRLink=y]; IF self.rbRLink # z THEN [] _ Check1[self.rbRLink, GetKey[LookupSmallest[self]]] }; RootNode: PUBLIC ENTRY PROC [self: Table] RETURNS [rootNode: Node] = { IF doChecking AND self.rbLLink # NIL THEN ERROR Error[badTable]; RETURN [IF self.rbRLink = z THEN NIL ELSE self.rbRLink] }; Balance: INTERNAL PROC [gg, g, f, x: Node] RETURNS [Node] = { t: Node; tc: RedBlack; IF f=g.rbLLink THEN { IF x=f.rbRLink THEN { f.rbRLink _ x.rbLLink; x.rbLLink _ f; t _ f; f _ x; x _ t; }; } ELSE { IF x=f.rbLLink THEN { f.rbLLink _ x.rbRLink; x.rbRLink _ f; t _ f; f _ x; x _ t; }; }; IF x=f.rbLLink THEN { g.rbLLink _ f.rbRLink; f.rbRLink _ g; } ELSE { g.rbRLink _ f.rbLLink; f.rbLLink _ g; }; IF g = gg.rbRLink THEN gg.rbRLink _ f ELSE gg.rbLLink _ f; tc _ g.rbColor; g.rbColor _ f.rbColor; f.rbColor _ tc; RETURN[f] }; END.--RedBlackTreeImpl CHANGE LOG Created by MBrown on January 18, 1980 10:58 AM Changed by MBrown on January 19, 1980 8:50 PM Changed by MBrown on 20-Jan-80 13:28 Changed by MBrown on March 4, 1980 2:17 PM Changed by MBrown on April 13, 1980 4:21 PM Changed by MBrown on April 13, 1980 6:01 PM Changed by MBrown on May 1, 1980 10:03 PM Changed by MBrown on May 7, 1980 6:36 PM Changed by MBrown on August 11, 1980 10:17 PM Changed by MBrown on October 29, 1980 8:42 PM Changed by MBrown on January 7, 1981 9:47 PM Changed by MBrown on March 1, 1982 3:30 pm Changed by MBrown on March 2, 1982 4:20 pm Changed by MBrown on June 28, 1982 11:12 am Changed by MBrown on August 26, 1982 11:11 pm Changed by MBrown on November 10, 1982 6:34 pm Changed by MBrown on October 20, 1983 11:38 pm Changed by Russ Atkinson, December 3, 1984 5:49:07 pm PST 4WaterlilyRedBlackTreeImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. MBrown on October 20, 1983 11:37 pm Russ Atkinson, December 3, 1984 5:47:46 pm PST Notes on the data structure The color of a node should be thought of as the color of the edge coming into the node. The general color invariants for red-black trees are that (1) all external nodes are black, while internals are red or black, and (2) all paths from an internal node to an external node contain the same number of black arcs. The tree edges of a 2-3-4 tree become black arcs in the binarized red-black representation, while the internal 2-, 3-, and 4-nodes are represented by connected red subtrees: the degenerate one with one node, both of the possible two node trees, and the completely balanced tree on three nodes. Another way of stating this invariant is to say that no path contains two consecutive red arcs. The top-down insertion algorithm below is from Program 5 of "A Dichromatic Framework for Balanced Trees" by Leo Guibas and Bob Sedgewick. The deletion algorithm incorporates several changes to the algorithm in that paper. This program was originally adapted from Dave Gifford's StringStorageImpl.Mesa. forces extra validity checking of inputs. Shared variables Procedures exported to WaterlilyOrderedSymbolTable Requires self.rbColor = self.rbRLink.rbColor = z.rbColor = Black, y.rbColor = Red. search the tree, rebalancing on the way down. an external node has been found; check to be sure that a duplicate key is not present. perform the insertion. do color flip. two reds in a row, so rebalance (gg may be self). Inject a red node at the root if necessary. Search the tree for the symmetric order succecessor of the node containing key (or the node itself if its RLink is z) If x is the node we're to return, save pointers to it and its parent for later. Note that if x is Red, no rotations happen now; this is what re-establishes the properties of g and f eventually... Single rotation to move the red link b onto the search path. Move back up the path to allow g and f to get re-established It is essential that this exit test be right here - after the single rotation, but before the double rotations. "Color flip" If search has been successful, f is now the symmetric order successor of result (or result itself if result.rbRLink = z), and g is its parent. f is Red, unless it is also the root. x and b are irrelevant. detach f from the tree. if f is not the result node, splice f into tree in place of result. quick and dirty recursive implementation, has overhead of one procedure call per call to procToApply. never called with root = z; this saves half of the procedure calls. ERRORs Error[badTable] if the table t is not well-formed. Returns largest key in subtree rooted at x, number of black arcs on paths to external nodes from x, and whether or not this node is red. ERRORs if it finds two reds in a row, finds different distances to the external nodes (counting only red arcs), or finds keys out of order. If x is an internal node, increments count. check structure of the table header, sentinels, etc. The following assertions may fail during intermediate states of Delete. Assert[z.rbColor=Black]; Assert[y.rbColor=Red]; Assert[self.rbRLink.rbColor=Black]; check structure of table. Private procedure, used by Insert (1 call), Delete (2 calls). Balances a local portion of the tree. g is a child of gg (it may be either child). if g -rlink-> f -rlink-> x, or x <-llink- f <-llink- g, then only a single rotation is needed; otherwise two rotations are used. when called from insert, g is black and both f and x are red. after rebalancing, the new g is black, and is the parent of both the new f and the new x, which are both red. do first rotation if necessary do second rotation update link in great grandparent do color swap (when called from Insert, g is always Black and f is always Red) return g, new child of gg (name changed in second rotation) It worked the first time! Implemented EnumerateIncreasing. Fixed a bug in CheckTable that defeated checking of key order. Made changes to allow MinusInfinity as a Key. Changed Insert to use keyPresent flag, as in Guibas-Sedgewick Program 5. Changed Balance to compare pointers rather than keys, and eliminated the code for "swap g and f" since only g is returned from Balance. Moved inline definitions of Node structure to WaterlilyOrderedSymbolTable, which we now OPEN. Coded Delete. Made LookupSmallest and LookupNextLarger PUBLIC, since they may be useful in testing Delete. Delete seemed to work the first time, a surprise. I removed some the redundant checks that were there for debugging; the old version will be called RedBlackCheckedImpl. Changed Delete to avoid a search from the root to find the parent of the result node. This involved actually understanding the algorithm; "cleaning up" the way rebalancing is done introduced several bugs. Added DestroyTable and Size. We now allocate/free TableObjects using procs in the WaterlilyOrderedSymbolTable interface. Renamed module. Major revisions (prompted by first real client, the Juniper locks code, which will make further changes for its special needs). We take the key comparison function from the interface, instead of requiring "<" to be applicable. This means that comparisons may be expensive, so we save the result in a local variable to avoid doing twice the required number. MinusInfinity is no longer treated specially in the code. We do explicit field selections for the links and color fields, instead of using inline procs from the interface. Added Lookup3 proc for Juniper locks application. We now pass in ALL storage, including storage for table objects. y and z now point to nodes in the global frame of this module, rather than being replicated for each table; thus it is now unsafe for multiple processes to be inside of an instance of this module, even if they operate on distinct tables (it was always unsafe to perform concurrent operations on a single table). Eliminated all reference to MinusInfinity (it was being used in CheckTable). Changes for collectible storage, module monitor. New version for use in Alpine. No allocation done in package, even for sentinels. No more "AssignKey[,]", which was used only for sentinels; instead, check for z explicitly. No more "Key[]", and Compare now takes a Key and a Node. A Table is just a Node; no count of number of nods in a table is kept in the table. Other variants that are possible (but hopefully are not required): (1) use < and = instead of 3-way compares. (2) use object monitor (requires replicating z and y per-table), or no monitor. (3) Table and Node are different types (this is required for object monitor, to hold y and z.) Table is a RECORD [Node]. Clean up errors in interface. CEDAR implementation. Use Environment.Comparison. DuplicateKey is now an ERROR. Conversion to Cedar 5.0. Cloned for Waterlily. Êœ™Jšœ Ïmœ1™™>—J˜šÏk ˜ Jšœžœ˜šœžœ/˜PJ˜——šœžœž˜(Jšžœ˜#Jšžœ˜#Jšžœ˜"Jšœžœžœ˜)Jšœ žœ˜%J˜Jšœ žœžœ˜Jšœžœžœ˜Jšœžœžœ˜J˜Jšœžœžœžœ˜"Jšœžœžœžœ˜+J˜šœ žœžœ˜Jšœ)™)J˜—Jšœ™J˜J˜Jšœ žœ˜—˜Jšœ2™2J˜šÏn œžœžœžœ!˜>JšœAžœ˜EJ˜MJ˜J˜—š Ÿ œžœžœžœžœ ˜?Jšžœžœžœžœ˜,Jšœ)žœ˜AJšžœ˜J˜—šŸœžœžœžœ5˜NJšœR™RJ˜Jšœžœžœ˜"JšœÏc;˜TJšœ-™-Jš žœ žœžœžœžœ˜@J˜šž˜šžœžœžœ˜=šžœžœ˜ JšœV™VJšžœ žœžœ˜Jšœ™Jšœ'žœ˜-J˜Jšžœ žœžœ˜2J˜ —Jšœ ˜Jšœ™J˜Hšžœžœ˜Jšœ1™1J˜J˜—Jšœ ˜—Jšœ ˜Jšžœ žœžœ˜J˜Jšœžœ$žœ žœ ˜HJšžœ˜—Jšœ ˜4Jš žœžœžœžœžœ˜9Jšœ˜——˜š Ÿœžœžœžœžœ˜VJ˜ J˜J˜Jšœ žœ˜ Jš žœ žœžœžœžœ˜@J˜Jšžœžœžœžœ˜Jšœ F˜YJšœ+™+Jšžœžœžœ˜TJšžœ%žœ&˜QJšœN™NJšœ&™&šžœž˜J˜ šžœ žœ#˜3Jšžœ$˜(—JšœO™OJšžœ%žœžœ&˜[JšœO™OJšœ#™#Jš žœžœžœžœžœ˜Mšžœžœ˜Jšœ<™<šžœžœ+˜@Jšžœ,˜0—J˜$Jšžœžœžœ˜7Jšœ<™žœ ˜N—J˜šžœžœ˜!Jšœ>žœ ˜N—J˜Jšœ ™ J˜$—šž˜J˜(—Jšžœžœ˜ J˜Jšœ$ ˜9JšœO™OJšœP™PJšœ-™-šžœ žœžœ˜Jšœ™Jšžœžœžœ˜7JšœC™Cšžœ žœ˜šžœ!žœ˜BJšžœ˜ —J˜8J˜—Jšœ ˜—Jšœ ˜Jšžœ ˜Jšœ˜——˜š Ÿœžœžœžœžœ˜TJ˜Jš žœ žœžœžœžœ˜@J˜šž˜Jšžœžœžœžœ˜#Jšžœ-žœžœ ˜GJšžœ žœžœ˜RJšžœ˜ J˜——šŸœžœžœžœ˜7šžœ*˜1J˜Jš žœ žœžœžœžœ˜@J˜šž˜Jšžœžœžœ žœ ˜7Jšžœ-žœžœ˜9šžœ žœ:˜JJšžœ;˜?—Jšžœ˜—šžœžœ˜J˜Jšžœžœžœ˜D—šžœžœ˜J˜Jšžœžœžœ˜G—Jšžœ#˜)J˜——š Ÿœžœžœžœžœ˜NJš žœ žœžœžœžœ˜@J˜Jšžœžœžœžœ˜#Jšžœžœ'žœ˜NJšžœ˜J˜—šŸœžœžœžœ˜@Jšžœ˜J˜Jš žœ žœžœžœžœ˜@Jšœ žœ˜šžœž˜ šžœžœ"˜FJšžœ˜—Jšžœ˜—Jšžœ˜J˜—š Ÿ œžœžœžœžœ˜LJš žœ žœžœžœžœ˜@J˜Jšžœžœžœžœ˜"Jšžœžœ%žœ˜KJšžœ˜J˜—šŸœžœžœžœ˜BJšžœ˜J˜Jš žœ žœžœžœžœ˜@Jšœžœ˜šžœž˜ šžœ!žœ#˜JJšžœ˜—Jšžœ˜—Jšžœ˜J˜—šŸ œž  žœ˜6Jš žœ žœžœžœžœ˜@J˜J˜—šŸœžœžœžœ˜(Jšœžœžœ žœ˜DJšœL™LJšœ™š Ÿ œžœžœžœ žœ˜FJšœC™CJš žœžœžœžœžœ˜FJšžœžœžœžœ˜(Jš žœžœžœžœžœžœ˜S—Jš žœ žœžœžœžœ˜@Jšžœžœžœ˜ J˜#——˜šŸœžœžœ˜Jšžœžœžœžœ˜&J˜—šŸ œžœžœ˜)Jšœ9™9J˜š Ÿœžœžœžœžœ˜EJšœL™LJšœO™OJšœL™LJšœF™FJšœ™Jšœžœ˜Jšœ žœ˜šžœžœž˜Jšžœ žœ˜—Jšžœ˜J˜3Jšœžœ˜(Jšœžœ žœžœ˜>J˜J˜6Jšœžœ˜(J˜Jšžœ žœžœžœ˜EJšœ ˜ J˜—Jšœžœžœ˜Jšœ4™4Jšœžœ˜J˜J˜JšœG™GJšœ™Jšœ™Jšœ#™#Jšœ™Jšžœžœ;˜SJ˜—š Ÿœžœžœžœžœ˜FJš žœ žœžœžœžœ˜@Jš žœžœžœžœžœ˜:J˜—Jšœ=™=J˜šŸœžœžœžœ ˜=Jšœ%™%Jšœ,™,JšœJ™JJšœ5™5Jšœ=™=JšœN™NJšœ™J˜J˜J˜ Jšœ™šžœ žœ˜šžœ žœ˜J˜&J˜—J˜—J˜šžœ˜šžœ žœ˜J˜&J˜—J˜—J˜Jšœ™šžœ žœ+˜>Jšžœ,˜0—Jšœ ™ Jšžœžœžœ˜:JšœN™NJ˜8Jšœ;™;Jšžœ˜ J˜——Jšžœ ˜J˜Jšžœž˜ J˜Jšœ-ž˜/Jšœ™J˜Jšœ,ž˜.JšœU™UJšœP™PJšœ2™2J˜J˜$JšœQ™QJšœ5™5J˜Jšœ)ž˜+Jšœ]™]J˜Jšœ*ž˜,JšœQ™QJšœ™J˜Jšœ*ž˜,JšœO™OJšœD™DJšœ™J˜Jšœ(ž˜*JšœU™UJšœU™UJšœ ™ J˜Jšœ'ž˜)JšœR™RJšœ7™7J˜Jšœ,ž˜.JšœR™RJšœV™VJšœV™VJšœT™TJšœR™RJšœQ™QJšœT™TJšœU™UJšœU™UJšœS™SJšœS™SJšœ™J˜Jšœ,ž˜.JšœL™LJ˜Jšœ+ž˜-Jšœ0™0J˜J˜*JšœV™VJšœ[™[JšœW™WJšœ2™2JšœB™BJšœ*™*JšœO™OJšœ^™^J˜J˜*Jšœ8™8J˜J˜+Jšœ™J˜J˜-Jšœ™J˜J˜.Jšœ™J˜J˜.Jšœ™J™˜9Jšœ™—J˜—…—$èO