text: (function (global, factory) {
  	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  	typeof define === 'function' && define.amd ? define(['exports'], factory) :
  	(factory((global.SimpleDOM = {})));
  }(this, (function (exports) { 'use strict';
  
  function Node(nodeType, nodeName, nodeValue) {
    this.nodeType = nodeType;
    this.nodeName = nodeName;
    this.nodeValue = nodeValue;
  
    this.childNodes = new ChildNodes(this);
  
    this.parentNode = null;
    this.previousSibling = null;
    this.nextSibling = null;
    this.firstChild = null;
    this.lastChild = null;
  }
  
  Node.prototype._cloneNode = function() {
    return new Node(this.nodeType, this.nodeName, this.nodeValue);
  };
  
  Node.prototype.cloneNode = function(deep) {
    var node = this._cloneNode();
  
    if (deep) {
      var child = this.firstChild, nextChild = child;
  
      while (nextChild) {
        nextChild = child.nextSibling;
        node.appendChild(child.cloneNode(true));
        child = nextChild;
      }
    }
  
    return node;
  };
  
  Node.prototype.appendChild = function(node) {
    if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
      insertFragment(node, this, this.lastChild, null);
      return node;
    }
  
    if (node.parentNode) { node.parentNode.removeChild(node); }
  
    node.parentNode = this;
    var refNode = this.lastChild;
    if (refNode === null) {
      this.firstChild = node;
      this.lastChild = node;
    } else {
      node.previousSibling = refNode;
      refNode.nextSibling = node;
      this.lastChild = node;
    }
  
    return node;
  };
  
  function insertFragment(fragment, newParent, before, after) {
    if (!fragment.firstChild) { return; }
  
    var firstChild = fragment.firstChild;
    var lastChild = firstChild;
    var node = firstChild;
  
    firstChild.previousSibling = before;
    if (before) {
      before.nextSibling = firstChild;
    } else {
      newParent.firstChild = firstChild;
    }
  
    while (node) {
      node.parentNode = newParent;
      lastChild = node;
      node = node.nextSibling;
    }
  
    lastChild.nextSibling = after;
    if (after) {
      after.previousSibling = lastChild;
    } else {
      newParent.lastChild = lastChild;
    }
  }
  
  Node.prototype.insertBefore = function(node, refNode) {
    if (refNode == null) {
      return this.appendChild(node);
    }
  
    if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
      insertFragment(node, this, refNode ? refNode.previousSibling : null, refNode);
      return;
    }
  
    if (node.parentNode) { node.parentNode.removeChild(node); }
  
    node.parentNode = this;
  
    var previousSibling = refNode.previousSibling;
    if (previousSibling) {
      previousSibling.nextSibling = node;
      node.previousSibling = previousSibling;
    } else {
      node.previousSibling = null;
    }
  
    refNode.previousSibling = node;
    node.nextSibling = refNode;
  
    if (this.firstChild === refNode) {
      this.firstChild = node;
    }
  };
  
  Node.prototype.removeChild = function(refNode) {
    if (this.firstChild === refNode) {
      this.firstChild = refNode.nextSibling;
    }
    if (this.lastChild === refNode) {
      this.lastChild = refNode.previousSibling;
    }
    if (refNode.previousSibling) {
      refNode.previousSibling.nextSibling = refNode.nextSibling;
    }
    if (refNode.nextSibling) {
      refNode.nextSibling.previousSibling = refNode.previousSibling;
    }
    refNode.parentNode = null;
    refNode.nextSibling = null;
    refNode.previousSibling = null;
  };
  
  Node.ELEMENT_NODE = 1;
  Node.ATTRIBUTE_NODE = 2;
  Node.TEXT_NODE = 3;
  Node.CDATA_SECTION_NODE = 4;
  Node.ENTITY_REFERENCE_NODE = 5;
  Node.ENTITY_NODE = 6;
  Node.PROCESSING_INSTRUCTION_NODE = 7;
  Node.COMMENT_NODE = 8;
  Node.DOCUMENT_NODE = 9;
  Node.DOCUMENT_TYPE_NODE = 10;
  Node.DOCUMENT_FRAGMENT_NODE = 11;
  Node.NOTATION_NODE = 12;
  
  function ChildNodes(node) {
    this.node = node;
  }
  
  ChildNodes.prototype.item = function(index) {
    var child = this.node.firstChild;
  
    for (var i = 0; child && index !== i; i++) {
      child = child.nextSibling;
    }
  
    return child;
  };
  
  function Element(tagName) {
    tagName = tagName.toUpperCase();
  
    this.nodeConstructor(1, tagName, null);
    this.attributes = [];
    this.tagName = tagName;
  }
  
  Element.prototype = Object.create(Node.prototype);
  Element.prototype.constructor = Element;
  Element.prototype.nodeConstructor = Node;
  
  Element.prototype._cloneNode = function() {
    var node = new Element(this.tagName);
  
    node.attributes = this.attributes.map(function(attr) {
      return { name: attr.name, value: attr.value, specified: attr.specified };
    });
  
    return node;
  };
  
  Element.prototype.getAttribute = function(_name) {
    var attributes = this.attributes;
    var name = _name.toLowerCase();
    var attr;
    for (var i=0, l=attributes.length; i<l; i++) {
      attr = attributes[i];
      if (attr.name === name) {
        return attr.value;
      }
    }
    return '';
  };
  
  Element.prototype.setAttribute = function(_name, _value) {
    var attributes = this.attributes;
    var name = _name.toLowerCase();
    var value;
    if (typeof _value === 'string') {
      value = _value;
    } else {
      value = '' + _value;
    }
    var attr;
    for (var i=0, l=attributes.length; i<l; i++) {
      attr = attributes[i];
      if (attr.name === name) {
        attr.value = value;
        return;
      }
    }
    attributes.push({
      name: name,
      value: value,
      specified: true // serializer compat with old IE
    });
  };
  
  Element.prototype.removeAttribute = function(name) {
    var attributes = this.attributes;
    for (var i=0, l=attributes.length; i<l; i++) {
      var attr = attributes[i];
      if (attr.name === name) {
        attributes.splice(i, 1);
        return;
      }
    }
  };
  
  function DocumentFragment() {
    this.nodeConstructor(11, '#document-fragment', null);
  }
  
  DocumentFragment.prototype._cloneNode = function() {
    return new DocumentFragment();
  };
  
  DocumentFragment.prototype = Object.create(Node.prototype);
  DocumentFragment.prototype.constructor = DocumentFragment;
  DocumentFragment.prototype.nodeConstructor = Node;
  
  function Text(text) {
    this.nodeConstructor(3, '#text', text);
  }
  
  Text.prototype._cloneNode = function() {
    return new Text(this.nodeValue);
  };
  
  Text.prototype = Object.create(Node.prototype);
  Text.prototype.constructor = Text;
  Text.prototype.nodeConstructor = Node;
  
  function Comment(text) {
    this.nodeConstructor(8, '#comment', text);
  }
  
  Comment.prototype._cloneNode = function() {
    return new Comment(this.nodeValue);
  };
  
  Comment.prototype = Object.create(Node.prototype);
  Comment.prototype.constructor = Comment;
  Comment.prototype.nodeConstructor = Node;
  
  function RawHTMLSection(text) {
    this.nodeConstructor(-1, "#raw-html-section", text);
  }
  
  RawHTMLSection.prototype = Object.create(Node.prototype);
  RawHTMLSection.prototype.constructor = RawHTMLSection;
  RawHTMLSection.prototype.nodeConstructor = Node;
  
  function Document() {
    this.nodeConstructor(9, '#document', null);
    this.documentElement = new Element('html');
    this.head = new Element('head');
    this.body = new Element('body');
    this.documentElement.appendChild(this.head);
    this.documentElement.appendChild(this.body);
    this.appendChild(this.documentElement);
  }
  
  Document.prototype = Object.create(Node.prototype);
  Document.prototype.constructor = Document;
  Document.prototype.nodeConstructor = Node;
  
  Document.prototype.createElement = function(tagName) {
    return new Element(tagName);
  };
  
  Document.prototype.createTextNode = function(text) {
    return new Text(text);
  };
  
  Document.prototype.createComment = function(text) {
    return new Comment(text);
  };
  
  Document.prototype.createRawHTMLSection = function(text) {
    return new RawHTMLSection(text);
  };
  
  Document.prototype.createDocumentFragment = function() {
    return new DocumentFragment();
  };
  
  function HTMLParser(tokenize, document, voidMap) {
    this.tokenize = tokenize;
    this.document = document;
    this.voidMap = voidMap;
    this.parentStack = [];
  }
  
  HTMLParser.prototype.isVoid = function(element) {
    return this.voidMap[element.nodeName] === true;
  };
  
  HTMLParser.prototype.pushElement = function(token) {
    var el = this.document.createElement(token.tagName);
  
    for (var i=0;i<token.attributes.length;i++) {
      var attr = token.attributes[i];
      el.setAttribute(attr[0], attr[1]);
    }
  
    if (this.isVoid(el)) {
      return this.appendChild(el);
    }
  
    this.parentStack.push(el);
  };
  
  HTMLParser.prototype.popElement = function(token) {
    var el = this.parentStack.pop();
  
    if (el.nodeName !== token.tagName.toUpperCase()) {
      throw new Error('unbalanced tag');
    }
  
    this.appendChild(el);
  };
  
  HTMLParser.prototype.appendText = function(token) {
    var text = this.document.createTextNode(token.chars);
    this.appendChild(text);
  };
  
  HTMLParser.prototype.appendComment = function(token) {
    var comment = this.document.createComment(token.chars);
    this.appendChild(comment);
  };
  
  HTMLParser.prototype.appendChild = function(node) {
    var parentNode = this.parentStack[this.parentStack.length-1];
    parentNode.appendChild(node);
  };
  
  HTMLParser.prototype.parse = function(html/*, context*/) {
    // TODO use context for namespaceURI issues
    var fragment = this.document.createDocumentFragment();
    this.parentStack.push(fragment);
  
    var tokens = this.tokenize(html);
    for (var i=0, l=tokens.length; i<l; i++) {
      var token = tokens[i];
      switch (token.type) {
        case 'StartTag':
          this.pushElement(token);
          break;
        case 'EndTag':
          this.popElement(token);
          break;
        case 'Chars':
          this.appendText(token);
          break;
        case 'Comment':
          this.appendComment(token);
          break;
      }
    }
  
    return this.parentStack.pop();
  };
  
  var ESC = {
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    '&': '&amp;'
  };
  
  function matcher(char) {
    if (ESC[char] === undefined) {
      return char;
    }
  
    return ESC[char];
  }
  
  function HTMLSerializer(voidMap) {
    this.voidMap = voidMap;
  }
  
  HTMLSerializer.prototype.openTag = function(element) {
    return '<' + element.nodeName.toLowerCase() + this.attributes(element.attributes) + '>';
  };
  
  HTMLSerializer.prototype.closeTag = function(element) {
    return '</' + element.nodeName.toLowerCase() + '>';
  };
  
  HTMLSerializer.prototype.isVoid = function(element) {
    return this.voidMap[element.nodeName] === true;
  };
  
  HTMLSerializer.prototype.attributes = function(namedNodeMap) {
    var buffer = '';
    for (var i=0, l=namedNodeMap.length; i<l; i++) {
      buffer += this.attr(namedNodeMap[i]);
    }
    return buffer;
  };
  
  HTMLSerializer.prototype.escapeAttrValue = function(attrValue) {
    if (attrValue.indexOf('&') > -1 || attrValue.indexOf('"') > -1) {
      return attrValue.replace(/[&"]/g, matcher);
    }
  
    return attrValue;
  };
  
  HTMLSerializer.prototype.attr = function(attr) {
    if (!attr.specified) {
      return '';
    }
    if (attr.value) {
      return ' ' + attr.name + '="' + this.escapeAttrValue(attr.value) + '"';
    }
    return ' ' + attr.name;
  };
  
  HTMLSerializer.prototype.escapeText = function(textNodeValue) {
    if (textNodeValue.indexOf('>') > -1 ||
        textNodeValue.indexOf('<') > -1 ||
        textNodeValue.indexOf('&') > -1
    ) {
      return textNodeValue.replace(/[&<>]/g, matcher);
    }
  
    return textNodeValue;
  };
  
  HTMLSerializer.prototype.text = function(text) {
    return this.escapeText(text.nodeValue);
  };
  
  HTMLSerializer.prototype.rawHTMLSection = function(text) {
    return text.nodeValue;
  };
  
  HTMLSerializer.prototype.comment = function(comment) {
    return '<!--'+comment.nodeValue+'-->';
  };
  
  HTMLSerializer.prototype.serializeChildren = function(node) {
    var buffer = '';
    var next = node.firstChild;
    if (next) {
      buffer += this.serialize(next);
  
      while(next = next.nextSibling) {
        buffer += this.serialize(next);
      }
    }
    return buffer;
  };
  
  HTMLSerializer.prototype.serialize = function(node) {
    var buffer = '';
  
    // open
    switch (node.nodeType) {
      case 1:
        buffer += this.openTag(node);
        break;
      case 3:
        buffer += this.text(node);
        break;
      case -1:
        buffer += this.rawHTMLSection(node);
        break;
      case 8:
        buffer += this.comment(node);
        break;
      default:
        break;
    }
  
    buffer += this.serializeChildren(node);
  
    if (node.nodeType === 1 && !this.isVoid(node)) {
      buffer += this.closeTag(node);
    }
  
    return buffer;
  };
  
  var voidMap = {
    AREA: true,
    BASE: true,
    BR: true,
    COL: true,
    COMMAND: true,
    EMBED: true,
    HR: true,
    IMG: true,
    INPUT: true,
    KEYGEN: true,
    LINK: true,
    META: true,
    PARAM: true,
    SOURCE: true,
    TRACK: true,
    WBR: true
  };
  
  exports.Node = Node;
  exports.Element = Element;
  exports.DocumentFragment = DocumentFragment;
  exports.Document = Document;
  exports.HTMLParser = HTMLParser;
  exports.HTMLSerializer = HTMLSerializer;
  exports.voidMap = voidMap;
  
  Object.defineProperty(exports, '__esModule', { value: true });
  
  })));
  //# sourceMappingURL=simple-dom.js.map
  