<commit_before>/*
  ServerJS Javascript DOM
*/
var core = {
  
  // Returns Array
  mapDOMNodes : function(parent, recursive, callback) {

    var results = [], result, child, i;
    // mark children readonly
    if (parent.childNodes) {
      for (i=0; i<parent.childNodes.length;i++)
      {
        child = parent.childNodes.item(i);
        if (callback(child)) {
          results[results.length] = child;
        }

        if (recursive) {
          result = core.mapDOMNodes(child, true, callback);
          for (var a=0; a<result.length;a++) {
            results.push(result[a]);
          }
          //results.push.apply(results, result);
        }
      }
    }
    return results;
  },
  
  markTreeReadonly : function(el) {
    el._readonly = true;
    
    // mark children readonly
    if (el.children) {
      for (var i=0; i<el.children.length;i++)
      {
        core.markTreeReadonly(el.children.item(i));
      }
    }
    
    // also mark attributes and their children read-only
    if (el.attributes) {
      for (var i=0; i<el.attributes.length;i++)
      {
        core.markTreeReadonly(el.attributes.item(i));
      }
    }
  }
};
var sys = require("sys");

core.DOMException = function(code) {
  this._code = code;
};

core.DOMException.prototype = {
	get code() { return this._code; }
};

core.DOMException.prototype.__proto__ = Error.prototype;

// ExceptionCode
var INDEX_SIZE_ERR     = 1;
var DOMSTRING_SIZE_ERR = 2;
var HIERARCHY_REQUEST_ERR = 3;
var WRONG_DOCUMENT_ERR = 4;
var INVALID_CHARACTER_ERR = 5;
var NO_DATA_ALLOWED_ERR = 6;
var NO_MODIFICATION_ALLOWED_ERR = 7;
var NOT_FOUND_ERR      = 8;
var NOT_SUPPORTED_ERR  = 9;
var INUSE_ATTRIBUTE_ERR = 10;

// ExceptionCode
var INDEX_SIZE_ERR     = 1;
var DOMSTRING_SIZE_ERR = 2;
var HIERARCHY_REQUEST_ERR = 3;
var WRONG_DOCUMENT_ERR = 4;
var INVALID_CHARACTER_ERR = 5;
var NO_DATA_ALLOWED_ERR = 6;
var NO_MODIFICATION_ALLOWED_ERR = 7;
var NOT_FOUND_ERR      = 8;
var NOT_SUPPORTED_ERR  = 9;
var INUSE_ATTRIBUTE_ERR = 10;


core.NodeList = function(document, element, tagName) {
  this._dav = 'was here 2';
  this._document = document;
  this._element  = element;
  this._tagName  = tagName;

};
core.NodeList.prototype = {
  /* returns Node */
  item : function(index) {
    return this[index] || null;
  },
  
  // TODO: make this "private"
  // Array Remove - By <NAME> (MIT Licensed)
  remove : function(from, to) {
    var rest = this.slice((to || from) + 1 || this.length);
    this.length = from < 0 ? this.length + from : from;
    return this.push.apply(this, rest);
  },

  toString: function() {
    return '[ jsdom NodeList ]: ' + this.length;
  }
};
// TODO: NO!
core.NodeList.prototype.__proto__ = Array.prototype;

core.LiveNodeList = function(document, element, callback) {
  // TODO: caching on the document
    this._dav = 'was here';
    this._callback = callback;
    this._element  = element;
    this._document = document || element;
    var results = core.mapDOMNodes(this._element, true, this._callback);
    for (var i = 0; i < results.length; i++) {
        this[i] = results[i];
    }
};

core.LiveNodeList.prototype = {
  /* returns Integer */
  get length() {
    var results = core.mapDOMNodes(this._element, true, this._callback);
    return results.length || 0;
  },
  
  /* returns Node */
  item : function(index) {
    var results = core.mapDOMNodes(this._element, true, this._callback);
    return results[index] || null;
  }
};

core.DOMImplementation = function(document, /* Object */ features) {
  this._ownerDocument = document;
  this._features = features;
};
core.DOMImplementation.prototype = {
  get ownerDocument() { return this._ownerDocument; },
  hasFeature: function(/* string */ feature, /* string */ version) {
    for (var i in this._features)
    {
      if (this._features.hasOwnProperty(i) && 
          i.toLowerCase() === feature.toLowerCase() && 
          (this._features[i] === version || !version))
      {
        return true;
      }
    }
    return false;
  }
};


core.Node = function (ownerDocument) {
	this._children = new core.NodeList();
	this._nodeValue = null;
  this._parentNode = null;
  this._ownerDocument = ownerDocument;
  this._attributes = new core.AttrNodeMap(this.ownerDocument, this);
  this._nodeName   = null;
  this._readonly   = false;
  this.style = {};
};
core.Node.prototype = {
  
  get ELEMENT_NODE() { return 1; },
  get ATTRIBUTE_NODE() { return 2; },
  get TEXT_NODE() { return 3; },
  get CDATA_SECTION_NODE() { return 4; },
  get ENTITY_REFERENCE_NODE() { return 5; },  
  get ENTITY_NODE() { return 6; },
  get PROCESSING_INSTRUCTION_NODE() { return 7; },
  get COMMENT_NODE() { return 8; },
  get DOCUMENT_NODE() { return 9; },
  get DOCUMENT_TYPE_NODE() { return 10; },
  get DOCUMENT_FRAGMENT_NODE() { return 11; },
  get NOTATION_NODE() { return 12; },

  get children() { return this._children; },
  get nodeValue() { return this._nodeValue; },
  set nodeValue(value) { 
  
    // readonly
    if (this.readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }
  
    this._nodeValue = value; 
  },
  get parentNode() { return this._parentNode; },
  
  get nodeName() { 
    var name = this._nodeName || this._tagName; 
    if (this.nodeType === this.ELEMENT_NODE &&
        this.ownerDocument                  && 
        this.ownerDocument.doctype          &&
        this.ownerDocument.doctype.name.indexOf("html") !== -1) 
    { 
      return name.toUpperCase();
    }
    return name;
  
  },
  set nodeName() { throw new core.DOMException(); },  
  
  get attributes() { return this._attributes; },

  get firstChild() { 
    return (this._children && this._children.length && this._children.item(0)) ? 
            this._children.item(0)                    :
            null; 
  },
  set firstChild() { throw new core.DOMException(); },
  get ownerDocument() { return this._ownerDocument; },
  
  get readonly() { return this._readonly; },
  
  get lastChild() { 
    return (this._children && this._children.length && this._children[this._children.length-1]) ? 
            this._children.item(this._children.length-1) : 
            null; 
  },
  set lastChild() { throw new core.DOMException(); },

  get childNodes() { return this._children; },
  set childNodes() { throw new core.DOMException(); },

  get nextSibling() { 
    // find this node's index in the parentNode, add one and call it a day
    var index = 0;

    if (!this._parentNode                   || 
        !this._parentNode.childNodes        || 
        !this._parentNode.childNodes.length || 
         this._parentNode.childNodes.length < 2) 
    {
      return null;
    }

    var currentNode;
    var index = 0;

    while ((currentNode = this._parentNode.childNodes[index]))
    {
      index++;
      if (currentNode === this) { break; }
    }
    
    // TODO: there is some subtle weirdness here.
    if (this._parentNode.childNodes.item(index) === this) {
      index++;
    }
    
    return this._parentNode.childNodes.item(index) || null;
  },
  set nextSibling() { throw new core.DOMException(); },

  get previousSibling() { 
      // find this node's index in the parentNode, add one and call it a day
      var index = 0;

      if (!this._parentNode                   || 
          !this._parentNode.childNodes        || 
          !this._parentNode.childNodes.length || 
           this._parentNode.childNodes.length < 1) 
      {
          return null;
      }

      var currentNode;
      while ((currentNode = this._parentNode.childNodes[index]))
      {
          if (currentNode === this) { break; }
          index++;
      }

      return this._parentNode.childNodes[index-1] || null;
  },
  set previousSibling() { throw new core.DOMException(); },

  /* returns Node */ 
  insertBefore :  function(/* Node */ newChild, /* Node*/ refChild){

    // readonly
    if (this.readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }

	  if (newChild.nodeType && newChild.nodeType === this.ATTRIBUTE_NODE) {
	    throw new core.DOMException(HIERARCHY_REQUEST_ERR);
	  }
	  
	  if (newChild.ownerDocument !== this.ownerDocument) {
      throw new core.DOMException(WRONG_DOCUMENT_ERR);
    }

    var found = false;
    
    // if the newChild is already in the tree elsewhere, remove it first
    if (newChild._parentNode) {
      newChild._parentNode.removeChild(newChild);
    }

    // if refChild is null, add to the end of the list
    if (refChild === null) {
      return this.appendChild(newChild);
    }

    for (var i=0;i<this._children.length; i++)
    {
      if (this._children[i] === refChild) {
        var current = this;
        // search for parents matching the newChild
        while ((current = current._parentNode))
        {
          if (current === newChild) {
            throw new core.DOMException(HIERARCHY_REQUEST_ERR);
          }
        }        

    	  // fragments are merged into the element
    	  if (newChild.nodeType === this.DOCUMENT_FRAGMENT_NODE) {
    	    var length = newChild.children.length;
    	    var j;
    	    var tmpNode;
    	    var child;
    	    
    	    for (j=0; j<length; j++)
    	    {
    	      tmpNode = newChild.removeChild(newChild.children.item(j));
    	      this.insertBefore(tmpNode, refChild);
    	    }
    	  } else {
    	    this._children.splice(i,0,newChild);
    	    newChild._parentNode = this;
    	  }
        found = true;
        break;
      }
    }
    
    if (!found) {
      throw new core.DOMException(NOT_FOUND_ERR); 
    } else {
      return newChild;
    }    
  }, // raises(DOMException);

  /* returns Node */
  replaceChild : function(/* Node */ newChild, /* Node */ oldChild){

    // readonly
    if (this.readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }
    
    if (newChild.nodeType === this.ATTRIBUTE_NODE) {
	    throw new core.DOMException(HIERARCHY_REQUEST_ERR);
	  }
    
    // moving elements across documents
    if (newChild.ownerDocument !== this.ownerDocument) {
      throw new core.DOMException(WRONG_DOCUMENT_ERR);
    }
    
    for (var i=0;i<this._children.length; i++)
    {
      if (this._children[i] === oldChild) {
        var current = this;
        // search for parents matching the newChild
        while ((current = current._parentNode))
        {
          if (current === newChild) {
            throw new core.DOMException(HIERARCHY_REQUEST_ERR);
          }
        }
        
        this._children.remove(i,i);

        if (newChild.parentNode && newChild.parentNode.removeChild) {
          newChild.parentNode.removeChild(newChild);
        }
        newChild._parentNode = this;

        // insert the new child at this location
        if (newChild.nodeType === this.DOCUMENT_FRAGMENT_NODE) {
          var child;
          for (var j = 0; j<newChild.children.length;j++)
          {
            child = newChild.children.item(j);
            this._children.splice(i+j,0, child);
          }
        } else {
          this._children.splice(i,0, newChild);
        }
        
        return oldChild;
      }
    }
    throw new core.DOMException(NOT_FOUND_ERR);
  }, //raises(DOMException);

  /* returns Node */
  removeChild : function(/* Node */ oldChild){
    
    // readonly
    if (this.readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }
    
    var found = false;
    for (var i=0;i<this._children.length; i++)
    {
      if (this._children[i] === oldChild) {
        found=true;
        this._children.remove(i,i);
        oldChild._parentNode = null;
        if (this.id) {
            if (this._ownerDocument._ids) {
                //TODO
                //this._ownerDocument._ids[this.id] = null;
                //delete this._ownerDocument._ids[this.id];
            }
        }
        return oldChild;
      }
    }
    
    // node was not found.
    throw new core.DOMException(NOT_FOUND_ERR); 

  }, // raises(DOMException);
  
  /* returns Node */
  appendChild : function(/* Node */ newChild){
	  // readonly
    if (this.readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }
    
	  if (newChild.nodeType === this.ATTRIBUTE_NODE) {
	    throw new core.DOMException(HIERARCHY_REQUEST_ERR);
	  }
    
    // avoid recursion
    var cur = this;
    do {
      if (cur === newChild) {
        throw new core.DOMException(HIERARCHY_REQUEST_ERR);
      }
      
    } while ((cur = cur._parentNode))
	  
	  // only elements created with this.ownerDocument can be added here
    if (newChild.ownerDocument && 
        this.ownerDocument     && 
        newChild.ownerDocument !== this.ownerDocument) {
      throw new core.DOMException(WRONG_DOCUMENT_ERR);
    }
	  
	  
	  try {
	    this.removeChild(newChild);
	  } catch (e) { /* do nothing */ }
	  
	  // fragments are merged into the element
	  if (newChild.nodeType === this.DOCUMENT_FRAGMENT_NODE) {
	    var length = newChild.children.length;
	    var i = 0;
	    var tmpNode;
	    var child;
	    for (; i<length; i++)
	    {
	      tmpNode = newChild.removeChild(newChild.children.item(i));
	      this.appendChild(tmpNode);
	    }
	  } else {
      if (newChild && newChild.parentNode) {
  	    newChild.parentNode.removeChild(newChild);
  	  }
    
      // Attach the parent node.
	    newChild._parentNode = this;
	    this._children.push(newChild);
        if (this.id) {
            if (!this._ownerDocument._ids) {
                this._ownerDocument._ids = {};
            }
            this._ownerDocument._ids[this.id] = this;
        }
	  }
	
  	return newChild;	
  }, // raises(DOMException);
  
  /* returns boolean */
  hasChildNodes : function() {
    return this.childNodes.length > 0;
  },
  
  /* returns Node */  
  cloneNode : function(/* bool */ deep) {
    
    var object = null;
    
    var attrCopy = function(src, dest) {
      if (src.attributes && src.attributes.length) {
        for (var i=0; i<src.attributes.length; i++)
        {
          dest.setAttribute(src.attributes.item(i).nodeName, src.attributes.item(i).nodeValue);
        }
      }
      return dest;
    };
    
    switch (this.nodeType) {
    
      case this.ELEMENT_NODE:
        object = attrCopy(this,this.ownerDocument.createElement(this.tagName));
      break;

      case this.TEXT_NODE:
        object = attrCopy(this,this.ownerDocument.createTextNode(this.tagName));
        object.nodeValue = this.nodeValue;
      break;
      case this.CDATA_SECTION_NODE:
        object = this.ownerDocument.createCDATASection(this.tagName);
        object.nodeValue = this.nodeValue;
      break;
      case this.ENTITY_REFERENCE_NODE:
        object = attrCopy(this,this.ownerDocument.createEntityReference(this._entity.name));
        object.nodeValue = this.nodeValue;
      break;
      case this.ATTRIBUTE_NODE:
        object = this.ownerDocument.createAttribute(this.name);
        //object.nodeValue = this.nodeValue;
      break;
      case this.ENTITY_NODE:
        object = attrCopy(this,this.ownerDocument.createEntityNode(this._entity.name));
        object.nodeValue = this.nodeValue;
      break;
      case this.PROCESSING_INSTRUCTION_NODE:
        object = attrCopy(this,this.ownerDocument.createProcessingInstruction(this._target, this._data));
        object.nodeValue = this.nodeValue;
      break;
      case this.COMMENT_NODE:
        object = this.ownerDocument.createComment(this.tagName);
        object.nodeValue = this.nodeValue;
      break;
      case this.DOCUMENT_NODE:
        object = attrCopy(this, new core.Document());
        // TODO: clone the doctype/entities/notations/etc?
      break;
      case this.DOCUMENT_TYPE_NODE:
        object = attrCopy(this, new core.DocumentType());
        object.nodeValue = this.nodeValue;
      break;
      case this.DOCUMENT_FRAGMENT_NODE:
        object = this.ownerDocument.createAttribute(this.tagName);
        object.nodeValue = this.nodeValue;
      break;
      case this.NOTATION_NODE:
        object = this.ownerDocument.createNotationNode(this._name, 
                                                       this._publicId, 
                                                       this._systemId);
        object = attrCopy(this,object);
        object.nodeValue = this.nodeValue;
      break;
      default:
        throw new core.DOMException(NOT_FOUND_ERR);
      break;
    }

    if (deep || this.nodeType === this.ATTRIBUTE_NODE) {
      var clone = null;
      for (var i=0; i<this.children.length; i++)
      {
        clone = this.children.item(i).cloneNode(true);
        if (!clone) {
          debug(this.children.item(i).nodeType);
        }
        if (clone.nodeType === this.ATTRIBUTE_NODE) {
          object.setAttributeNode(clone);
        } else {
          object.appendChild(clone);
        }
      }
    }
    
    return object;    
  },
  
  /* returns void */
  normalize: function() {
    var prevChild, child, attr,i;
    
    if (this._attributes && this._attributes.length) {
      for (i=0; i<this._attributes.length; i++)
      {
        if (attr = this._attributes.item(i).normalize) {
          attr = this._attributes.item(i).normalize();
        }
      }
    }
    
    for (i=0; i<this._children.length; i++)
    {
      child = this._children[i];
      
      if (child.normalize) {
        child.normalize();
      }

      if (i>0) {
        prevChild = this._children[i-1];
        
        if (child.nodeType === this.TEXT_NODE && prevChild.nodeType === this.TEXT_NODE)
        {
        
          // remove the child and decrement i
          prevChild.appendData(child.value);
          
          this.removeChild(child);
          i--;
        } 
      }
    }
  },
  
    toString: function() {
        var id = '';
        if (this.id) {
            id = '#' + this.id;
        }
        if (this.className) {
            id += '.' + this.className;
        }
        return '[ ' + this.tagName + id + ' ]';
    }
};


core.NamedNodeMap = function(document) {
	this._nodes = {};
	this._length = 0;
	this._ownerDocument = document;
	this._readonly = false;
};
core.NamedNodeMap.prototype = {
  get readonly() { return this._readonly; },
  get ownerDocument() { this._ownerDocument; },
    get length() {
        var count = 0;
        for (var i in this._nodes) {
            count++;
        }
        this._length = count;
        return this._length;
    },

  exists : function(name) {
    return (this._nodes[name] || this._nodes[name] === null) ? true : false;
  },
  
	/* returns Node */
	getNamedItem: function(/* string */ name) {
    return this._nodes[name] || null;
	},

	/* returns Node */
	setNamedItem: function(/* Node */ arg) {

    // readonly
    if (this._readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }
    
    // arg is from a different document
    if (arg && arg.ownerDocument !== this._ownerDocument) {
      throw new core.DOMException(WRONG_DOCUMENT_ERR);
    }

    // if this argument is already in use..
    if (arg && arg._parentNode) {
      throw new core.DOMException(INUSE_ATTRIBUTE_ERR);
    }
    
    var ret;
    if (!this._nodes[arg.name] || this._nodes[arg.name] === null) {
      this._length++;
      ret = null;
    } else {
      ret = this._nodes[arg.name];
    }
    arg._parentNode = this;
    arg._specified = true;
    this._nodes[arg.name] = arg;
    return ret;
	}, // raises: function(DOMException) {},

	/* returns Node */
	removeNamedItem: function(/* string */ name) {

	  // readonly
    if (this.readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }
    
    if (!this._nodes[name] && this._nodes[name] !== null) {
        throw new core.DOMException(NOT_FOUND_ERR);<commit_msg>fixed an index check issue<commit_after>/*
  ServerJS Javascript DOM
*/
var core = {
  
  // Returns Array
  mapDOMNodes : function(parent, recursive, callback) {

    var results = [], result, child, i;
    // mark children readonly
    if (parent.childNodes) {
      for (i=0; i<parent.childNodes.length;i++)
      {
        child = parent.childNodes.item(i);
        if (callback(child)) {
          results[results.length] = child;
        }

        if (recursive) {
          result = core.mapDOMNodes(child, true, callback);
          for (var a=0; a<result.length;a++) {
            results.push(result[a]);
          }
          //results.push.apply(results, result);
        }
      }
    }
    return results;
  },
  
  markTreeReadonly : function(el) {
    el._readonly = true;
    
    // mark children readonly
    if (el.children) {
      for (var i=0; i<el.children.length;i++)
      {
        core.markTreeReadonly(el.children.item(i));
      }
    }
    
    // also mark attributes and their children read-only
    if (el.attributes) {
      for (var i=0; i<el.attributes.length;i++)
      {
        core.markTreeReadonly(el.attributes.item(i));
      }
    }
  }
};
var sys = require("sys");

core.DOMException = function(code) {
  this._code = code;
};

core.DOMException.prototype = {
	get code() { return this._code; }
};

core.DOMException.prototype.__proto__ = Error.prototype;

// ExceptionCode
var INDEX_SIZE_ERR     = 1;
var DOMSTRING_SIZE_ERR = 2;
var HIERARCHY_REQUEST_ERR = 3;
var WRONG_DOCUMENT_ERR = 4;
var INVALID_CHARACTER_ERR = 5;
var NO_DATA_ALLOWED_ERR = 6;
var NO_MODIFICATION_ALLOWED_ERR = 7;
var NOT_FOUND_ERR      = 8;
var NOT_SUPPORTED_ERR  = 9;
var INUSE_ATTRIBUTE_ERR = 10;

// ExceptionCode
var INDEX_SIZE_ERR     = 1;
var DOMSTRING_SIZE_ERR = 2;
var HIERARCHY_REQUEST_ERR = 3;
var WRONG_DOCUMENT_ERR = 4;
var INVALID_CHARACTER_ERR = 5;
var NO_DATA_ALLOWED_ERR = 6;
var NO_MODIFICATION_ALLOWED_ERR = 7;
var NOT_FOUND_ERR      = 8;
var NOT_SUPPORTED_ERR  = 9;
var INUSE_ATTRIBUTE_ERR = 10;


core.NodeList = function(document, element, tagName) {
  this._dav = 'was here 2';
  this._document = document;
  this._element  = element;
  this._tagName  = tagName;

};
core.NodeList.prototype = {
  /* returns Node */
  item : function(index) {
    return this[index] || null;
  },
  
  // TODO: make this "private"
  // Array Remove - By <NAME> (MIT Licensed)
  remove : function(from, to) {
    var rest = this.slice((to || from) + 1 || this.length);
    this.length = from < 0 ? this.length + from : from;
    return this.push.apply(this, rest);
  },

  toString: function() {
    return '[ jsdom NodeList ]: ' + this.length;
  }
};
// TODO: NO!
core.NodeList.prototype.__proto__ = Array.prototype;

core.LiveNodeList = function(document, element, callback) {
  // TODO: caching on the document
    this._dav = 'was here';
    this._callback = callback;
    this._element  = element;
    this._document = document || element;
    var results = core.mapDOMNodes(this._element, true, this._callback);
    for (var i = 0; i < results.length; i++) {
        this[i] = results[i];
    }
};

core.LiveNodeList.prototype = {
  /* returns Integer */
  get length() {
    var results = core.mapDOMNodes(this._element, true, this._callback);
    return results.length || 0;
  },
  
  /* returns Node */
  item : function(index) {
    var results = core.mapDOMNodes(this._element, true, this._callback);
    return results[index] || null;
  }
};

core.DOMImplementation = function(document, /* Object */ features) {
  this._ownerDocument = document;
  this._features = features;
};
core.DOMImplementation.prototype = {
  get ownerDocument() { return this._ownerDocument; },
  hasFeature: function(/* string */ feature, /* string */ version) {
    for (var i in this._features)
    {
      if (this._features.hasOwnProperty(i) && 
          i.toLowerCase() === feature.toLowerCase() && 
          (this._features[i] === version || !version))
      {
        return true;
      }
    }
    return false;
  }
};


core.Node = function (ownerDocument) {
	this._children = new core.NodeList();
	this._nodeValue = null;
  this._parentNode = null;
  this._ownerDocument = ownerDocument;
  this._attributes = new core.AttrNodeMap(this.ownerDocument, this);
  this._nodeName   = null;
  this._readonly   = false;
  this.style = {};
};
core.Node.prototype = {
  
  get ELEMENT_NODE() { return 1; },
  get ATTRIBUTE_NODE() { return 2; },
  get TEXT_NODE() { return 3; },
  get CDATA_SECTION_NODE() { return 4; },
  get ENTITY_REFERENCE_NODE() { return 5; },  
  get ENTITY_NODE() { return 6; },
  get PROCESSING_INSTRUCTION_NODE() { return 7; },
  get COMMENT_NODE() { return 8; },
  get DOCUMENT_NODE() { return 9; },
  get DOCUMENT_TYPE_NODE() { return 10; },
  get DOCUMENT_FRAGMENT_NODE() { return 11; },
  get NOTATION_NODE() { return 12; },

  get children() { return this._children; },
  get nodeValue() { return this._nodeValue; },
  set nodeValue(value) { 
  
    // readonly
    if (this.readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }
  
    this._nodeValue = value; 
  },
  get parentNode() { return this._parentNode; },
  
  get nodeName() { 
    var name = this._nodeName || this._tagName; 
    if (this.nodeType === this.ELEMENT_NODE &&
        this.ownerDocument                  && 
        this.ownerDocument.doctype          &&
        this.ownerDocument.doctype.name.indexOf("html") !== -1) 
    { 
      return name.toUpperCase();
    }
    return name;
  
  },
  set nodeName() { throw new core.DOMException(); },  
  
  get attributes() { return this._attributes; },

  get firstChild() { 
    return (this._children && this._children.length && this._children.item(0)) ? 
            this._children.item(0)                    :
            null; 
  },
  set firstChild() { throw new core.DOMException(); },
  get ownerDocument() { return this._ownerDocument; },
  
  get readonly() { return this._readonly; },
  
  get lastChild() { 
    return (this._children && this._children.length && this._children[this._children.length-1]) ? 
            this._children.item(this._children.length-1) : 
            null; 
  },
  set lastChild() { throw new core.DOMException(); },

  get childNodes() { return this._children; },
  set childNodes() { throw new core.DOMException(); },

  get nextSibling() { 
    // find this node's index in the parentNode, add one and call it a day
    var index = 0;

    if (!this._parentNode                   || 
        !this._parentNode.childNodes        || 
        !this._parentNode.childNodes.length || 
         this._parentNode.childNodes.length < 2) 
    {
      return null;
    }

    var currentNode;
    var index = 0;

    while ((currentNode = this._parentNode.childNodes[index]))
    {
      index++;
      if (currentNode === this) { break; }
    }
    
    // TODO: there is some subtle weirdness here.
    if (this._parentNode.childNodes.item(index) === this) {
      index++;
    }
    
    return this._parentNode.childNodes.item(index) || null;
  },
  set nextSibling() { throw new core.DOMException(); },

  get previousSibling() { 
      // find this node's index in the parentNode, add one and call it a day
      var index = 0;

      if (!this._parentNode                   || 
          !this._parentNode.childNodes        || 
          !this._parentNode.childNodes.length || 
           this._parentNode.childNodes.length < 1) 
      {
          return null;
      }

      var currentNode;
      while ((currentNode = this._parentNode.childNodes[index]))
      {
          if (currentNode === this) { break; }
          index++;
      }

      return this._parentNode.childNodes[index-1] || null;
  },
  set previousSibling() { throw new core.DOMException(); },

  /* returns Node */ 
  insertBefore :  function(/* Node */ newChild, /* Node*/ refChild){

    // readonly
    if (this.readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }

	  if (newChild.nodeType && newChild.nodeType === this.ATTRIBUTE_NODE) {
	    throw new core.DOMException(HIERARCHY_REQUEST_ERR);
	  }
	  
	  if (newChild.ownerDocument !== this.ownerDocument) {
      throw new core.DOMException(WRONG_DOCUMENT_ERR);
    }

    var found = false;
    
    // if the newChild is already in the tree elsewhere, remove it first
    if (newChild._parentNode) {
      newChild._parentNode.removeChild(newChild);
    }

    // if refChild is null, add to the end of the list
    if (refChild === null) {
      return this.appendChild(newChild);
    }

    for (var i=0;i<this._children.length; i++)
    {
      if (this._children[i] === refChild) {
        var current = this;
        // search for parents matching the newChild
        while ((current = current._parentNode))
        {
          if (current === newChild) {
            throw new core.DOMException(HIERARCHY_REQUEST_ERR);
          }
        }        

    	  // fragments are merged into the element
    	  if (newChild.nodeType === this.DOCUMENT_FRAGMENT_NODE) {
    	    var length = newChild.children.length;
    	    var j;
    	    var tmpNode;
    	    var child;
    	    
    	    for (j=0; j<length; j++)
    	    {
    	      tmpNode = newChild.removeChild(newChild.children.item(j));
    	      this.insertBefore(tmpNode, refChild);
    	    }
    	  } else {
    	    this._children.splice(i,0,newChild);
    	    newChild._parentNode = this;
    	  }
        found = true;
        break;
      }
    }
    
    if (!found) {
      throw new core.DOMException(NOT_FOUND_ERR); 
    } else {
      return newChild;
    }    
  }, // raises(DOMException);

  /* returns Node */
  replaceChild : function(/* Node */ newChild, /* Node */ oldChild){

    // readonly
    if (this.readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }
    
    if (newChild.nodeType === this.ATTRIBUTE_NODE) {
	    throw new core.DOMException(HIERARCHY_REQUEST_ERR);
	  }
    
    // moving elements across documents
    if (newChild.ownerDocument !== this.ownerDocument) {
      throw new core.DOMException(WRONG_DOCUMENT_ERR);
    }
    
    for (var i=0;i<this._children.length; i++)
    {
      if (this._children[i] === oldChild) {
        var current = this;
        // search for parents matching the newChild
        while ((current = current._parentNode))
        {
          if (current === newChild) {
            throw new core.DOMException(HIERARCHY_REQUEST_ERR);
          }
        }
        
        this._children.remove(i,i);

        if (newChild.parentNode && newChild.parentNode.removeChild) {
          newChild.parentNode.removeChild(newChild);
        }
        newChild._parentNode = this;

        // insert the new child at this location
        if (newChild.nodeType === this.DOCUMENT_FRAGMENT_NODE) {
          var child;
          for (var j = 0; j<newChild.children.length;j++)
          {
            child = newChild.children.item(j);
            this._children.splice(i+j,0, child);
          }
        } else {
          this._children.splice(i,0, newChild);
        }
        
        return oldChild;
      }
    }
    throw new core.DOMException(NOT_FOUND_ERR);
  }, //raises(DOMException);

  /* returns Node */
  removeChild : function(/* Node */ oldChild){
    
    // readonly
    if (this.readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }
    
    var found = false;
    for (var i=0;i<this._children.length; i++)
    {
      if (this._children[i] === oldChild) {
        found=true;
        this._children.remove(i,i);
        oldChild._parentNode = null;
        if (this.id) {
            if (this._ownerDocument._ids) {
                //TODO
                //this._ownerDocument._ids[this.id] = null;
                //delete this._ownerDocument._ids[this.id];
            }
        }
        return oldChild;
      }
    }
    
    // node was not found.
    throw new core.DOMException(NOT_FOUND_ERR); 

  }, // raises(DOMException);
  
  /* returns Node */
  appendChild : function(/* Node */ newChild){
	  // readonly
    if (this.readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }
    
	  if (newChild.nodeType === this.ATTRIBUTE_NODE) {
	    throw new core.DOMException(HIERARCHY_REQUEST_ERR);
	  }
    
    // avoid recursion
    var cur = this;
    do {
      if (cur === newChild) {
        throw new core.DOMException(HIERARCHY_REQUEST_ERR);
      }
      
    } while ((cur = cur._parentNode))
	  
	  // only elements created with this.ownerDocument can be added here
    if (newChild.ownerDocument && 
        this.ownerDocument     && 
        newChild.ownerDocument !== this.ownerDocument) {
      throw new core.DOMException(WRONG_DOCUMENT_ERR);
    }
	  
	  
	  try {
	    this.removeChild(newChild);
	  } catch (e) { /* do nothing */ }
	  
	  // fragments are merged into the element
	  if (newChild.nodeType === this.DOCUMENT_FRAGMENT_NODE) {
	    var length = newChild.children.length;
	    var i = 0;
	    var tmpNode;
	    var child;
	    for (; i<length; i++)
	    {
	      tmpNode = newChild.removeChild(newChild.children.item(i));
	      this.appendChild(tmpNode);
	    }
	  } else {
      if (newChild && newChild.parentNode) {
  	    newChild.parentNode.removeChild(newChild);
  	  }
    
      // Attach the parent node.
	    newChild._parentNode = this;
	    this._children.push(newChild);
        if (this.id) {
            if (!this._ownerDocument._ids) {
                this._ownerDocument._ids = {};
            }
            this._ownerDocument._ids[this.id] = this;
        }
	  }
	
  	return newChild;	
  }, // raises(DOMException);
  
  /* returns boolean */
  hasChildNodes : function() {
    return this.childNodes.length > 0;
  },
  
  /* returns Node */  
  cloneNode : function(/* bool */ deep) {
    
    var object = null;
    
    var attrCopy = function(src, dest) {
      if (src.attributes && src.attributes.length) {
        for (var i=0; i<src.attributes.length; i++)
        {
          dest.setAttribute(src.attributes.item(i).nodeName, src.attributes.item(i).nodeValue);
        }
      }
      return dest;
    };
    
    switch (this.nodeType) {
    
      case this.ELEMENT_NODE:
        object = attrCopy(this,this.ownerDocument.createElement(this.tagName));
      break;

      case this.TEXT_NODE:
        object = attrCopy(this,this.ownerDocument.createTextNode(this.tagName));
        object.nodeValue = this.nodeValue;
      break;
      case this.CDATA_SECTION_NODE:
        object = this.ownerDocument.createCDATASection(this.tagName);
        object.nodeValue = this.nodeValue;
      break;
      case this.ENTITY_REFERENCE_NODE:
        object = attrCopy(this,this.ownerDocument.createEntityReference(this._entity.name));
        object.nodeValue = this.nodeValue;
      break;
      case this.ATTRIBUTE_NODE:
        object = this.ownerDocument.createAttribute(this.name);
        //object.nodeValue = this.nodeValue;
      break;
      case this.ENTITY_NODE:
        object = attrCopy(this,this.ownerDocument.createEntityNode(this._entity.name));
        object.nodeValue = this.nodeValue;
      break;
      case this.PROCESSING_INSTRUCTION_NODE:
        object = attrCopy(this,this.ownerDocument.createProcessingInstruction(this._target, this._data));
        object.nodeValue = this.nodeValue;
      break;
      case this.COMMENT_NODE:
        object = this.ownerDocument.createComment(this.tagName);
        object.nodeValue = this.nodeValue;
      break;
      case this.DOCUMENT_NODE:
        object = attrCopy(this, new core.Document());
        // TODO: clone the doctype/entities/notations/etc?
      break;
      case this.DOCUMENT_TYPE_NODE:
        object = attrCopy(this, new core.DocumentType());
        object.nodeValue = this.nodeValue;
      break;
      case this.DOCUMENT_FRAGMENT_NODE:
        object = this.ownerDocument.createAttribute(this.tagName);
        object.nodeValue = this.nodeValue;
      break;
      case this.NOTATION_NODE:
        object = this.ownerDocument.createNotationNode(this._name, 
                                                       this._publicId, 
                                                       this._systemId);
        object = attrCopy(this,object);
        object.nodeValue = this.nodeValue;
      break;
      default:
        throw new core.DOMException(NOT_FOUND_ERR);
      break;
    }

    if (deep || this.nodeType === this.ATTRIBUTE_NODE) {
      var clone = null;
      for (var i=0; i<this.children.length; i++)
      {
        clone = this.children.item(i).cloneNode(true);
        if (!clone) {
          debug(this.children.item(i).nodeType);
        }
        if (clone.nodeType === this.ATTRIBUTE_NODE) {
          object.setAttributeNode(clone);
        } else {
          object.appendChild(clone);
        }
      }
    }
    
    return object;    
  },
  
  /* returns void */
  normalize: function() {
    var prevChild, child, attr,i;
    
    if (this._attributes && this._attributes.length) {
      for (i=0; i<this._attributes.length; i++)
      {
        if (attr = this._attributes.item(i).normalize) {
          attr = this._attributes.item(i).normalize();
        }
      }
    }
    
    for (i=0; i<this._children.length; i++)
    {
      child = this._children[i];
      
      if (child.normalize) {
        child.normalize();
      }

      if (i>0) {
        prevChild = this._children[i-1];
        
        if (child.nodeType === this.TEXT_NODE && prevChild.nodeType === this.TEXT_NODE)
        {
        
          // remove the child and decrement i
          prevChild.appendData(child.value);
          
          this.removeChild(child);
          i--;
        } 
      }
    }
  },
  
    toString: function() {
        var id = '';
        if (this.id) {
            id = '#' + this.id;
        }
        if (this.className) {
            id += '.' + this.className;
        }
        return '[ ' + this.tagName + id + ' ]';
    }
};


core.NamedNodeMap = function(document) {
	this._nodes = {};
	this._length = 0;
	this._ownerDocument = document;
	this._readonly = false;
};
core.NamedNodeMap.prototype = {
  get readonly() { return this._readonly; },
  get ownerDocument() { this._ownerDocument; },
    get length() {
        var count = 0;
        for (var i in this._nodes) {
            count++;
        }
        this._length = count;
        return this._length;
    },

  exists : function(name) {
    return (this._nodes[name] || this._nodes[name] === null) ? true : false;
  },
  
	/* returns Node */
	getNamedItem: function(/* string */ name) {
    return this._nodes[name] || null;
	},

	/* returns Node */
	setNamedItem: function(/* Node */ arg) {

    // readonly
    if (this._readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }
    
    // arg is from a different document
    if (arg && arg.ownerDocument !== this._ownerDocument) {
      throw new core.DOMException(WRONG_DOCUMENT_ERR);
    }

    // if this argument is already in use..
    if (arg && arg._parentNode) {
      throw new core.DOMException(INUSE_ATTRIBUTE_ERR);
    }
    
    var ret;
    if (!this._nodes[arg.name] || this._nodes[arg.name] === null) {
      this._length++;
      ret = null;
    } else {
      ret = this._nodes[arg.name];
    }
    arg._parentNode = this;
    arg._specified = true;
    this._nodes[arg.name] = arg;
    return ret;
	}, // raises: function(DOMException) {},

	/* returns Node */
	removeNamedItem: function(/* string */ name) {

	  // readonly
    if (this.readonly === true) {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
    }
    
    if (typeof this._nodes[name] === 'undefined') {
        throw new core.DOMException(NOT_FOUND_ERR);
{'fraction_non_alphanumeric': 0.12669637686632929, 'fraction_numerical': 0.003776720296094871, 'mean_word_length': 2.192508640784503, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7346999', 'n_tokens_mistral': 12604, 'n_tokens_neox': 12281, 'n_words': 2583}