def add(obj, index=-1)
      case
        when obj.is_a?(Array), obj.is_a?(NodeSet)
          obj.each_with_index do |e, i|
            add(e, index == -1 ? index : index+i)
          end
        when obj.is_a?(String)
          if obj[0] == '<' and obj[-1] == '>' and (s = Ox.parse(obj))
            add dclone s
          else
            type = :NewText
            nodes.insert(index, obj)
          end
        else
          type = :Add
          nodes.insert(index, obj)
          if obj.count_observers < 1 && @observer_peers
            obj.add_observer(@observer_peers.first.first)
          end
          obj.set_doc! @doc
      end
      report(type, obj, index)
      self
    end
def add(obj, index=-1)
      case
        when obj.is_a?(Array), obj.is_a?(NodeSet)
          obj.each_with_index do |e, i|
            add(e, index == -1 ? index : index+i)
          end
        when obj.is_a?(String)
          if obj[0] == '<' and obj[-1] == '>' and (s = Ox.parse(obj))
            add dclone s
          else
            type = :NewText
            nodes.insert(index, obj)
          end
        else
          type = :Add
          nodes.insert(index, obj)
          if obj.count_observers < 1 && @observer_peers
            obj.add_observer(@observer_peers.first.first)
          end
          obj.set_doc! @doc
      end
      report(type, obj, index)
      self
    end
@see #<<
 this version of the method allows insertions between existing elements

 @param obj [Element, Array] element or string to add to this Element; can insert arrays which are always inserted in order
 @param index [Fixnum] index at which to insert new node; inserts at end of element by default; when inserting arrays, index is incremented for each item to avoid reversing array order
 @return [Element] self