     @rootNode = new Leaf(Point.infinity(), new Set)
 
   insert: (id, start, end) ->
-    ids = new Set
-    ids.add(id)
-    @rootNode.findContaining(start, ids) if start.compare(end) is 0
-    if splitNodes = @rootNode.insert(ids, start, end)
+    if splitNodes = @rootNode.insert(new Set().add(id), start, end)
       @rootNode = new Node(splitNodes)
 
   delete: (id) ->

    # shrink enough, we may need to shrink subsequent leaves.
    @extent.traversalFrom(myOldExtent).traversalFrom(spliceDelta)

  shouldMergeWith: (other) ->
    setEqual(@ids, other.ids)

  merge: (other) ->
    new Leaf(@extent.traverse(other.extent), new Set(@ids))

  getStart: (id) ->
    Point.zero() if @ids.has(id)

  getEnd: (id) ->
    @extent if @ids.has(id)

  hasEmptyRightmostLeaf: ->
    @extent.isZero()

  hasEmptyLeftmostLeaf: ->
    @extent.isZero()

  findContaining: (point, set) ->
    addSet(set, @ids)

  findIntersecting: (start, end, set) ->
    addSet(set, @ids)

  toString: (indentLevel=0) ->
    indent = ""

      return

  delete: (id) ->
    return unless @ids.delete(id)
    i = 0
    while i < @children.length
      @children[i].delete(id)
      if @children[i - 1]?.shouldMergeWith(@children[i])
        @children.splice(i - 1, 2, @children[i - 1].merge(@children[i]))
      else
        i++

  splice: (position, oldExtent, newExtent, excludedIds) ->
    oldRangeIsEmpty = oldExtent.isZero()
    childEnd = Point.zero()
    for child in @children
      childStart = childEnd
      childEnd = childStart.traverse(child.extent)

      if remainderToDelete?
        remainderToDelete = child.splice(Point.zero(), remainderToDelete, Point.zero())
        continue

      switch childEnd.compare(position)
        when -1 then childPrecedesRange = true
        when 0  then childPrecedesRange = not (child.hasEmptyRightmostLeaf() and oldRangeIsEmpty)
        when 1  then childPrecedesRange = false
      continue if childPrecedesRange

      relativeStart = position.traversalFrom(childStart)
      remainderToDelete = child.splice(relativeStart, oldExtent, newExtent, excludedIds)

    @extent = @extent
      .traverse(newExtent.traversalFrom(oldExtent))
      .traverse(remainderToDelete)
    remainderToDelete

  getStart: (id) ->
    return unless @ids.has(id)
    childEnd = Point.zero()
    for child in @children
      childStart = childEnd
      childEnd = childStart.traverse(child.extent)
      if startRelativeToChild = child.getStart(id)
        return childStart.traverse(startRelativeToChild)
    return

  getEnd: (id) ->
    return unless @ids.has(id)
    childEnd = Point.zero()
    for child in @children
      childStart = childEnd
      childEnd = childStart.traverse(child.extent)
      if endRelativeToChild = child.getEnd(id)
        end = childStart.traverse(endRelativeToChild)
      else if end?
        break
    end

  findContaining: (point, set) ->
    childEnd = Point.zero()
    for child in @children
      childStart = childEnd
      childEnd = childStart.traverse(child.extent)
      continue if childEnd.compare(point) < 0
      break if childStart.compare(point) > 0
      child.findContaining(point.traversalFrom(childStart), set)

  findIntersecting: (start, end, set) ->
    if start.isZero() and end.compare(@extent) is 0
      addSet(set, @ids)
      return

    childEnd = Point.zero()
    for child in @children
      childStart = childEnd
      childEnd = childStart.traverse(child.extent)
      continue if childEnd.compare(start) < 0
      break if childStart.compare(end) > 0
      child.findIntersecting(
        Point.max(Point.zero(), start.traversalFrom(childStart)),
        Point.min(child.extent, end.traversalFrom(childStart)),
        set
      )

  hasEmptyRightmostLeaf: ->
    @children[@children.length - 1].hasEmptyRightmostLeaf()

  hasEmptyLeftmostLeaf: ->
    @children[0].hasEmptyLeftmostLeaf()

  shouldMergeWith: (other) ->
    @children.length + other.children.length <= BRANCHING_FACTOR

  merge: (other) ->
    new Node(@children.concat(other.children))

  toString: (indentLevel=0) ->
    indent = ""
