annotate vendor/gems/rubytree-0.5.2/lib/.svn/text-base/tree.rb.svn-base @ 8:0c83d98252d9 yuya

* Add custom repo prefix and proper auth realm, remove auth cache (seems like an unwise feature), pass DB handle around, various other bits of tidying
author Chris Cannam
date Thu, 12 Aug 2010 15:31:37 +0100
parents 513646585e45
children
rev   line source
Chris@0 1 # tree.rb
Chris@0 2 #
Chris@0 3 # $Revision: 1.29 $ by $Author: anupamsg $
Chris@0 4 # $Name: $
Chris@0 5 #
Chris@0 6 # = tree.rb - Generic Multi-way Tree implementation
Chris@0 7 #
Chris@0 8 # Provides a generic tree data structure with ability to
Chris@0 9 # store keyed node elements in the tree. The implementation
Chris@0 10 # mixes in the Enumerable module.
Chris@0 11 #
Chris@0 12 # Author:: Anupam Sengupta (anupamsg@gmail.com)
Chris@0 13 #
Chris@0 14
Chris@0 15 # Copyright (c) 2006, 2007 Anupam Sengupta
Chris@0 16 #
Chris@0 17 # All rights reserved.
Chris@0 18 #
Chris@0 19 # Redistribution and use in source and binary forms, with or without modification,
Chris@0 20 # are permitted provided that the following conditions are met:
Chris@0 21 #
Chris@0 22 # - Redistributions of source code must retain the above copyright notice, this
Chris@0 23 # list of conditions and the following disclaimer.
Chris@0 24 #
Chris@0 25 # - Redistributions in binary form must reproduce the above copyright notice, this
Chris@0 26 # list of conditions and the following disclaimer in the documentation and/or
Chris@0 27 # other materials provided with the distribution.
Chris@0 28 #
Chris@0 29 # - Neither the name of the organization nor the names of its contributors may
Chris@0 30 # be used to endorse or promote products derived from this software without
Chris@0 31 # specific prior written permission.
Chris@0 32 #
Chris@0 33 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Chris@0 34 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Chris@0 35 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Chris@0 36 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
Chris@0 37 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
Chris@0 38 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
Chris@0 39 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
Chris@0 40 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Chris@0 41 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
Chris@0 42 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Chris@0 43 #
Chris@0 44
Chris@0 45 # This module provides a TreeNode class which is the primary class for all
Chris@0 46 # nodes represented in the Tree.
Chris@0 47 # This module mixes in the Enumerable module.
Chris@0 48 module Tree
Chris@0 49
Chris@0 50 # Rubytree Package Version
Chris@0 51 VERSION = '0.5.2'
Chris@0 52
Chris@0 53 # == TreeNode Class Description
Chris@0 54 #
Chris@0 55 # The node class for the tree representation. the nodes are named and have a
Chris@0 56 # place-holder for the node data (i.e., the `content' of the node). The node
Chris@0 57 # names are expected to be unique. In addition, the node provides navigation
Chris@0 58 # methods to traverse the tree.
Chris@0 59 #
Chris@0 60 # The nodes can have any number of child nodes attached to it. Note that while
Chris@0 61 # this implementation does not support directed graphs, the class itself makes
Chris@0 62 # no restrictions on associating a node's CONTENT with multiple parent nodes.
Chris@0 63 #
Chris@0 64 #
Chris@0 65 # == Example
Chris@0 66 #
Chris@0 67 # The following code-snippet implements this tree structure:
Chris@0 68 #
Chris@0 69 # +------------+
Chris@0 70 # | ROOT |
Chris@0 71 # +-----+------+
Chris@0 72 # +-------------+------------+
Chris@0 73 # | |
Chris@0 74 # +-------+-------+ +-------+-------+
Chris@0 75 # | CHILD 1 | | CHILD 2 |
Chris@0 76 # +-------+-------+ +---------------+
Chris@0 77 # |
Chris@0 78 # |
Chris@0 79 # +-------+-------+
Chris@0 80 # | GRANDCHILD 1 |
Chris@0 81 # +---------------+
Chris@0 82 #
Chris@0 83 # require 'tree'
Chris@0 84 #
Chris@0 85 # myTreeRoot = Tree::TreeNode.new("ROOT", "Root Content")
Chris@0 86 #
Chris@0 87 # myTreeRoot << Tree::TreeNode.new("CHILD1", "Child1 Content") << Tree::TreeNode.new("GRANDCHILD1", "GrandChild1 Content")
Chris@0 88 #
Chris@0 89 # myTreeRoot << Tree::TreeNode.new("CHILD2", "Child2 Content")
Chris@0 90 #
Chris@0 91 # myTreeRoot.printTree
Chris@0 92 #
Chris@0 93 # child1 = myTreeRoot["CHILD1"]
Chris@0 94 #
Chris@0 95 # grandChild1 = myTreeRoot["CHILD1"]["GRANDCHILD1"]
Chris@0 96 #
Chris@0 97 # siblingsOfChild1Array = child1.siblings
Chris@0 98 #
Chris@0 99 # immediateChildrenArray = myTreeRoot.children
Chris@0 100 #
Chris@0 101 # # Process all nodes
Chris@0 102 #
Chris@0 103 # myTreeRoot.each { |node| node.content.reverse }
Chris@0 104 #
Chris@0 105 # myTreeRoot.remove!(child1) # Remove the child
Chris@0 106 class TreeNode
Chris@0 107 include Enumerable
Chris@0 108
Chris@0 109 attr_reader :content, :name, :parent
Chris@0 110 attr_writer :content
Chris@0 111
Chris@0 112 # Constructor which expects the name of the node
Chris@0 113 #
Chris@0 114 # Name of the node is expected to be unique across the
Chris@0 115 # tree.
Chris@0 116 #
Chris@0 117 # The content can be of any type, and is defaulted to _nil_.
Chris@0 118 def initialize(name, content = nil)
Chris@0 119 raise "Node name HAS to be provided" if name == nil
Chris@0 120 @name = name
Chris@0 121 @content = content
Chris@0 122 self.setAsRoot!
Chris@0 123
Chris@0 124 @childrenHash = Hash.new
Chris@0 125 @children = []
Chris@0 126 end
Chris@0 127
Chris@0 128 # Returns a copy of this node, with the parent and children links removed.
Chris@0 129 def detached_copy
Chris@0 130 Tree::TreeNode.new(@name, @content ? @content.clone : nil)
Chris@0 131 end
Chris@0 132
Chris@0 133 # Print the string representation of this node.
Chris@0 134 def to_s
Chris@0 135 "Node Name: #{@name}" +
Chris@0 136 " Content: " + (@content || "<Empty>") +
Chris@0 137 " Parent: " + (isRoot?() ? "<None>" : @parent.name) +
Chris@0 138 " Children: #{@children.length}" +
Chris@0 139 " Total Nodes: #{size()}"
Chris@0 140 end
Chris@0 141
Chris@0 142 # Returns an array of ancestors in reversed order (the first element is the
Chris@0 143 # immediate parent). Returns nil if this is a root node.
Chris@0 144 def parentage
Chris@0 145 return nil if isRoot?
Chris@0 146
Chris@0 147 parentageArray = []
Chris@0 148 prevParent = self.parent
Chris@0 149 while (prevParent)
Chris@0 150 parentageArray << prevParent
Chris@0 151 prevParent = prevParent.parent
Chris@0 152 end
Chris@0 153
Chris@0 154 parentageArray
Chris@0 155 end
Chris@0 156
Chris@0 157 # Protected method to set the parent node.
Chris@0 158 # This method should NOT be invoked by client code.
Chris@0 159 def parent=(parent)
Chris@0 160 @parent = parent
Chris@0 161 end
Chris@0 162
Chris@0 163 # Convenience synonym for TreeNode#add method. This method allows a convenient
Chris@0 164 # method to add children hierarchies in the tree.
Chris@0 165 #
Chris@0 166 # E.g. root << child << grand_child
Chris@0 167 def <<(child)
Chris@0 168 add(child)
Chris@0 169 end
Chris@0 170
Chris@0 171 # Adds the specified child node to the receiver node. The child node's
Chris@0 172 # parent is set to be the receiver. The child is added as the last child in
Chris@0 173 # the current list of children for the receiver node.
Chris@0 174 def add(child)
Chris@0 175 raise "Child already added" if @childrenHash.has_key?(child.name)
Chris@0 176
Chris@0 177 @childrenHash[child.name] = child
Chris@0 178 @children << child
Chris@0 179 child.parent = self
Chris@0 180 return child
Chris@0 181
Chris@0 182 end
Chris@0 183
Chris@0 184 # Removes the specified child node from the receiver node. The removed
Chris@0 185 # children nodes are orphaned but available if an alternate reference
Chris@0 186 # exists.
Chris@0 187 #
Chris@0 188 # Returns the child node.
Chris@0 189 def remove!(child)
Chris@0 190 @childrenHash.delete(child.name)
Chris@0 191 @children.delete(child)
Chris@0 192 child.setAsRoot! unless child == nil
Chris@0 193 return child
Chris@0 194 end
Chris@0 195
Chris@0 196 # Removes this node from its parent. If this is the root node, then does
Chris@0 197 # nothing.
Chris@0 198 def removeFromParent!
Chris@0 199 @parent.remove!(self) unless isRoot?
Chris@0 200 end
Chris@0 201
Chris@0 202 # Removes all children from the receiver node.
Chris@0 203 def removeAll!
Chris@0 204 for child in @children
Chris@0 205 child.setAsRoot!
Chris@0 206 end
Chris@0 207 @childrenHash.clear
Chris@0 208 @children.clear
Chris@0 209 self
Chris@0 210 end
Chris@0 211
Chris@0 212 # Indicates whether this node has any associated content.
Chris@0 213 def hasContent?
Chris@0 214 @content != nil
Chris@0 215 end
Chris@0 216
Chris@0 217 # Protected method which sets this node as a root node.
Chris@0 218 def setAsRoot!
Chris@0 219 @parent = nil
Chris@0 220 end
Chris@0 221
Chris@0 222 # Indicates whether this node is a root node. Note that
Chris@0 223 # orphaned children will also be reported as root nodes.
Chris@0 224 def isRoot?
Chris@0 225 @parent == nil
Chris@0 226 end
Chris@0 227
Chris@0 228 # Indicates whether this node has any immediate child nodes.
Chris@0 229 def hasChildren?
Chris@0 230 @children.length != 0
Chris@0 231 end
Chris@0 232
Chris@0 233 # Indicates whether this node is a 'leaf' - i.e., one without
Chris@0 234 # any children
Chris@0 235 def isLeaf?
Chris@0 236 !hasChildren?
Chris@0 237 end
Chris@0 238
Chris@0 239 # Returns an array of all the immediate children. If a block is given,
Chris@0 240 # yields each child node to the block.
Chris@0 241 def children
Chris@0 242 if block_given?
Chris@0 243 @children.each {|child| yield child}
Chris@0 244 else
Chris@0 245 @children
Chris@0 246 end
Chris@0 247 end
Chris@0 248
Chris@0 249 # Returns the first child of this node. Will return nil if no children are
Chris@0 250 # present.
Chris@0 251 def firstChild
Chris@0 252 children.first
Chris@0 253 end
Chris@0 254
Chris@0 255 # Returns the last child of this node. Will return nil if no children are
Chris@0 256 # present.
Chris@0 257 def lastChild
Chris@0 258 children.last
Chris@0 259 end
Chris@0 260
Chris@0 261 # Returns every node (including the receiver node) from the tree to the
Chris@0 262 # specified block. The traversal is depth first and from left to right in
Chris@0 263 # pre-ordered sequence.
Chris@0 264 def each &block
Chris@0 265 yield self
Chris@0 266 children { |child| child.each(&block) }
Chris@0 267 end
Chris@0 268
Chris@0 269 # Traverses the tree in a pre-ordered sequence. This is equivalent to
Chris@0 270 # TreeNode#each
Chris@0 271 def preordered_each &block
Chris@0 272 each(&block)
Chris@0 273 end
Chris@0 274
Chris@0 275 # Performs breadth first traversal of the tree rooted at this node. The
Chris@0 276 # traversal in a given level is from left to right.
Chris@0 277 def breadth_each &block
Chris@0 278 node_queue = [self] # Create a queue with self as the initial entry
Chris@0 279
Chris@0 280 # Use a queue to do breadth traversal
Chris@0 281 until node_queue.empty?
Chris@0 282 node_to_traverse = node_queue.shift
Chris@0 283 yield node_to_traverse
Chris@0 284 # Enqueue the children from left to right.
Chris@0 285 node_to_traverse.children { |child| node_queue.push child }
Chris@0 286 end
Chris@0 287 end
Chris@0 288
Chris@0 289 # Yields all leaf nodes from this node to the specified block. May yield
Chris@0 290 # this node as well if this is a leaf node. Leaf traversal depth first and
Chris@0 291 # left to right.
Chris@0 292 def each_leaf &block
Chris@0 293 self.each { |node| yield(node) if node.isLeaf? }
Chris@0 294 end
Chris@0 295
Chris@0 296 # Returns the requested node from the set of immediate children.
Chris@0 297 #
Chris@0 298 # If the parameter is _numeric_, then the in-sequence array of children is
Chris@0 299 # accessed (see Tree#children). If the parameter is not _numeric_, then it
Chris@0 300 # is assumed to be the *name* of the child node to be returned.
Chris@0 301 def [](name_or_index)
Chris@0 302 raise "Name_or_index needs to be provided" if name_or_index == nil
Chris@0 303
Chris@0 304 if name_or_index.kind_of?(Integer)
Chris@0 305 @children[name_or_index]
Chris@0 306 else
Chris@0 307 @childrenHash[name_or_index]
Chris@0 308 end
Chris@0 309 end
Chris@0 310
Chris@0 311 # Returns the total number of nodes in this tree, rooted at the receiver
Chris@0 312 # node.
Chris@0 313 def size
Chris@0 314 @children.inject(1) {|sum, node| sum + node.size}
Chris@0 315 end
Chris@0 316
Chris@0 317 # Convenience synonym for Tree#size
Chris@0 318 def length
Chris@0 319 size()
Chris@0 320 end
Chris@0 321
Chris@0 322 # Pretty prints the tree starting with the receiver node.
Chris@0 323 def printTree(level = 0)
Chris@0 324
Chris@0 325 if isRoot?
Chris@0 326 print "*"
Chris@0 327 else
Chris@0 328 print "|" unless parent.isLastSibling?
Chris@0 329 print(' ' * (level - 1) * 4)
Chris@0 330 print(isLastSibling? ? "+" : "|")
Chris@0 331 print "---"
Chris@0 332 print(hasChildren? ? "+" : ">")
Chris@0 333 end
Chris@0 334
Chris@0 335 puts " #{name}"
Chris@0 336
Chris@0 337 children { |child| child.printTree(level + 1)}
Chris@0 338 end
Chris@0 339
Chris@0 340 # Returns the root for this tree. Root's root is itself.
Chris@0 341 def root
Chris@0 342 root = self
Chris@0 343 root = root.parent while !root.isRoot?
Chris@0 344 root
Chris@0 345 end
Chris@0 346
Chris@0 347 # Returns the first sibling for this node. If this is the root node, returns
Chris@0 348 # itself.
Chris@0 349 def firstSibling
Chris@0 350 if isRoot?
Chris@0 351 self
Chris@0 352 else
Chris@0 353 parent.children.first
Chris@0 354 end
Chris@0 355 end
Chris@0 356
Chris@0 357 # Returns true if this node is the first sibling.
Chris@0 358 def isFirstSibling?
Chris@0 359 firstSibling == self
Chris@0 360 end
Chris@0 361
Chris@0 362 # Returns the last sibling for this node. If this node is the root, returns
Chris@0 363 # itself.
Chris@0 364 def lastSibling
Chris@0 365 if isRoot?
Chris@0 366 self
Chris@0 367 else
Chris@0 368 parent.children.last
Chris@0 369 end
Chris@0 370 end
Chris@0 371
Chris@0 372 # Returns true if his node is the last sibling
Chris@0 373 def isLastSibling?
Chris@0 374 lastSibling == self
Chris@0 375 end
Chris@0 376
Chris@0 377 # Returns an array of siblings for this node.
Chris@0 378 # If a block is provided, yields each of the sibling
Chris@0 379 # nodes to the block. The root always has nil siblings.
Chris@0 380 def siblings
Chris@0 381 return nil if isRoot?
Chris@0 382 if block_given?
Chris@0 383 for sibling in parent.children
Chris@0 384 yield sibling if sibling != self
Chris@0 385 end
Chris@0 386 else
Chris@0 387 siblings = []
Chris@0 388 parent.children {|sibling| siblings << sibling if sibling != self}
Chris@0 389 siblings
Chris@0 390 end
Chris@0 391 end
Chris@0 392
Chris@0 393 # Returns true if this node is the only child of its parent
Chris@0 394 def isOnlyChild?
Chris@0 395 parent.children.size == 1
Chris@0 396 end
Chris@0 397
Chris@0 398 # Returns the next sibling for this node. Will return nil if no subsequent
Chris@0 399 # node is present.
Chris@0 400 def nextSibling
Chris@0 401 if myidx = parent.children.index(self)
Chris@0 402 parent.children.at(myidx + 1)
Chris@0 403 end
Chris@0 404 end
Chris@0 405
Chris@0 406 # Returns the previous sibling for this node. Will return nil if no
Chris@0 407 # subsequent node is present.
Chris@0 408 def previousSibling
Chris@0 409 if myidx = parent.children.index(self)
Chris@0 410 parent.children.at(myidx - 1) if myidx > 0
Chris@0 411 end
Chris@0 412 end
Chris@0 413
Chris@0 414 # Provides a comparision operation for the nodes. Comparision
Chris@0 415 # is based on the natural character-set ordering for the
Chris@0 416 # node names.
Chris@0 417 def <=>(other)
Chris@0 418 return +1 if other == nil
Chris@0 419 self.name <=> other.name
Chris@0 420 end
Chris@0 421
Chris@0 422 # Freezes all nodes in the tree
Chris@0 423 def freezeTree!
Chris@0 424 each {|node| node.freeze}
Chris@0 425 end
Chris@0 426
Chris@0 427 # Creates the marshal-dump represention of the tree rooted at this node.
Chris@0 428 def marshal_dump
Chris@0 429 self.collect { |node| node.createDumpRep }
Chris@0 430 end
Chris@0 431
Chris@0 432 # Creates a dump representation and returns the same as a hash.
Chris@0 433 def createDumpRep
Chris@0 434 { :name => @name, :parent => (isRoot? ? nil : @parent.name), :content => Marshal.dump(@content)}
Chris@0 435 end
Chris@0 436
Chris@0 437 # Loads a marshalled dump of the tree and returns the root node of the
Chris@0 438 # reconstructed tree. See the Marshal class for additional details.
Chris@0 439 def marshal_load(dumped_tree_array)
Chris@0 440 nodes = { }
Chris@0 441 for node_hash in dumped_tree_array do
Chris@0 442 name = node_hash[:name]
Chris@0 443 parent_name = node_hash[:parent]
Chris@0 444 content = Marshal.load(node_hash[:content])
Chris@0 445
Chris@0 446 if parent_name then
Chris@0 447 nodes[name] = current_node = Tree::TreeNode.new(name, content)
Chris@0 448 nodes[parent_name].add current_node
Chris@0 449 else
Chris@0 450 # This is the root node, hence initialize self.
Chris@0 451 initialize(name, content)
Chris@0 452
Chris@0 453 nodes[name] = self # Add self to the list of nodes
Chris@0 454 end
Chris@0 455 end
Chris@0 456 end
Chris@0 457
Chris@0 458 # Returns depth of the tree from this node. A single leaf node has a
Chris@0 459 # depth of 1.
Chris@0 460 def depth
Chris@0 461 return 1 if isLeaf?
Chris@0 462 1 + @children.collect { |child| child.depth }.max
Chris@0 463 end
Chris@0 464
Chris@0 465 # Returns breadth of the tree at this node level. A single node has a
Chris@0 466 # breadth of 1.
Chris@0 467 def breadth
Chris@0 468 return 1 if isRoot?
Chris@0 469 parent.children.size
Chris@0 470 end
Chris@0 471
Chris@0 472 protected :parent=, :setAsRoot!, :createDumpRep
Chris@0 473
Chris@0 474 end
Chris@0 475 end
Chris@0 476
Chris@0 477 # $Log: tree.rb,v $
Chris@0 478 # Revision 1.29 2007/12/22 00:28:59 anupamsg
Chris@0 479 # Added more test cases, and enabled ZenTest compatibility.
Chris@0 480 #
Chris@0 481 # Revision 1.28 2007/12/20 03:19:33 anupamsg
Chris@0 482 # * README (Module): Modified the install instructions from source.
Chris@0 483 # (Module): Updated the minor version number.
Chris@0 484 #
Chris@0 485 # Revision 1.27 2007/12/20 03:00:03 anupamsg
Chris@0 486 # Minor code changes. Removed self_initialize from the protected methods' list.
Chris@0 487 #
Chris@0 488 # Revision 1.26 2007/12/20 02:50:04 anupamsg
Chris@0 489 # (Tree::TreeNode): Removed the spurious self_initialize from the protected list.
Chris@0 490 #
Chris@0 491 # Revision 1.25 2007/12/19 20:28:05 anupamsg
Chris@0 492 # Removed the unnecesary self_initialize method.
Chris@0 493 #
Chris@0 494 # Revision 1.24 2007/12/19 06:39:17 anupamsg
Chris@0 495 # Removed the unnecessary field and record separator constants. Also updated the
Chris@0 496 # history.txt file.
Chris@0 497 #
Chris@0 498 # Revision 1.23 2007/12/19 06:25:00 anupamsg
Chris@0 499 # (Tree::TreeNode): Minor fix to the comments. Also fixed the private/protected
Chris@0 500 # scope issue with the createDumpRep method.
Chris@0 501 #
Chris@0 502 # Revision 1.22 2007/12/19 06:22:03 anupamsg
Chris@0 503 # Updated the marshalling logic to correctly handle non-string content. This
Chris@0 504 # should fix the bug # 15614 ("When dumping with an Object as the content, you get
Chris@0 505 # a delimiter collision")
Chris@0 506 #
Chris@0 507 # Revision 1.21 2007/12/19 02:24:17 anupamsg
Chris@0 508 # Updated the marshalling logic to handle non-string contents on the nodes.
Chris@0 509 #
Chris@0 510 # Revision 1.20 2007/10/10 08:42:57 anupamsg
Chris@0 511 # Release 0.4.3
Chris@0 512 #
Chris@0 513 # Revision 1.19 2007/08/31 01:16:27 anupamsg
Chris@0 514 # Added breadth and pre-order traversals for the tree. Also added a method
Chris@0 515 # to return the detached copy of a node from the tree.
Chris@0 516 #
Chris@0 517 # Revision 1.18 2007/07/21 05:14:44 anupamsg
Chris@0 518 # Added a VERSION constant to the Tree module,
Chris@0 519 # and using the same in the Rakefile.
Chris@0 520 #
Chris@0 521 # Revision 1.17 2007/07/21 03:24:25 anupamsg
Chris@0 522 # Minor edits to parameter names. User visible functionality does not change.
Chris@0 523 #
Chris@0 524 # Revision 1.16 2007/07/18 23:38:55 anupamsg
Chris@0 525 # Minor updates to tree.rb
Chris@0 526 #
Chris@0 527 # Revision 1.15 2007/07/18 22:11:50 anupamsg
Chris@0 528 # Added depth and breadth methods for the TreeNode.
Chris@0 529 #
Chris@0 530 # Revision 1.14 2007/07/18 19:33:27 anupamsg
Chris@0 531 # Added a new binary tree implementation.
Chris@0 532 #
Chris@0 533 # Revision 1.13 2007/07/18 07:17:34 anupamsg
Chris@0 534 # Fixed a issue where TreeNode.ancestors was shadowing Module.ancestors. This method
Chris@0 535 # has been renamed to TreeNode.parentage.
Chris@0 536 #
Chris@0 537 # Revision 1.12 2007/07/17 03:39:28 anupamsg
Chris@0 538 # Moved the CVS Log keyword to end of the files.
Chris@0 539 #