[Pkg-javascript-commits] [sax.js] 01/08: New upstream version 1.2.4

Praveen Arimbrathodiyil praveen at moszumanska.debian.org
Mon Jan 15 18:12:27 UTC 2018


This is an automated email from the git hooks/post-receive script.

praveen pushed a commit to branch master
in repository sax.js.

commit ea2d4e8645e1b45df07a6804822efdb2c90cfb40
Author: Pirate Praveen <praveen at debian.org>
Date:   Mon Jan 15 23:12:59 2018 +0530

    New upstream version 1.2.4
---
 .gitignore                                 |    5 +
 .travis.yml                                |   12 +
 CONTRIBUTING.md                            |   14 +
 LICENSE                                    |   73 +-
 LICENSE-W3C.html                           |  188 --
 README.md                                  |   97 +-
 component.json                             |   12 -
 examples/example.js                        |   37 +-
 examples/get-products.js                   |   26 +-
 examples/hello-world.js                    |    4 +-
 examples/pretty-print.js                   |   54 +-
 examples/strict.dtd                        |  870 ---------
 lib/sax.js                                 | 2674 +++++++++++++++-------------
 package-lock.json                          | 2604 +++++++++++++++++++++++++++
 package.json                               |   21 +-
 test/attribute-name.js                     |   73 +-
 test/attribute-no-space.js                 |   71 +
 test/attribute-unquoted.js                 |   36 +
 test/bom.js                                |   47 +
 test/buffer-overrun.js                     |   42 +-
 test/case.js                               |  102 +-
 test/cdata-chunked.js                      |   17 +-
 test/cdata-end-split.js                    |   23 +-
 test/cdata-fake-end.js                     |   38 +-
 test/cdata-multiple.js                     |   25 +-
 test/cdata.js                              |   17 +-
 test/cyrillic.js                           |    5 +-
 test/duplicate-attribute.js                |   31 +-
 test/emoji.js                              |   12 +
 test/end_empty_stream.js                   |    5 +
 test/entities.js                           |    9 +-
 test/entity-mega.js                        |   11 +-
 test/entity-nan.js                         |    9 +
 test/flush.js                              |   14 +
 test/index.js                              |  105 +-
 test/issue-23.js                           |   89 +-
 test/issue-30.js                           |   45 +-
 test/issue-35.js                           |   25 +-
 test/issue-47.js                           |   21 +-
 test/issue-49.js                           |   59 +-
 test/issue-84.js                           |   24 +-
 test/issue-86.js                           |   85 +
 test/not-string.js                         |    8 +
 test/opentagstart.js                       |   86 +
 test/parser-position.js                    |   46 +-
 test/script-close-better.js                |   23 +-
 test/script.js                             |   74 +-
 test/self-closing-child-strict.js          |   97 +-
 test/self-closing-child.js                 |   97 +-
 test/self-closing-tag.js                   |   44 +-
 test/stand-alone-comment.js                |   12 +
 test/stray-ending.js                       |   64 +-
 test/trailing-attribute-no-value.js        |   15 +-
 test/trailing-non-whitespace.js            |   33 +-
 test/unclosed-root.js                      |   37 +-
 test/unquoted.js                           |   59 +-
 test/utf8-split.js                         |   24 +-
 test/xml-internal-entities.js              |   92 +
 test/xml_entities.js                       |   12 +
 test/xmlns-as-tag-name.js                  |   33 +
 test/xmlns-issue-41.js                     |  145 +-
 test/xmlns-rebinding.js                    |  390 +++-
 test/xmlns-strict.js                       |  408 ++++-
 test/xmlns-unbound-element.js              |  128 +-
 test/xmlns-unbound.js                      |   65 +-
 test/xmlns-xml-default-ns.js               |   98 +-
 test/xmlns-xml-default-prefix-attribute.js |   81 +-
 test/xmlns-xml-default-prefix.js           |   48 +-
 test/xmlns-xml-default-redefine.js         |   92 +-
 69 files changed, 6648 insertions(+), 3394 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8428194
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+.*.swp
+node_modules/*
+nyc_output/
+.nyc_output/
+coverage/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..12f7eeb
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+language: node_js
+sudo: false
+node_js:
+  - 8
+  - 6
+  - 4
+notifications:
+  email: false
+cache:
+  directories:
+    - $HOME/.npm
+    - node_modules
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..86b7311
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,14 @@
+**NO PATCHES WITHOUT A TEST**
+
+**TEST MUST PASS WITH THE PATCH.**
+
+**TEST MUST FAIL WITHOUT THE PATCH.**
+
+**NO EXCEPTIONS.**
+
+# EVERY PULL REQUEST MUST HAVE A TEST.
+
+Seriously.  This is a very strict rule, and I will not bend it for any
+patch, no matter how minor.
+
+Write a test.
diff --git a/LICENSE b/LICENSE
index 62e4ccf..ccffa08 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,32 +1,41 @@
-Copyright (c) Isaac Z. Schlueter ("Author")
-All rights reserved.
-
-The BSD License
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-The file "examples/strict.dtd" is licensed by the W3C and used according
-to the terms of the W3C SOFTWARE NOTICE AND LICENSE.  See LICENSE-W3C.html
-for details.
+The ISC License
+
+Copyright (c) Isaac Z. Schlueter and Contributors
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+====
+
+`String.fromCodePoint` by Mathias Bynens used according to terms of MIT
+License, as follows:
+
+    Copyright Mathias Bynens <https://mathiasbynens.be/>
+
+    Permission is hereby granted, free of charge, to any person obtaining
+    a copy of this software and associated documentation files (the
+    "Software"), to deal in the Software without restriction, including
+    without limitation the rights to use, copy, modify, merge, publish,
+    distribute, sublicense, and/or sell copies of the Software, and to
+    permit persons to whom the Software is furnished to do so, subject to
+    the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+    LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+    OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/LICENSE-W3C.html b/LICENSE-W3C.html
deleted file mode 100644
index a611e3f..0000000
--- a/LICENSE-W3C.html
+++ /dev/null
@@ -1,188 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><meta name="generator" content="HTML Tidy for Mac OS X (vers 31 October 2006 - Apple Inc. build 13), see www.w3.org" /><title>W3C Software Notice and License</title><link rel="stylesheet" href="/2008/site/css/minimum" type="text/css" media="handheld, all" /><style type="text/css" media="print, screen and (min-width: 481px)" xml:space="preserve">
-     @import url("/2008/site/css/advanced");
-</style><link href="/2008/site/css/minimum" rel="stylesheet" type="text/css" media="handheld, only screen and (max-device-width: 480px)" /><meta name="viewport" content="width=device-width" /><link rel="stylesheet" href="/2008/site/css/print" type="text/css" media="print" /><link rel="shortcut icon" href="/2008/site/images/favicon.ico" type="image/x-icon" /></head><body id="www-w3-org" class="w3c_public"><div id="w3c_container">
-    
-    
-
-         <div id="w3c_mast">
-            <h1 class="logo">
-               <a tabindex="2" accesskey="1" href="/"><img src="/2008/site/images/logo-w3c-mobile-lg" width="90" height="53" alt="W3C" /></a>
-               <span class="alt-logo">W3C</span>
-            </h1>
-
-            <div id="w3c_nav">
-               
-               
-
-               <form action="/Help/search" method="get" enctype="application/x-www-form-urlencoded"><div class="w3c_sec_nav"><!-- --></div><ul class="main_nav"><li class="first-item">
-                        <a href="/standards/">Standards</a>
-                     </li><li>
-                        <a href="/participate/">Participate</a>
-                     </li><li>
-                        <a href="/Consortium/membership">Membership</a>
-                     </li><li class="last-item">
-                        <a href="/Consortium/">About W3C</a>
-                     </li><li class="search-item">
-                        <div id="search-form">
-                           <input tabindex="3" class="text" name="q" value="" title="Search" type="text" />
-                           <button id="search-submit" name="search-submit" type="submit"><img class="submit" src="/2008/site/images/search-button" alt="Search" width="21" height="17" /></button>
-                        </div>
-                     </li></ul></form>
-            </div>
-            
-         </div>
-         
-
-         <div id="w3c_main">
-            <div id="w3c_logo_shadow" class="w3c_leftCol">
-               <img height="32" alt="" src="/2008/site/images/logo-shadow" />
-            </div>
-            
-            <div class="w3c_leftCol"><h2 class="offscreen">Site Navigation</h2>
-    <h3 class="category"><span class="ribbon"><a href="/Consortium/Legal/ipr-notice.html" title="Up to Policies and Legal Information">Policies and Legal Information <img src="/2008/site/images/header-link" alt="Header link" width="13" height="13" class="header-link" /></a></span></h3>
-       <ul class="theme">
-        <li><a href="/Consortium/Legal/2008/04-testsuite-copyright.html">Licenses for W3C Test Suites</a></li>
-        <li><a href="/2004/10/27-testcases.html">Policies for Contribution of Test Cases to W3C</a></li>
-        <li><a href="/Consortium/Legal/IPR-FAQ-20000620.html">Intellectual Rights FAQ</a></li>
-        <li><a href="/Consortium/Legal/privacy-statement-20000612.html">W3C Privacy Statements</a></li>
-        <li><a href="/Consortium/Legal/2002/copyright-documents-20021231.html">W3C Document License</a></li>
-        <li><a href="/Consortium/Legal/2002/trademarks-20021231.html">W3C Trademarks and Generic Terms</a></li>
-        <li><a href="/Consortium/Legal/2002/trademark-license-20021231.html">W3C&#xAE; Trademark and Service Mark License</a></li>
-        <li><a class="current">W3C Software Notice and License</a></li>
-        <li><a href="/Consortium/Legal/2002/collaborators-agreement-20021231.html">W3C Invited Expert and Collaborators Agreement</a></li>
-        <li><a href="/Consortium/Persistence.html">W3C URI Persistence Policy</a></li>
-        <li><a href="/1999/10/21-mirroring-policy.html">Mirroring the W3C Site</a></li>
-        <li><a href="/Consortium/Legal/2006/08-copyright-translations.html">Translations of the Copyright Notice</a></li>
-       </ul>
-       <br /></div>
-            <div class="w3c_mainCol">
-               <div id="w3c_crumbs">
-       <div id="w3c_crumbs_frame">
-        <ul class="bct"> <!-- .bct / Breadcrumbs -->
-          <li class="skip"><a tabindex="1" accesskey="2" title="Skip to content (e.g., when browsing via audio)" href="#w3c_content_body">Skip</a></li>
-          <li><a href="/">W3C</a>&#xA0;<span class="cr">&#xBB;</span>&#xA0;</li>
-          <li><a href="/Consortium/">About&#xA0;W3C</a>&#xA0;<span class="cr">&#xBB;</span>&#xA0;</li>
-          <li><a href="/Consortium/facts.html">Facts&#xA0;About&#xA0;W3C</a>&#xA0;<span class="cr">&#xBB;</span>&#xA0;</li>
-          <li><a href="/Consortium/Legal/ipr-notice.html">Policies&#xA0;and&#xA0;Legal&#xA0;Information</a>&#xA0;<span class="cr">&#xBB;</span>&#xA0;</li>
-          <li class="current">W3C Software Notice and License</li>
-        </ul>            
-     </div>
-    </div>
-               <h1 class="title">W3C Software Notice and License</h1>
-               <div id="w3c_content_body">
-                  <div class="line">
-                     <p class="intro tPadding">This work (and included software, documentation such as READMEs, or other
-related items) is being provided by the copyright holders under the following
-license.</p>
-<h2>License</h2>
-                     
-                     <p class="tPadding">
-By obtaining, using and/or copying this work, you (the licensee)
-agree that you have read, understood, and will comply with the following
-terms and conditions.</p>
-
-                     <p>Permission to copy, modify, and distribute this software and its
-documentation, with or without modification,&#xA0;for any purpose and without
-fee or royalty is hereby granted, provided that you include the following on
-ALL copies of the software and documentation or portions thereof, including
-modifications:</p>
-
-                     <ul class="show_items"><li>The full text of this NOTICE in a location viewable to users of the
-    redistributed or derivative work.</li><li>Any pre-existing intellectual property disclaimers, notices, or terms
-    and conditions. If none exist, the <a href="copyright-software-short-notice-20021231.html">W3C Software Short
-    Notice</a> should be included (hypertext is preferred, text is permitted)
-    within the body of any redistributed or derivative code.</li><li>Notice of any changes or modifications to the files, including the date
-    changes were made. (We recommend you provide URIs to the location from
-    which the code is derived.)</li></ul>
-
-<h2>Disclaimers</h2>
-
-                     <p>THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS
-MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
-LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
-PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE
-ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.</p>
-
-                     <p>COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
-DOCUMENTATION.</p>
-
-                     <p>The name and trademarks of copyright holders may NOT be used in
-advertising or publicity pertaining to the software without specific, written
-prior permission. Title to copyright in this software and any associated
-documentation will at all times remain with copyright holders.</p>
-
-                     <h2>Notes</h2>
-
-	                    <p>This version: http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231</p>
-
-                     <p>This formulation of W3C's notice and license became active on December 31
-2002. This version removes the copyright ownership notice such that this
-license can be used with materials other than those owned by the W3C,
-reflects that ERCIM is now a host of the W3C, includes references to this
-specific dated version of the license, and removes the ambiguous grant of
-"use". Otherwise, this version is the same as the <a href="http://www.w3.org/Consortium/Legal/copyright-software-19980720">previous
-version</a> and is written so as to preserve the <a href="http://www.gnu.org/philosophy/license-list.html#GPLCompatibleLicenses">Free
-Software Foundation's assessment of GPL compatibility</a> and <a href="http://www.opensource.org/licenses/W3C.php">OSI's certification</a>
-under the <a href="http://www.opensource.org/docs/definition.php">Open Source
-Definition</a>.</p>
-                  </div>
-               </div>
-            </div>
-         </div>
-         
-         
-         
-      </div><div id="w3c_footer">
-         <div id="w3c_footer-inner">
-            <h2 class="offscreen">Footer Navigation</h2>
-            <div class="w3c_footer-nav">
-               <h3>Navigation</h3>
-               <ul class="footer_top_nav"><li>
-                     <a href="/">Home</a>
-                  </li><li>
-                     <a href="/standards/">Standards</a>
-                  </li><li>
-                     <a href="/participate/">Participate</a>
-                  </li><li>
-                     <a href="/Consortium/membership">Membership</a>
-                  </li><li class="last-item">
-                     <a href="/Consortium/">About W3C</a>
-                  </li></ul>
-            </div>
-            <div class="w3c_footer-nav">
-               <h3>Contact W3C</h3>
-               <ul class="footer_bottom_nav"><li>
-                     <a href="/Consortium/contact">Contact</a>
-                  </li><li>
-                     <a accesskey="0" href="/Help/">Help and FAQ</a>
-                  </li><li>
-                     <a href="/Consortium/sponsor/">Sponsor / Donate</a>
-                  </li><li>
-                     <a href="/Consortium/siteindex">Site Map</a>
-                  </li><li>
-                     <address id="w3c_signature">
-                        <a href="http://lists.w3.org/Archives/Public/site-comments/">Feedback</a></address>
-                  </li></ul>
-            </div>
-            <div class="w3c_footer-nav">
-               <h3>W3C Updates</h3>
-               <ul class="footer_follow_nav"><li>
-                     <a href="http://twitter.com/W3C" title="Follow W3C on Twitter">
-                        <img src="/2008/site/images/twitter-bird" alt="Twitter" width="78" height="83" class="social-icon" />
-                     </a>
-                     <a href="http://identi.ca/w3c" title="See W3C on Identica">
-                        <img src="/2008/site/images/identica-logo" alt="Identica" width="91" height="83" class="social-icon" />
-                     </a>
-                  </li></ul>
-            </div>
-            <p class="copyright">Copyright &#xA9; 2012 W3C <sup>&#xAE;</sup> (<a href="http://www.csail.mit.edu/">
-                  <acronym title="Massachusetts Institute of Technology">MIT</acronym>
-               </a>, <a href="http://www.ercim.org/">
-                  <acronym title="European Research Consortium for Informatics and Mathematics"> ERCIM</acronym>
-               </a>, <a href="http://www.keio.ac.jp/">Keio</a>) <a href="/Consortium/Legal/ipr-notice">Usage policies apply</a>.</p>
-         </div>
-      </div><!-- Generated from data/scripts.php, ../../smarty/{scripts.tpl} --><!-- At the bottom for performance reasons --><div id="w3c_scripts">
-         <script type="text/javascript" src="/2008/site/js/main" xml:space="preserve"><!-- --></script>
-      </div></body></html>
diff --git a/README.md b/README.md
index c965242..afcd3f3 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ the browser or other CommonJS implementations.
 
 * A very simple tool to parse through an XML string.
 * A stepping stone to a streaming HTML parser.
-* A handy way to deal with RSS and other mostly-ok-but-kinda-broken XML 
+* A handy way to deal with RSS and other mostly-ok-but-kinda-broken XML
   docs.
 
 ## What This Is (probably) Not
@@ -23,7 +23,7 @@ the browser or other CommonJS implementations.
   implementations are in Java and do a lot more than this does.
 * An XML Validator - It does a little validation when in strict mode, but
   not much.
-* A Schema-Aware XSD Thing - Schemas are an exercise in fetishistic 
+* A Schema-Aware XSD Thing - Schemas are an exercise in fetishistic
   masochism.
 * A DTD-aware Thing - Fetching DTDs is a much bigger job.
 
@@ -41,48 +41,49 @@ through unmolested.
 
 ## Usage
 
-    var sax = require("./lib/sax"),
-      strict = true, // set to false for html-mode
-      parser = sax.parser(strict);
-
-    parser.onerror = function (e) {
-      // an error happened.
-    };
-    parser.ontext = function (t) {
-      // got some text.  t is the string of text.
-    };
-    parser.onopentag = function (node) {
-      // opened a tag.  node has "name" and "attributes"
-    };
-    parser.onattribute = function (attr) {
-      // an attribute.  attr has "name" and "value"
-    };
-    parser.onend = function () {
-      // parser stream is done, and ready to have more stuff written to it.
-    };
-
-    parser.write('<xml>Hello, <who name="world">world</who>!</xml>').close();
-
-    // stream usage
-    // takes the same options as the parser
-    var saxStream = require("sax").createStream(strict, options)
-    saxStream.on("error", function (e) {
-      // unhandled errors will throw, since this is a proper node
-      // event emitter.
-      console.error("error!", e)
-      // clear the error
-      this._parser.error = null
-      this._parser.resume()
-    })
-    saxStream.on("opentag", function (node) {
-      // same object as above
-    })
-    // pipe is supported, and it's readable/writable
-    // same chunks coming in also go out.
-    fs.createReadStream("file.xml")
-      .pipe(saxStream)
-      .pipe(fs.createWriteStream("file-copy.xml"))
-
+```javascript
+var sax = require("./lib/sax"),
+  strict = true, // set to false for html-mode
+  parser = sax.parser(strict);
+
+parser.onerror = function (e) {
+  // an error happened.
+};
+parser.ontext = function (t) {
+  // got some text.  t is the string of text.
+};
+parser.onopentag = function (node) {
+  // opened a tag.  node has "name" and "attributes"
+};
+parser.onattribute = function (attr) {
+  // an attribute.  attr has "name" and "value"
+};
+parser.onend = function () {
+  // parser stream is done, and ready to have more stuff written to it.
+};
+
+parser.write('<xml>Hello, <who name="world">world</who>!</xml>').close();
+
+// stream usage
+// takes the same options as the parser
+var saxStream = require("sax").createStream(strict, options)
+saxStream.on("error", function (e) {
+  // unhandled errors will throw, since this is a proper node
+  // event emitter.
+  console.error("error!", e)
+  // clear the error
+  this._parser.error = null
+  this._parser.resume()
+})
+saxStream.on("opentag", function (node) {
+  // same object as above
+})
+// pipe is supported, and it's readable/writable
+// same chunks coming in also go out.
+fs.createReadStream("file.xml")
+  .pipe(saxStream)
+  .pipe(fs.createWriteStream("file-copy.xml"))
+```
 
 
 ## Arguments
@@ -102,6 +103,9 @@ Settings supported:
   in loose mode, rather than uppercasing them.
 * `xmlns` - Boolean. If true, then namespaces are supported.
 * `position` - Boolean. If false, then don't track line/col/position.
+* `strictEntities` - Boolean. If true, only parse [predefined XML
+  entities](http://www.w3.org/TR/REC-xml/#sec-predefined-ent)
+  (`&`, `'`, `>`, `<`, and `"`)
 
 ## Methods
 
@@ -164,6 +168,11 @@ would trigger this kind of event. This is a weird thing to support, so it
 might go away at some point. SAX isn't intended to be used to parse SGML,
 after all.
 
+`opentagstart` - Emitted immediately when the tag name is available,
+but before any attributes are encountered.  Argument: object with a
+`name` field and an empty `attributes` set.  Note that this is the
+same object that will later be emitted in the `opentag` event.
+
 `opentag` - An opening tag. Argument: object with `name` and `attributes`.
 In non-strict mode, tag names are uppercased, unless the `lowercase`
 option is set.  If the `xmlns` option is set, then it will contain
diff --git a/component.json b/component.json
deleted file mode 100644
index 96b5d73..0000000
--- a/component.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "name": "sax",
-  "description": "An evented streaming XML parser in JavaScript",
-  "author": "Isaac Z. Schlueter <i at izs.me> (http://blog.izs.me/)",
-  "version": "0.5.2",
-  "main": "lib/sax.js",
-  "license": "BSD",
-  "scripts": [
-    "lib/sax.js"
-  ],
-  "repository": "git://github.com/isaacs/sax-js.git"
-}
diff --git a/examples/example.js b/examples/example.js
index 7b0246e..152ba44 100644
--- a/examples/example.js
+++ b/examples/example.js
@@ -1,29 +1,28 @@
-
-var fs = require("fs"),
-  util = require("util"),
-  path = require("path"),
-  xml = fs.readFileSync(path.join(__dirname, "test.xml"), "utf8"),
-  sax = require("../lib/sax"),
+var fs = require('fs'),
+  util = require('util'),
+  path = require('path'),
+  xml = fs.readFileSync(path.join(__dirname, 'test.xml'), 'utf8'),
+  sax = require('../lib/sax'),
   strict = sax.parser(true),
-  loose = sax.parser(false, {trim:true}),
+  loose = sax.parser(false, {trim: true}),
   inspector = function (ev) { return function (data) {
-    console.error("%s %s %j", this.line+":"+this.column, ev, data);
-  }};
+      console.error('%s %s %j', this.line + ':' + this.column, ev, data)
+    }}
 
 sax.EVENTS.forEach(function (ev) {
-  loose["on"+ev] = inspector(ev);
-});
+  loose['on' + ev] = inspector(ev)
+})
 loose.onend = function () {
-  console.error("end");
-  console.error(loose);
-};
+  console.error('end')
+  console.error(loose)
+}
 
 // do this in random bits at a time to verify that it works.
 (function () {
   if (xml) {
     var c = Math.ceil(Math.random() * 1000)
-    loose.write(xml.substr(0,c));
-    xml = xml.substr(c);
-    process.nextTick(arguments.callee);
-  } else loose.close();
-})();
+    loose.write(xml.substr(0, c))
+    xml = xml.substr(c)
+    process.nextTick(arguments.callee)
+  } else loose.close()
+})()
diff --git a/examples/get-products.js b/examples/get-products.js
index 9e8d74a..897c4c6 100644
--- a/examples/get-products.js
+++ b/examples/get-products.js
@@ -1,17 +1,17 @@
 // pull out /GeneralSearchResponse/categories/category/items/product tags
 // the rest we don't care about.
 
-var sax = require("../lib/sax.js")
-var fs = require("fs")
-var path = require("path")
-var xmlFile = path.resolve(__dirname, "shopping.xml")
-var util = require("util")
-var http = require("http")
+var sax = require('../lib/sax.js')
+var fs = require('fs')
+var path = require('path')
+var xmlFile = path.resolve(__dirname, 'shopping.xml')
+var util = require('util')
+var http = require('http')
 
 fs.readFile(xmlFile, function (er, d) {
   http.createServer(function (req, res) {
     if (er) throw er
-    var xmlstr = d.toString("utf8")
+    var xmlstr = d.toString('utf8')
 
     var parser = sax.parser(true)
     var products = []
@@ -19,7 +19,7 @@ fs.readFile(xmlFile, function (er, d) {
     var currentTag = null
 
     parser.onclosetag = function (tagName) {
-      if (tagName === "product") {
+      if (tagName === 'product') {
         products.push(product)
         currentTag = product = null
         return
@@ -32,8 +32,8 @@ fs.readFile(xmlFile, function (er, d) {
     }
 
     parser.onopentag = function (tag) {
-      if (tag.name !== "product" && !product) return
-      if (tag.name === "product") {
+      if (tag.name !== 'product' && !product) return
+      if (tag.name === 'product') {
         product = tag
       }
       tag.parent = currentTag
@@ -48,9 +48,9 @@ fs.readFile(xmlFile, function (er, d) {
 
     parser.onend = function () {
       var out = util.inspect(products, false, 3, true)
-      res.writeHead(200, {"content-type":"application/json"})
-      res.end("{\"ok\":true}")
-      // res.end(JSON.stringify(products))
+      res.writeHead(200, {'content-type': 'application/json'})
+      res.end('{"ok":true}')
+    // res.end(JSON.stringify(products))
     }
 
     parser.write(xmlstr).end()
diff --git a/examples/hello-world.js b/examples/hello-world.js
index cbfa518..612e057 100644
--- a/examples/hello-world.js
+++ b/examples/hello-world.js
@@ -1,4 +1,4 @@
-require("http").createServer(function (req, res) {
-  res.writeHead(200, {"content-type":"application/json"})
+require('http').createServer(function (req, res) {
+  res.writeHead(200, {'content-type': 'application/json'})
   res.end(JSON.stringify({ok: true}))
 }).listen(1337)
diff --git a/examples/pretty-print.js b/examples/pretty-print.js
index cd6aca9..c2f20fd 100644
--- a/examples/pretty-print.js
+++ b/examples/pretty-print.js
@@ -1,6 +1,6 @@
-var sax = require("../lib/sax")
-  , printer = sax.createStream(false, {lowercasetags:true, trim:true})
-  , fs = require("fs")
+var sax = require('../lib/sax'),
+  printer = sax.createStream(false, {lowercasetags: true, trim: true}),
+  fs = require('fs')
 
 function entity (str) {
   return str.replace('"', '"')
@@ -9,57 +9,57 @@ function entity (str) {
 printer.tabstop = 2
 printer.level = 0
 printer.indent = function () {
-  print("\n")
-  for (var i = this.level; i > 0; i --) {
-    for (var j = this.tabstop; j > 0; j --) {
-      print(" ")
+  print('\n')
+  for (var i = this.level; i > 0; i--) {
+    for (var j = this.tabstop; j > 0; j--) {
+      print(' ')
     }
   }
 }
-printer.on("opentag", function (tag) {
+printer.on('opentag', function (tag) {
   this.indent()
-  this.level ++
-  print("<"+tag.name)
+  this.level++
+  print('<' + tag.name)
   for (var i in tag.attributes) {
-    print(" "+i+"=\""+entity(tag.attributes[i])+"\"")
+    print(' ' + i + '="' + entity(tag.attributes[i]) + '"')
   }
-  print(">")
+  print('>')
 })
 
-printer.on("text", ontext)
-printer.on("doctype", ontext)
+printer.on('text', ontext)
+printer.on('doctype', ontext)
 function ontext (text) {
   this.indent()
   print(text)
 }
 
-printer.on("closetag", function (tag) {
-  this.level --
+printer.on('closetag', function (tag) {
+  this.level--
   this.indent()
-  print("</"+tag+">")
+  print('</' + tag + '>')
 })
 
-printer.on("cdata", function (data) {
+printer.on('cdata', function (data) {
   this.indent()
-  print("<![CDATA["+data+"]]>")
+  print('<![CDATA[' + data + ']]>')
 })
 
-printer.on("comment", function (comment) {
+printer.on('comment', function (comment) {
   this.indent()
-  print("<!--"+comment+"-->")
+  print('<!--' + comment + '-->')
 })
 
-printer.on("error", function (error) {
+printer.on('error', function (error) {
   console.error(error)
   throw error
 })
 
 if (!process.argv[2]) {
-  throw new Error("Please provide an xml file to prettify\n"+
-    "TODO: read from stdin or take a file")
+  throw new Error('Please provide an xml file to prettify\n' +
+    'TODO: read from stdin or take a file')
 }
-var xmlfile = require("path").join(process.cwd(), process.argv[2])
-var fstr = fs.createReadStream(xmlfile, { encoding: "utf8" })
+var xmlfile = require('path').join(process.cwd(), process.argv[2])
+var fstr = fs.createReadStream(xmlfile, { encoding: 'utf8' })
 
 function print (c) {
   if (!process.stdout.write(c)) {
@@ -67,7 +67,7 @@ function print (c) {
   }
 }
 
-process.stdout.on("drain", function () {
+process.stdout.on('drain', function () {
   fstr.resume()
 })
 
diff --git a/examples/strict.dtd b/examples/strict.dtd
deleted file mode 100644
index b274559..0000000
--- a/examples/strict.dtd
+++ /dev/null
@@ -1,870 +0,0 @@
-<!--
-    This is HTML 4.01 Strict DTD, which excludes the presentation 
-    attributes and elements that W3C expects to phase out as 
-    support for style sheets matures. Authors should use the Strict
-    DTD when possible, but may use the Transitional DTD when support
-    for presentation attribute and elements is required.
-    
-    HTML 4 includes mechanisms for style sheets, scripting,
-    embedding objects, improved support for right to left and mixed
-    direction text, and enhancements to forms for improved
-    accessibility for people with disabilities.
-
-          Draft: $Date: 1999/12/24 23:37:48 $
-
-          Authors:
-              Dave Raggett <dsr at w3.org>
-              Arnaud Le Hors <lehors at w3.org>
-              Ian Jacobs <ij at w3.org>
-
-    Further information about HTML 4.01 is available at:
-
-        http://www.w3.org/TR/1999/REC-html401-19991224
-
-
-    The HTML 4.01 specification includes additional
-    syntactic constraints that cannot be expressed within
-    the DTDs.
-
--->
-<!--
-    Typical usage:
-
-    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
-            "http://www.w3.org/TR/html4/strict.dtd">
-    <html>
-    <head>
-    ...
-    </head>
-    <body>
-    ...
-    </body>
-    </html>
-
-    The URI used as a system identifier with the public identifier allows
-    the user agent to download the DTD and entity sets as needed.
-
-    The FPI for the Transitional HTML 4.01 DTD is:
-
-        "-//W3C//DTD HTML 4.01 Transitional//EN"
-
-    This version of the transitional DTD is:
-
-        http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd
-
-    If you are writing a document that includes frames, use 
-    the following FPI:
-
-        "-//W3C//DTD HTML 4.01 Frameset//EN"
-
-    This version of the frameset DTD is:
-
-        http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd
-
-    Use the following (relative) URIs to refer to 
-    the DTDs and entity definitions of this specification:
-
-    "strict.dtd"
-    "loose.dtd"
-    "frameset.dtd"
-    "HTMLlat1.ent"
-    "HTMLsymbol.ent"
-    "HTMLspecial.ent"
-
--->
-
-<!--================== Imported Names ====================================-->
-<!-- Feature Switch for frameset documents -->
-<!ENTITY % HTML.Frameset "IGNORE">
-
-<!ENTITY % ContentType "CDATA"
-    -- media type, as per [RFC2045]
-    -->
-
-<!ENTITY % ContentTypes "CDATA"
-    -- comma-separated list of media types, as per [RFC2045]
-    -->
-
-<!ENTITY % Charset "CDATA"
-    -- a character encoding, as per [RFC2045]
-    -->
-
-<!ENTITY % Charsets "CDATA"
-    -- a space-separated list of character encodings, as per [RFC2045]
-    -->
-
-<!ENTITY % LanguageCode "NAME"
-    -- a language code, as per [RFC1766]
-    -->
-
-<!ENTITY % Character "CDATA"
-    -- a single character from [ISO10646] 
-    -->
-
-<!ENTITY % LinkTypes "CDATA"
-    -- space-separated list of link types
-    -->
-
-<!ENTITY % MediaDesc "CDATA"
-    -- single or comma-separated list of media descriptors
-    -->
-
-<!ENTITY % URI "CDATA"
-    -- a Uniform Resource Identifier,
-       see [URI]
-    -->
-
-<!ENTITY % Datetime "CDATA" -- date and time information. ISO date format -->
-
-
-<!ENTITY % Script "CDATA" -- script expression -->
-
-<!ENTITY % StyleSheet "CDATA" -- style sheet data -->
-
-
-
-<!ENTITY % Text "CDATA">
-
-
-<!-- Parameter Entities -->
-
-<!ENTITY % head.misc "SCRIPT|STYLE|META|LINK|OBJECT" -- repeatable head elements -->
-
-<!ENTITY % heading "H1|H2|H3|H4|H5|H6">
-
-<!ENTITY % list "UL | OL">
-
-<!ENTITY % preformatted "PRE">
-
-
-<!--================ Character mnemonic entities =========================-->
-
-<!ENTITY % HTMLlat1 PUBLIC
-   "-//W3C//ENTITIES Latin1//EN//HTML"
-   "HTMLlat1.ent">
-%HTMLlat1;
-
-<!ENTITY % HTMLsymbol PUBLIC
-   "-//W3C//ENTITIES Symbols//EN//HTML"
-   "HTMLsymbol.ent">
-%HTMLsymbol;
-
-<!ENTITY % HTMLspecial PUBLIC
-   "-//W3C//ENTITIES Special//EN//HTML"
-   "HTMLspecial.ent">
-%HTMLspecial;
-<!--=================== Generic Attributes ===============================-->
-
-<!ENTITY % coreattrs
- "id          ID             #IMPLIED  -- document-wide unique id --
-  class       CDATA          #IMPLIED  -- space-separated list of classes --
-  style       %StyleSheet;   #IMPLIED  -- associated style info --
-  title       %Text;         #IMPLIED  -- advisory title --"
-  >
-
-<!ENTITY % i18n
- "lang        %LanguageCode; #IMPLIED  -- language code --
-  dir         (ltr|rtl)      #IMPLIED  -- direction for weak/neutral text --"
-  >
-
-<!ENTITY % events
- "onclick     %Script;       #IMPLIED  -- a pointer button was clicked --
-  ondblclick  %Script;       #IMPLIED  -- a pointer button was double clicked--
-  onmousedown %Script;       #IMPLIED  -- a pointer button was pressed down --
-  onmouseup   %Script;       #IMPLIED  -- a pointer button was released --
-  onmouseover %Script;       #IMPLIED  -- a pointer was moved onto --
-  onmousemove %Script;       #IMPLIED  -- a pointer was moved within --
-  onmouseout  %Script;       #IMPLIED  -- a pointer was moved away --
-  onkeypress  %Script;       #IMPLIED  -- a key was pressed and released --
-  onkeydown   %Script;       #IMPLIED  -- a key was pressed down --
-  onkeyup     %Script;       #IMPLIED  -- a key was released --"
-  >
-
-<!-- Reserved Feature Switch -->
-<!ENTITY % HTML.Reserved "IGNORE">
-
-<!-- The following attributes are reserved for possible future use -->
-<![ %HTML.Reserved; [
-<!ENTITY % reserved
- "datasrc     %URI;          #IMPLIED  -- a single or tabular Data Source --
-  datafld     CDATA          #IMPLIED  -- the property or column name --
-  dataformatas (plaintext|html) plaintext -- text or html --"
-  >
-]]>
-
-<!ENTITY % reserved "">
-
-<!ENTITY % attrs "%coreattrs; %i18n; %events;">
-
-
-<!--=================== Text Markup ======================================-->
-
-<!ENTITY % fontstyle
- "TT | I | B | BIG | SMALL">
-
-<!ENTITY % phrase "EM | STRONG | DFN | CODE |
-                   SAMP | KBD | VAR | CITE | ABBR | ACRONYM" >
-
-<!ENTITY % special
-   "A | IMG | OBJECT | BR | SCRIPT | MAP | Q | SUB | SUP | SPAN | BDO">
-
-<!ENTITY % formctrl "INPUT | SELECT | TEXTAREA | LABEL | BUTTON">
-
-<!-- %inline; covers inline or "text-level" elements -->
-<!ENTITY % inline "#PCDATA | %fontstyle; | %phrase; | %special; | %formctrl;">
-
-<!ELEMENT (%fontstyle;|%phrase;) - - (%inline;)*>
-<!ATTLIST (%fontstyle;|%phrase;)
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!ELEMENT (SUB|SUP) - - (%inline;)*    -- subscript, superscript -->
-<!ATTLIST (SUB|SUP)
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!ELEMENT SPAN - - (%inline;)*         -- generic language/style container -->
-<!ATTLIST SPAN
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  %reserved;			       -- reserved for possible future use --
-  >
-
-<!ELEMENT BDO - - (%inline;)*          -- I18N BiDi over-ride -->
-<!ATTLIST BDO
-  %coreattrs;                          -- id, class, style, title --
-  lang        %LanguageCode; #IMPLIED  -- language code --
-  dir         (ltr|rtl)      #REQUIRED -- directionality --
-  >
-
-
-<!ELEMENT BR - O EMPTY                 -- forced line break -->
-<!ATTLIST BR
-  %coreattrs;                          -- id, class, style, title --
-  >
-
-<!--================== HTML content models ===============================-->
-
-<!--
-    HTML has two basic content models:
-
-        %inline;     character level elements and text strings
-        %block;      block-like elements e.g. paragraphs and lists
--->
-
-<!ENTITY % block
-     "P | %heading; | %list; | %preformatted; | DL | DIV | NOSCRIPT |
-      BLOCKQUOTE | FORM | HR | TABLE | FIELDSET | ADDRESS">
-
-<!ENTITY % flow "%block; | %inline;">
-
-<!--=================== Document Body ====================================-->
-
-<!ELEMENT BODY O O (%block;|SCRIPT)+ +(INS|DEL) -- document body -->
-<!ATTLIST BODY
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  onload          %Script;   #IMPLIED  -- the document has been loaded --
-  onunload        %Script;   #IMPLIED  -- the document has been removed --
-  >
-
-<!ELEMENT ADDRESS - - (%inline;)* -- information on author -->
-<!ATTLIST ADDRESS
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!ELEMENT DIV - - (%flow;)*            -- generic language/style container -->
-<!ATTLIST DIV
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  %reserved;                           -- reserved for possible future use --
-  >
-
-
-<!--================== The Anchor Element ================================-->
-
-<!ENTITY % Shape "(rect|circle|poly|default)">
-<!ENTITY % Coords "CDATA" -- comma-separated list of lengths -->
-
-<!ELEMENT A - - (%inline;)* -(A)       -- anchor -->
-<!ATTLIST A
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  charset     %Charset;      #IMPLIED  -- char encoding of linked resource --
-  type        %ContentType;  #IMPLIED  -- advisory content type --
-  name        CDATA          #IMPLIED  -- named link end --
-  href        %URI;          #IMPLIED  -- URI for linked resource --
-  hreflang    %LanguageCode; #IMPLIED  -- language code --
-  rel         %LinkTypes;    #IMPLIED  -- forward link types --
-  rev         %LinkTypes;    #IMPLIED  -- reverse link types --
-  accesskey   %Character;    #IMPLIED  -- accessibility key character --
-  shape       %Shape;        rect      -- for use with client-side image maps --
-  coords      %Coords;       #IMPLIED  -- for use with client-side image maps --
-  tabindex    NUMBER         #IMPLIED  -- position in tabbing order --
-  onfocus     %Script;       #IMPLIED  -- the element got the focus --
-  onblur      %Script;       #IMPLIED  -- the element lost the focus --
-  >
-
-<!--================== Client-side image maps ============================-->
-
-<!-- These can be placed in the same document or grouped in a
-     separate document although this isn't yet widely supported -->
-
-<!ELEMENT MAP - - ((%block;) | AREA)+ -- client-side image map -->
-<!ATTLIST MAP
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  name        CDATA          #REQUIRED -- for reference by usemap --
-  >
-
-<!ELEMENT AREA - O EMPTY               -- client-side image map area -->
-<!ATTLIST AREA
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  shape       %Shape;        rect      -- controls interpretation of coords --
-  coords      %Coords;       #IMPLIED  -- comma-separated list of lengths --
-  href        %URI;          #IMPLIED  -- URI for linked resource --
-  nohref      (nohref)       #IMPLIED  -- this region has no action --
-  alt         %Text;         #REQUIRED -- short description --
-  tabindex    NUMBER         #IMPLIED  -- position in tabbing order --
-  accesskey   %Character;    #IMPLIED  -- accessibility key character --
-  onfocus     %Script;       #IMPLIED  -- the element got the focus --
-  onblur      %Script;       #IMPLIED  -- the element lost the focus --
-  >
-
-<!--================== The LINK Element ==================================-->
-
-<!--
-  Relationship values can be used in principle:
-
-   a) for document specific toolbars/menus when used
-      with the LINK element in document head e.g.
-        start, contents, previous, next, index, end, help
-   b) to link to a separate style sheet (rel=stylesheet)
-   c) to make a link to a script (rel=script)
-   d) by stylesheets to control how collections of
-      html nodes are rendered into printed documents
-   e) to make a link to a printable version of this document
-      e.g. a postscript or pdf version (rel=alternate media=print)
--->
-
-<!ELEMENT LINK - O EMPTY               -- a media-independent link -->
-<!ATTLIST LINK
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  charset     %Charset;      #IMPLIED  -- char encoding of linked resource --
-  href        %URI;          #IMPLIED  -- URI for linked resource --
-  hreflang    %LanguageCode; #IMPLIED  -- language code --
-  type        %ContentType;  #IMPLIED  -- advisory content type --
-  rel         %LinkTypes;    #IMPLIED  -- forward link types --
-  rev         %LinkTypes;    #IMPLIED  -- reverse link types --
-  media       %MediaDesc;    #IMPLIED  -- for rendering on these media --
-  >
-
-<!--=================== Images ===========================================-->
-
-<!-- Length defined in strict DTD for cellpadding/cellspacing -->
-<!ENTITY % Length "CDATA" -- nn for pixels or nn% for percentage length -->
-<!ENTITY % MultiLength "CDATA" -- pixel, percentage, or relative -->
-
-<![ %HTML.Frameset; [
-<!ENTITY % MultiLengths "CDATA" -- comma-separated list of MultiLength -->
-]]>
-
-<!ENTITY % Pixels "CDATA" -- integer representing length in pixels -->
-
-
-<!-- To avoid problems with text-only UAs as well as 
-   to make image content understandable and navigable 
-   to users of non-visual UAs, you need to provide
-   a description with ALT, and avoid server-side image maps -->
-<!ELEMENT IMG - O EMPTY                -- Embedded image -->
-<!ATTLIST IMG
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  src         %URI;          #REQUIRED -- URI of image to embed --
-  alt         %Text;         #REQUIRED -- short description --
-  longdesc    %URI;          #IMPLIED  -- link to long description
-                                          (complements alt) --
-  name        CDATA          #IMPLIED  -- name of image for scripting --
-  height      %Length;       #IMPLIED  -- override height --
-  width       %Length;       #IMPLIED  -- override width --
-  usemap      %URI;          #IMPLIED  -- use client-side image map --
-  ismap       (ismap)        #IMPLIED  -- use server-side image map --
-  >
-
-<!-- USEMAP points to a MAP element which may be in this document
-  or an external document, although the latter is not widely supported -->
-
-<!--==================== OBJECT ======================================-->
-<!--
-  OBJECT is used to embed objects as part of HTML pages 
-  PARAM elements should precede other content. SGML mixed content
-  model technicality precludes specifying this formally ...
--->
-
-<!ELEMENT OBJECT - - (PARAM | %flow;)*
- -- generic embedded object -->
-<!ATTLIST OBJECT
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  declare     (declare)      #IMPLIED  -- declare but don't instantiate flag --
-  classid     %URI;          #IMPLIED  -- identifies an implementation --
-  codebase    %URI;          #IMPLIED  -- base URI for classid, data, archive--
-  data        %URI;          #IMPLIED  -- reference to object's data --
-  type        %ContentType;  #IMPLIED  -- content type for data --
-  codetype    %ContentType;  #IMPLIED  -- content type for code --
-  archive     CDATA          #IMPLIED  -- space-separated list of URIs --
-  standby     %Text;         #IMPLIED  -- message to show while loading --
-  height      %Length;       #IMPLIED  -- override height --
-  width       %Length;       #IMPLIED  -- override width --
-  usemap      %URI;          #IMPLIED  -- use client-side image map --
-  name        CDATA          #IMPLIED  -- submit as part of form --
-  tabindex    NUMBER         #IMPLIED  -- position in tabbing order --
-  %reserved;                           -- reserved for possible future use --
-  >
-
-<!ELEMENT PARAM - O EMPTY              -- named property value -->
-<!ATTLIST PARAM
-  id          ID             #IMPLIED  -- document-wide unique id --
-  name        CDATA          #REQUIRED -- property name --
-  value       CDATA          #IMPLIED  -- property value --
-  valuetype   (DATA|REF|OBJECT) DATA   -- How to interpret value --
-  type        %ContentType;  #IMPLIED  -- content type for value
-                                          when valuetype=ref --
-  >
-
-
-<!--=================== Horizontal Rule ==================================-->
-
-<!ELEMENT HR - O EMPTY -- horizontal rule -->
-<!ATTLIST HR
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!--=================== Paragraphs =======================================-->
-
-<!ELEMENT P - O (%inline;)*            -- paragraph -->
-<!ATTLIST P
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!--=================== Headings =========================================-->
-
-<!--
-  There are six levels of headings from H1 (the most important)
-  to H6 (the least important).
--->
-
-<!ELEMENT (%heading;)  - - (%inline;)* -- heading -->
-<!ATTLIST (%heading;)
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!--=================== Preformatted Text ================================-->
-
-<!-- excludes markup for images and changes in font size -->
-<!ENTITY % pre.exclusion "IMG|OBJECT|BIG|SMALL|SUB|SUP">
-
-<!ELEMENT PRE - - (%inline;)* -(%pre.exclusion;) -- preformatted text -->
-<!ATTLIST PRE
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!--===================== Inline Quotes ==================================-->
-
-<!ELEMENT Q - - (%inline;)*            -- short inline quotation -->
-<!ATTLIST Q
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  cite        %URI;          #IMPLIED  -- URI for source document or msg --
-  >
-
-<!--=================== Block-like Quotes ================================-->
-
-<!ELEMENT BLOCKQUOTE - - (%block;|SCRIPT)+ -- long quotation -->
-<!ATTLIST BLOCKQUOTE
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  cite        %URI;          #IMPLIED  -- URI for source document or msg --
-  >
-
-<!--=================== Inserted/Deleted Text ============================-->
-
-
-<!-- INS/DEL are handled by inclusion on BODY -->
-<!ELEMENT (INS|DEL) - - (%flow;)*      -- inserted text, deleted text -->
-<!ATTLIST (INS|DEL)
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  cite        %URI;          #IMPLIED  -- info on reason for change --
-  datetime    %Datetime;     #IMPLIED  -- date and time of change --
-  >
-
-<!--=================== Lists ============================================-->
-
-<!-- definition lists - DT for term, DD for its definition -->
-
-<!ELEMENT DL - - (DT|DD)+              -- definition list -->
-<!ATTLIST DL
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!ELEMENT DT - O (%inline;)*           -- definition term -->
-<!ELEMENT DD - O (%flow;)*             -- definition description -->
-<!ATTLIST (DT|DD)
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-
-<!ELEMENT OL - - (LI)+                 -- ordered list -->
-<!ATTLIST OL
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!-- Unordered Lists (UL) bullet styles -->
-<!ELEMENT UL - - (LI)+                 -- unordered list -->
-<!ATTLIST UL
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-
-
-<!ELEMENT LI - O (%flow;)*             -- list item -->
-<!ATTLIST LI
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!--================ Forms ===============================================-->
-<!ELEMENT FORM - - (%block;|SCRIPT)+ -(FORM) -- interactive form -->
-<!ATTLIST FORM
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  action      %URI;          #REQUIRED -- server-side form handler --
-  method      (GET|POST)     GET       -- HTTP method used to submit the form--
-  enctype     %ContentType;  "application/x-www-form-urlencoded"
-  accept      %ContentTypes; #IMPLIED  -- list of MIME types for file upload --
-  name        CDATA          #IMPLIED  -- name of form for scripting --
-  onsubmit    %Script;       #IMPLIED  -- the form was submitted --
-  onreset     %Script;       #IMPLIED  -- the form was reset --
-  accept-charset %Charsets;  #IMPLIED  -- list of supported charsets --
-  >
-
-<!-- Each label must not contain more than ONE field -->
-<!ELEMENT LABEL - - (%inline;)* -(LABEL) -- form field label text -->
-<!ATTLIST LABEL
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  for         IDREF          #IMPLIED  -- matches field ID value --
-  accesskey   %Character;    #IMPLIED  -- accessibility key character --
-  onfocus     %Script;       #IMPLIED  -- the element got the focus --
-  onblur      %Script;       #IMPLIED  -- the element lost the focus --
-  >
-
-<!ENTITY % InputType
-  "(TEXT | PASSWORD | CHECKBOX |
-    RADIO | SUBMIT | RESET |
-    FILE | HIDDEN | IMAGE | BUTTON)"
-   >
-
-<!-- attribute name required for all but submit and reset -->
-<!ELEMENT INPUT - O EMPTY              -- form control -->
-<!ATTLIST INPUT
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  type        %InputType;    TEXT      -- what kind of widget is needed --
-  name        CDATA          #IMPLIED  -- submit as part of form --
-  value       CDATA          #IMPLIED  -- Specify for radio buttons and checkboxes --
-  checked     (checked)      #IMPLIED  -- for radio buttons and check boxes --
-  disabled    (disabled)     #IMPLIED  -- unavailable in this context --
-  readonly    (readonly)     #IMPLIED  -- for text and passwd --
-  size        CDATA          #IMPLIED  -- specific to each type of field --
-  maxlength   NUMBER         #IMPLIED  -- max chars for text fields --
-  src         %URI;          #IMPLIED  -- for fields with images --
-  alt         CDATA          #IMPLIED  -- short description --
-  usemap      %URI;          #IMPLIED  -- use client-side image map --
-  ismap       (ismap)        #IMPLIED  -- use server-side image map --
-  tabindex    NUMBER         #IMPLIED  -- position in tabbing order --
-  accesskey   %Character;    #IMPLIED  -- accessibility key character --
-  onfocus     %Script;       #IMPLIED  -- the element got the focus --
-  onblur      %Script;       #IMPLIED  -- the element lost the focus --
-  onselect    %Script;       #IMPLIED  -- some text was selected --
-  onchange    %Script;       #IMPLIED  -- the element value was changed --
-  accept      %ContentTypes; #IMPLIED  -- list of MIME types for file upload --
-  %reserved;                           -- reserved for possible future use --
-  >
-
-<!ELEMENT SELECT - - (OPTGROUP|OPTION)+ -- option selector -->
-<!ATTLIST SELECT
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  name        CDATA          #IMPLIED  -- field name --
-  size        NUMBER         #IMPLIED  -- rows visible --
-  multiple    (multiple)     #IMPLIED  -- default is single selection --
-  disabled    (disabled)     #IMPLIED  -- unavailable in this context --
-  tabindex    NUMBER         #IMPLIED  -- position in tabbing order --
-  onfocus     %Script;       #IMPLIED  -- the element got the focus --
-  onblur      %Script;       #IMPLIED  -- the element lost the focus --
-  onchange    %Script;       #IMPLIED  -- the element value was changed --
-  %reserved;                           -- reserved for possible future use --
-  >
-
-<!ELEMENT OPTGROUP - - (OPTION)+ -- option group -->
-<!ATTLIST OPTGROUP
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  disabled    (disabled)     #IMPLIED  -- unavailable in this context --
-  label       %Text;         #REQUIRED -- for use in hierarchical menus --
-  >
-
-<!ELEMENT OPTION - O (#PCDATA)         -- selectable choice -->
-<!ATTLIST OPTION
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  selected    (selected)     #IMPLIED
-  disabled    (disabled)     #IMPLIED  -- unavailable in this context --
-  label       %Text;         #IMPLIED  -- for use in hierarchical menus --
-  value       CDATA          #IMPLIED  -- defaults to element content --
-  >
-
-<!ELEMENT TEXTAREA - - (#PCDATA)       -- multi-line text field -->
-<!ATTLIST TEXTAREA
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  name        CDATA          #IMPLIED
-  rows        NUMBER         #REQUIRED
-  cols        NUMBER         #REQUIRED
-  disabled    (disabled)     #IMPLIED  -- unavailable in this context --
-  readonly    (readonly)     #IMPLIED
-  tabindex    NUMBER         #IMPLIED  -- position in tabbing order --
-  accesskey   %Character;    #IMPLIED  -- accessibility key character --
-  onfocus     %Script;       #IMPLIED  -- the element got the focus --
-  onblur      %Script;       #IMPLIED  -- the element lost the focus --
-  onselect    %Script;       #IMPLIED  -- some text was selected --
-  onchange    %Script;       #IMPLIED  -- the element value was changed --
-  %reserved;                           -- reserved for possible future use --
-  >
-
-<!--
-  #PCDATA is to solve the mixed content problem,
-  per specification only whitespace is allowed there!
- -->
-<!ELEMENT FIELDSET - - (#PCDATA,LEGEND,(%flow;)*) -- form control group -->
-<!ATTLIST FIELDSET
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!ELEMENT LEGEND - - (%inline;)*       -- fieldset legend -->
-
-<!ATTLIST LEGEND
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  accesskey   %Character;    #IMPLIED  -- accessibility key character --
-  >
-
-<!ELEMENT BUTTON - -
-     (%flow;)* -(A|%formctrl;|FORM|FIELDSET)
-     -- push button -->
-<!ATTLIST BUTTON
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  name        CDATA          #IMPLIED
-  value       CDATA          #IMPLIED  -- sent to server when submitted --
-  type        (button|submit|reset) submit -- for use as form button --
-  disabled    (disabled)     #IMPLIED  -- unavailable in this context --
-  tabindex    NUMBER         #IMPLIED  -- position in tabbing order --
-  accesskey   %Character;    #IMPLIED  -- accessibility key character --
-  onfocus     %Script;       #IMPLIED  -- the element got the focus --
-  onblur      %Script;       #IMPLIED  -- the element lost the focus --
-  %reserved;                           -- reserved for possible future use --
-  >
-
-<!--======================= Tables =======================================-->
-
-<!-- IETF HTML table standard, see [RFC1942] -->
-
-<!--
- The BORDER attribute sets the thickness of the frame around the
- table. The default units are screen pixels.
-
- The FRAME attribute specifies which parts of the frame around
- the table should be rendered. The values are not the same as
- CALS to avoid a name clash with the VALIGN attribute.
-
- The value "border" is included for backwards compatibility with
- <TABLE BORDER> which yields frame=border and border=implied
- For <TABLE BORDER=1> you get border=1 and frame=implied. In this
- case, it is appropriate to treat this as frame=border for backwards
- compatibility with deployed browsers.
--->
-<!ENTITY % TFrame "(void|above|below|hsides|lhs|rhs|vsides|box|border)">
-
-<!--
- The RULES attribute defines which rules to draw between cells:
-
- If RULES is absent then assume:
-     "none" if BORDER is absent or BORDER=0 otherwise "all"
--->
-
-<!ENTITY % TRules "(none | groups | rows | cols | all)">
-  
-<!-- horizontal placement of table relative to document -->
-<!ENTITY % TAlign "(left|center|right)">
-
-<!-- horizontal alignment attributes for cell contents -->
-<!ENTITY % cellhalign
-  "align      (left|center|right|justify|char) #IMPLIED
-   char       %Character;    #IMPLIED  -- alignment char, e.g. char=':' --
-   charoff    %Length;       #IMPLIED  -- offset for alignment char --"
-  >
-
-<!-- vertical alignment attributes for cell contents -->
-<!ENTITY % cellvalign
-  "valign     (top|middle|bottom|baseline) #IMPLIED"
-  >
-
-<!ELEMENT TABLE - -
-     (CAPTION?, (COL*|COLGROUP*), THEAD?, TFOOT?, TBODY+)>
-<!ELEMENT CAPTION  - - (%inline;)*     -- table caption -->
-<!ELEMENT THEAD    - O (TR)+           -- table header -->
-<!ELEMENT TFOOT    - O (TR)+           -- table footer -->
-<!ELEMENT TBODY    O O (TR)+           -- table body -->
-<!ELEMENT COLGROUP - O (COL)*          -- table column group -->
-<!ELEMENT COL      - O EMPTY           -- table column -->
-<!ELEMENT TR       - O (TH|TD)+        -- table row -->
-<!ELEMENT (TH|TD)  - O (%flow;)*       -- table header cell, table data cell-->
-
-<!ATTLIST TABLE                        -- table element --
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  summary     %Text;         #IMPLIED  -- purpose/structure for speech output--
-  width       %Length;       #IMPLIED  -- table width --
-  border      %Pixels;       #IMPLIED  -- controls frame width around table --
-  frame       %TFrame;       #IMPLIED  -- which parts of frame to render --
-  rules       %TRules;       #IMPLIED  -- rulings between rows and cols --
-  cellspacing %Length;       #IMPLIED  -- spacing between cells --
-  cellpadding %Length;       #IMPLIED  -- spacing within cells --
-  %reserved;                           -- reserved for possible future use --
-  datapagesize CDATA         #IMPLIED  -- reserved for possible future use --
-  >
-
-
-<!ATTLIST CAPTION
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!--
-COLGROUP groups a set of COL elements. It allows you to group
-several semantically related columns together.
--->
-<!ATTLIST COLGROUP
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  span        NUMBER         1         -- default number of columns in group --
-  width       %MultiLength;  #IMPLIED  -- default width for enclosed COLs --
-  %cellhalign;                         -- horizontal alignment in cells --
-  %cellvalign;                         -- vertical alignment in cells --
-  >
-
-<!--
- COL elements define the alignment properties for cells in
- one or more columns.
-
- The WIDTH attribute specifies the width of the columns, e.g.
-
-     width=64        width in screen pixels
-     width=0.5*      relative width of 0.5
-
- The SPAN attribute causes the attributes of one
- COL element to apply to more than one column.
--->
-<!ATTLIST COL                          -- column groups and properties --
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  span        NUMBER         1         -- COL attributes affect N columns --
-  width       %MultiLength;  #IMPLIED  -- column width specification --
-  %cellhalign;                         -- horizontal alignment in cells --
-  %cellvalign;                         -- vertical alignment in cells --
-  >
-
-<!--
-    Use THEAD to duplicate headers when breaking table
-    across page boundaries, or for static headers when
-    TBODY sections are rendered in scrolling panel.
-
-    Use TFOOT to duplicate footers when breaking table
-    across page boundaries, or for static footers when
-    TBODY sections are rendered in scrolling panel.
-
-    Use multiple TBODY sections when rules are needed
-    between groups of table rows.
--->
-<!ATTLIST (THEAD|TBODY|TFOOT)          -- table section --
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  %cellhalign;                         -- horizontal alignment in cells --
-  %cellvalign;                         -- vertical alignment in cells --
-  >
-
-<!ATTLIST TR                           -- table row --
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  %cellhalign;                         -- horizontal alignment in cells --
-  %cellvalign;                         -- vertical alignment in cells --
-  >
-
-
-<!-- Scope is simpler than headers attribute for common tables -->
-<!ENTITY % Scope "(row|col|rowgroup|colgroup)">
-
-<!-- TH is for headers, TD for data, but for cells acting as both use TD -->
-<!ATTLIST (TH|TD)                      -- header or data cell --
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  abbr        %Text;         #IMPLIED  -- abbreviation for header cell --
-  axis        CDATA          #IMPLIED  -- comma-separated list of related headers--
-  headers     IDREFS         #IMPLIED  -- list of id's for header cells --
-  scope       %Scope;        #IMPLIED  -- scope covered by header cells --
-  rowspan     NUMBER         1         -- number of rows spanned by cell --
-  colspan     NUMBER         1         -- number of cols spanned by cell --
-  %cellhalign;                         -- horizontal alignment in cells --
-  %cellvalign;                         -- vertical alignment in cells --
-  >
-
-
-<!--================ Document Head =======================================-->
-<!-- %head.misc; defined earlier on as "SCRIPT|STYLE|META|LINK|OBJECT" -->
-<!ENTITY % head.content "TITLE & BASE?">
-
-<!ELEMENT HEAD O O (%head.content;) +(%head.misc;) -- document head -->
-<!ATTLIST HEAD
-  %i18n;                               -- lang, dir --
-  profile     %URI;          #IMPLIED  -- named dictionary of meta info --
-  >
-
-<!-- The TITLE element is not considered part of the flow of text.
-       It should be displayed, for example as the page header or
-       window title. Exactly one title is required per document.
-    -->
-<!ELEMENT TITLE - - (#PCDATA) -(%head.misc;) -- document title -->
-<!ATTLIST TITLE %i18n>
-
-
-<!ELEMENT BASE - O EMPTY               -- document base URI -->
-<!ATTLIST BASE
-  href        %URI;          #REQUIRED -- URI that acts as base URI --
-  >
-
-<!ELEMENT META - O EMPTY               -- generic metainformation -->
-<!ATTLIST META
-  %i18n;                               -- lang, dir, for use with content --
-  http-equiv  NAME           #IMPLIED  -- HTTP response header name  --
-  name        NAME           #IMPLIED  -- metainformation name --
-  content     CDATA          #REQUIRED -- associated information --
-  scheme      CDATA          #IMPLIED  -- select form of content --
-  >
-
-<!ELEMENT STYLE - - %StyleSheet        -- style info -->
-<!ATTLIST STYLE
-  %i18n;                               -- lang, dir, for use with title --
-  type        %ContentType;  #REQUIRED -- content type of style language --
-  media       %MediaDesc;    #IMPLIED  -- designed for use with these media --
-  title       %Text;         #IMPLIED  -- advisory title --
-  >
-
-<!ELEMENT SCRIPT - - %Script;          -- script statements -->
-<!ATTLIST SCRIPT
-  charset     %Charset;      #IMPLIED  -- char encoding of linked resource --
-  type        %ContentType;  #REQUIRED -- content type of script language --
-  src         %URI;          #IMPLIED  -- URI for an external script --
-  defer       (defer)        #IMPLIED  -- UA may defer execution of script --
-  event       CDATA          #IMPLIED  -- reserved for possible future use --
-  for         %URI;          #IMPLIED  -- reserved for possible future use --
-  >
-
-<!ELEMENT NOSCRIPT - - (%block;)+
-  -- alternate content container for non script-based rendering -->
-<!ATTLIST NOSCRIPT
-  %attrs;                              -- %coreattrs, %i18n, %events --
-  >
-
-<!--================ Document Structure ==================================-->
-<!ENTITY % html.content "HEAD, BODY">
-
-<!ELEMENT HTML O O (%html.content;)    -- document root element -->
-<!ATTLIST HTML
-  %i18n;                               -- lang, dir --
-  >
diff --git a/lib/sax.js b/lib/sax.js
index 77e20ae..795d607 100644
--- a/lib/sax.js
+++ b/lib/sax.js
@@ -1,1329 +1,1565 @@
-// wrapper for non-node envs
-;(function (sax) {
-
-sax.parser = function (strict, opt) { return new SAXParser(strict, opt) }
-sax.SAXParser = SAXParser
-sax.SAXStream = SAXStream
-sax.createStream = createStream
-
-// When we pass the MAX_BUFFER_LENGTH position, start checking for buffer overruns.
-// When we check, schedule the next check for MAX_BUFFER_LENGTH - (max(buffer lengths)),
-// since that's the earliest that a buffer overrun could occur.  This way, checks are
-// as rare as required, but as often as necessary to ensure never crossing this bound.
-// Furthermore, buffers are only tested at most once per write(), so passing a very
-// large string into write() might have undesirable effects, but this is manageable by
-// the caller, so it is assumed to be safe.  Thus, a call to write() may, in the extreme
-// edge case, result in creating at most one complete copy of the string passed in.
-// Set to Infinity to have unlimited buffers.
-sax.MAX_BUFFER_LENGTH = 64 * 1024
-
-var buffers = [
-  "comment", "sgmlDecl", "textNode", "tagName", "doctype",
-  "procInstName", "procInstBody", "entity", "attribName",
-  "attribValue", "cdata", "script"
-]
-
-sax.EVENTS = // for discoverability.
-  [ "text"
-  , "processinginstruction"
-  , "sgmldeclaration"
-  , "doctype"
-  , "comment"
-  , "attribute"
-  , "opentag"
-  , "closetag"
-  , "opencdata"
-  , "cdata"
-  , "closecdata"
-  , "error"
-  , "end"
-  , "ready"
-  , "script"
-  , "opennamespace"
-  , "closenamespace"
+;(function (sax) { // wrapper for non-node envs
+  sax.parser = function (strict, opt) { return new SAXParser(strict, opt) }
+  sax.SAXParser = SAXParser
+  sax.SAXStream = SAXStream
+  sax.createStream = createStream
+
+  // When we pass the MAX_BUFFER_LENGTH position, start checking for buffer overruns.
+  // When we check, schedule the next check for MAX_BUFFER_LENGTH - (max(buffer lengths)),
+  // since that's the earliest that a buffer overrun could occur.  This way, checks are
+  // as rare as required, but as often as necessary to ensure never crossing this bound.
+  // Furthermore, buffers are only tested at most once per write(), so passing a very
+  // large string into write() might have undesirable effects, but this is manageable by
+  // the caller, so it is assumed to be safe.  Thus, a call to write() may, in the extreme
+  // edge case, result in creating at most one complete copy of the string passed in.
+  // Set to Infinity to have unlimited buffers.
+  sax.MAX_BUFFER_LENGTH = 64 * 1024
+
+  var buffers = [
+    'comment', 'sgmlDecl', 'textNode', 'tagName', 'doctype',
+    'procInstName', 'procInstBody', 'entity', 'attribName',
+    'attribValue', 'cdata', 'script'
   ]
 
-function SAXParser (strict, opt) {
-  if (!(this instanceof SAXParser)) return new SAXParser(strict, opt)
-
-  var parser = this
-  clearBuffers(parser)
-  parser.q = parser.c = ""
-  parser.bufferCheckPosition = sax.MAX_BUFFER_LENGTH
-  parser.opt = opt || {}
-  parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags
-  parser.looseCase = parser.opt.lowercase ? "toLowerCase" : "toUpperCase"
-  parser.tags = []
-  parser.closed = parser.closedRoot = parser.sawRoot = false
-  parser.tag = parser.error = null
-  parser.strict = !!strict
-  parser.noscript = !!(strict || parser.opt.noscript)
-  parser.state = S.BEGIN
-  parser.ENTITIES = Object.create(sax.ENTITIES)
-  parser.attribList = []
-
-  // namespaces form a prototype chain.
-  // it always points at the current tag,
-  // which protos to its parent tag.
-  if (parser.opt.xmlns) parser.ns = Object.create(rootNS)
-
-  // mostly just for error reporting
-  parser.trackPosition = parser.opt.position !== false
-  if (parser.trackPosition) {
-    parser.position = parser.line = parser.column = 0
+  sax.EVENTS = [
+    'text',
+    'processinginstruction',
+    'sgmldeclaration',
+    'doctype',
+    'comment',
+    'opentagstart',
+    'attribute',
+    'opentag',
+    'closetag',
+    'opencdata',
+    'cdata',
+    'closecdata',
+    'error',
+    'end',
+    'ready',
+    'script',
+    'opennamespace',
+    'closenamespace'
+  ]
+
+  function SAXParser (strict, opt) {
+    if (!(this instanceof SAXParser)) {
+      return new SAXParser(strict, opt)
+    }
+
+    var parser = this
+    clearBuffers(parser)
+    parser.q = parser.c = ''
+    parser.bufferCheckPosition = sax.MAX_BUFFER_LENGTH
+    parser.opt = opt || {}
+    parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags
+    parser.looseCase = parser.opt.lowercase ? 'toLowerCase' : 'toUpperCase'
+    parser.tags = []
+    parser.closed = parser.closedRoot = parser.sawRoot = false
+    parser.tag = parser.error = null
+    parser.strict = !!strict
+    parser.noscript = !!(strict || parser.opt.noscript)
+    parser.state = S.BEGIN
+    parser.strictEntities = parser.opt.strictEntities
+    parser.ENTITIES = parser.strictEntities ? Object.create(sax.XML_ENTITIES) : Object.create(sax.ENTITIES)
+    parser.attribList = []
+
+    // namespaces form a prototype chain.
+    // it always points at the current tag,
+    // which protos to its parent tag.
+    if (parser.opt.xmlns) {
+      parser.ns = Object.create(rootNS)
+    }
+
+    // mostly just for error reporting
+    parser.trackPosition = parser.opt.position !== false
+    if (parser.trackPosition) {
+      parser.position = parser.line = parser.column = 0
+    }
+    emit(parser, 'onready')
   }
-  emit(parser, "onready")
-}
-
-if (!Object.create) Object.create = function (o) {
-  function f () { this.__proto__ = o }
-  f.prototype = o
-  return new f
-}
-
-if (!Object.getPrototypeOf) Object.getPrototypeOf = function (o) {
-  return o.__proto__
-}
-
-if (!Object.keys) Object.keys = function (o) {
-  var a = []
-  for (var i in o) if (o.hasOwnProperty(i)) a.push(i)
-  return a
-}
-
-function checkBufferLength (parser) {
-  var maxAllowed = Math.max(sax.MAX_BUFFER_LENGTH, 10)
-    , maxActual = 0
-  for (var i = 0, l = buffers.length; i < l; i ++) {
-    var len = parser[buffers[i]].length
-    if (len > maxAllowed) {
-      // Text/cdata nodes can get big, and since they're buffered,
-      // we can get here under normal conditions.
-      // Avoid issues by emitting the text node now,
-      // so at least it won't get any bigger.
-      switch (buffers[i]) {
-        case "textNode":
-          closeText(parser)
-        break
 
-        case "cdata":
-          emitNode(parser, "oncdata", parser.cdata)
-          parser.cdata = ""
-        break
+  if (!Object.create) {
+    Object.create = function (o) {
+      function F () {}
+      F.prototype = o
+      var newf = new F()
+      return newf
+    }
+  }
 
-        case "script":
-          emitNode(parser, "onscript", parser.script)
-          parser.script = ""
-        break
+  if (!Object.keys) {
+    Object.keys = function (o) {
+      var a = []
+      for (var i in o) if (o.hasOwnProperty(i)) a.push(i)
+      return a
+    }
+  }
 
-        default:
-          error(parser, "Max buffer length exceeded: "+buffers[i])
+  function checkBufferLength (parser) {
+    var maxAllowed = Math.max(sax.MAX_BUFFER_LENGTH, 10)
+    var maxActual = 0
+    for (var i = 0, l = buffers.length; i < l; i++) {
+      var len = parser[buffers[i]].length
+      if (len > maxAllowed) {
+        // Text/cdata nodes can get big, and since they're buffered,
+        // we can get here under normal conditions.
+        // Avoid issues by emitting the text node now,
+        // so at least it won't get any bigger.
+        switch (buffers[i]) {
+          case 'textNode':
+            closeText(parser)
+            break
+
+          case 'cdata':
+            emitNode(parser, 'oncdata', parser.cdata)
+            parser.cdata = ''
+            break
+
+          case 'script':
+            emitNode(parser, 'onscript', parser.script)
+            parser.script = ''
+            break
+
+          default:
+            error(parser, 'Max buffer length exceeded: ' + buffers[i])
+        }
       }
+      maxActual = Math.max(maxActual, len)
     }
-    maxActual = Math.max(maxActual, len)
+    // schedule the next check for the earliest possible buffer overrun.
+    var m = sax.MAX_BUFFER_LENGTH - maxActual
+    parser.bufferCheckPosition = m + parser.position
   }
-  // schedule the next check for the earliest possible buffer overrun.
-  parser.bufferCheckPosition = (sax.MAX_BUFFER_LENGTH - maxActual)
-                             + parser.position
-}
-
-function clearBuffers (parser) {
-  for (var i = 0, l = buffers.length; i < l; i ++) {
-    parser[buffers[i]] = ""
+
+  function clearBuffers (parser) {
+    for (var i = 0, l = buffers.length; i < l; i++) {
+      parser[buffers[i]] = ''
+    }
   }
-}
 
-SAXParser.prototype =
-  { end: function () { end(this) }
-  , write: write
-  , resume: function () { this.error = null; return this }
-  , close: function () { return this.write(null) }
+  function flushBuffers (parser) {
+    closeText(parser)
+    if (parser.cdata !== '') {
+      emitNode(parser, 'oncdata', parser.cdata)
+      parser.cdata = ''
+    }
+    if (parser.script !== '') {
+      emitNode(parser, 'onscript', parser.script)
+      parser.script = ''
+    }
   }
 
-try {
-  var Stream = require("stream").Stream
-} catch (ex) {
-  var Stream = function () {}
-}
+  SAXParser.prototype = {
+    end: function () { end(this) },
+    write: write,
+    resume: function () { this.error = null; return this },
+    close: function () { return this.write(null) },
+    flush: function () { flushBuffers(this) }
+  }
 
+  var Stream
+  try {
+    Stream = require('stream').Stream
+  } catch (ex) {
+    Stream = function () {}
+  }
 
-var streamWraps = sax.EVENTS.filter(function (ev) {
-  return ev !== "error" && ev !== "end"
-})
+  var streamWraps = sax.EVENTS.filter(function (ev) {
+    return ev !== 'error' && ev !== 'end'
+  })
 
-function createStream (strict, opt) {
-  return new SAXStream(strict, opt)
-}
+  function createStream (strict, opt) {
+    return new SAXStream(strict, opt)
+  }
 
-function SAXStream (strict, opt) {
-  if (!(this instanceof SAXStream)) return new SAXStream(strict, opt)
+  function SAXStream (strict, opt) {
+    if (!(this instanceof SAXStream)) {
+      return new SAXStream(strict, opt)
+    }
 
-  Stream.apply(this)
+    Stream.apply(this)
 
-  this._parser = new SAXParser(strict, opt)
-  this.writable = true
-  this.readable = true
+    this._parser = new SAXParser(strict, opt)
+    this.writable = true
+    this.readable = true
 
+    var me = this
 
-  var me = this
+    this._parser.onend = function () {
+      me.emit('end')
+    }
 
-  this._parser.onend = function () {
-    me.emit("end")
-  }
+    this._parser.onerror = function (er) {
+      me.emit('error', er)
 
-  this._parser.onerror = function (er) {
-    me.emit("error", er)
+      // if didn't throw, then means error was handled.
+      // go ahead and clear error, so we can write again.
+      me._parser.error = null
+    }
 
-    // if didn't throw, then means error was handled.
-    // go ahead and clear error, so we can write again.
-    me._parser.error = null
+    this._decoder = null
+
+    streamWraps.forEach(function (ev) {
+      Object.defineProperty(me, 'on' + ev, {
+        get: function () {
+          return me._parser['on' + ev]
+        },
+        set: function (h) {
+          if (!h) {
+            me.removeAllListeners(ev)
+            me._parser['on' + ev] = h
+            return h
+          }
+          me.on(ev, h)
+        },
+        enumerable: true,
+        configurable: false
+      })
+    })
   }
 
-  this._decoder = null;
-
-  streamWraps.forEach(function (ev) {
-    Object.defineProperty(me, "on" + ev, {
-      get: function () { return me._parser["on" + ev] },
-      set: function (h) {
-        if (!h) {
-          me.removeAllListeners(ev)
-          return me._parser["on"+ev] = h
-        }
-        me.on(ev, h)
-      },
-      enumerable: true,
-      configurable: false
-    })
+  SAXStream.prototype = Object.create(Stream.prototype, {
+    constructor: {
+      value: SAXStream
+    }
   })
-}
-
-SAXStream.prototype = Object.create(Stream.prototype,
-  { constructor: { value: SAXStream } })
 
-SAXStream.prototype.write = function (data) {
-  if (typeof Buffer === 'function' &&
+  SAXStream.prototype.write = function (data) {
+    if (typeof Buffer === 'function' &&
       typeof Buffer.isBuffer === 'function' &&
       Buffer.isBuffer(data)) {
-    if (!this._decoder) {
-      var SD = require('string_decoder').StringDecoder
-      this._decoder = new SD('utf8')
+      if (!this._decoder) {
+        var SD = require('string_decoder').StringDecoder
+        this._decoder = new SD('utf8')
+      }
+      data = this._decoder.write(data)
     }
-    data = this._decoder.write(data);
+
+    this._parser.write(data.toString())
+    this.emit('data', data)
+    return true
   }
 
-  this._parser.write(data.toString())
-  this.emit("data", data)
-  return true
-}
-
-SAXStream.prototype.end = function (chunk) {
-  if (chunk && chunk.length) this.write(chunk)
-  else if (this.leftovers) this._parser.write(this.leftovers.toString())
-  this._parser.end()
-  return true
-}
-
-SAXStream.prototype.on = function (ev, handler) {
-  var me = this
-  if (!me._parser["on"+ev] && streamWraps.indexOf(ev) !== -1) {
-    me._parser["on"+ev] = function () {
-      var args = arguments.length === 1 ? [arguments[0]]
-               : Array.apply(null, arguments)
-      args.splice(0, 0, ev)
-      me.emit.apply(me, args)
+  SAXStream.prototype.end = function (chunk) {
+    if (chunk && chunk.length) {
+      this.write(chunk)
     }
+    this._parser.end()
+    return true
   }
 
-  return Stream.prototype.on.call(me, ev, handler)
-}
-
+  SAXStream.prototype.on = function (ev, handler) {
+    var me = this
+    if (!me._parser['on' + ev] && streamWraps.indexOf(ev) !== -1) {
+      me._parser['on' + ev] = function () {
+        var args = arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments)
+        args.splice(0, 0, ev)
+        me.emit.apply(me, args)
+      }
+    }
 
+    return Stream.prototype.on.call(me, ev, handler)
+  }
 
-// character classes and tokens
-var whitespace = "\r\n\t "
   // this really needs to be replaced with character classes.
   // XML allows all manner of ridiculous numbers and digits.
-  , number = "0124356789"
-  , letter = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
-  // (Letter | "_" | ":")
-  , quote = "'\""
-  , entity = number+letter+"#"
-  , attribEnd = whitespace + ">"
-  , CDATA = "[CDATA["
-  , DOCTYPE = "DOCTYPE"
-  , XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace"
-  , XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/"
-  , rootNS = { xml: XML_NAMESPACE, xmlns: XMLNS_NAMESPACE }
-
-// turn all the string character sets into character class objects.
-whitespace = charClass(whitespace)
-number = charClass(number)
-letter = charClass(letter)
-
-// http://www.w3.org/TR/REC-xml/#NT-NameStartChar
-// This implementation works on strings, a single character at a time
-// as such, it cannot ever support astral-plane characters (10000-EFFFF)
-// without a significant breaking change to either this  parser, or the
-// JavaScript language.  Implementation of an emoji-capable xml parser
-// is left as an exercise for the reader.
-var nameStart = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/
-
-var nameBody = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040\.\d-]/
-
-quote = charClass(quote)
-entity = charClass(entity)
-attribEnd = charClass(attribEnd)
-
-function charClass (str) {
-  return str.split("").reduce(function (s, c) {
-    s[c] = true
-    return s
-  }, {})
-}
-
-function isRegExp (c) {
-  return Object.prototype.toString.call(c) === '[object RegExp]'
-}
-
-function is (charclass, c) {
-  return isRegExp(charclass) ? !!c.match(charclass) : charclass[c]
-}
-
-function not (charclass, c) {
-  return !is(charclass, c)
-}
-
-var S = 0
-sax.STATE =
-{ BEGIN                     : S++
-, TEXT                      : S++ // general stuff
-, TEXT_ENTITY               : S++ // &amp and such.
-, OPEN_WAKA                 : S++ // <
-, SGML_DECL                 : S++ // <!BLARG
-, SGML_DECL_QUOTED          : S++ // <!BLARG foo "bar
-, DOCTYPE                   : S++ // <!DOCTYPE
-, DOCTYPE_QUOTED            : S++ // <!DOCTYPE "//blah
-, DOCTYPE_DTD               : S++ // <!DOCTYPE "//blah" [ ...
-, DOCTYPE_DTD_QUOTED        : S++ // <!DOCTYPE "//blah" [ "foo
-, COMMENT_STARTING          : S++ // <!-
-, COMMENT                   : S++ // <!--
-, COMMENT_ENDING            : S++ // <!-- blah -
-, COMMENT_ENDED             : S++ // <!-- blah --
-, CDATA                     : S++ // <![CDATA[ something
-, CDATA_ENDING              : S++ // ]
-, CDATA_ENDING_2            : S++ // ]]
-, PROC_INST                 : S++ // <?hi
-, PROC_INST_BODY            : S++ // <?hi there
-, PROC_INST_ENDING          : S++ // <?hi "there" ?
-, OPEN_TAG                  : S++ // <strong
-, OPEN_TAG_SLASH            : S++ // <strong /
-, ATTRIB                    : S++ // <a
-, ATTRIB_NAME               : S++ // <a foo
-, ATTRIB_NAME_SAW_WHITE     : S++ // <a foo _
-, ATTRIB_VALUE              : S++ // <a foo=
-, ATTRIB_VALUE_QUOTED       : S++ // <a foo="bar
-, ATTRIB_VALUE_UNQUOTED     : S++ // <a foo=bar
-, ATTRIB_VALUE_ENTITY_Q     : S++ // <foo bar="""
-, ATTRIB_VALUE_ENTITY_U     : S++ // <foo bar="
-, CLOSE_TAG                 : S++ // </a
-, CLOSE_TAG_SAW_WHITE       : S++ // </a   >
-, SCRIPT                    : S++ // <script> ...
-, SCRIPT_ENDING             : S++ // <script> ... <
-}
-
-sax.ENTITIES =
-{ "amp" : "&"
-, "gt" : ">"
-, "lt" : "<"
-, "quot" : "\""
-, "apos" : "'"
-, "AElig" : 198
-, "Aacute" : 193
-, "Acirc" : 194
-, "Agrave" : 192
-, "Aring" : 197
-, "Atilde" : 195
-, "Auml" : 196
-, "Ccedil" : 199
-, "ETH" : 208
-, "Eacute" : 201
-, "Ecirc" : 202
-, "Egrave" : 200
-, "Euml" : 203
-, "Iacute" : 205
-, "Icirc" : 206
-, "Igrave" : 204
-, "Iuml" : 207
-, "Ntilde" : 209
-, "Oacute" : 211
-, "Ocirc" : 212
-, "Ograve" : 210
-, "Oslash" : 216
-, "Otilde" : 213
-, "Ouml" : 214
-, "THORN" : 222
-, "Uacute" : 218
-, "Ucirc" : 219
-, "Ugrave" : 217
-, "Uuml" : 220
-, "Yacute" : 221
-, "aacute" : 225
-, "acirc" : 226
-, "aelig" : 230
-, "agrave" : 224
-, "aring" : 229
-, "atilde" : 227
-, "auml" : 228
-, "ccedil" : 231
-, "eacute" : 233
-, "ecirc" : 234
-, "egrave" : 232
-, "eth" : 240
-, "euml" : 235
-, "iacute" : 237
-, "icirc" : 238
-, "igrave" : 236
-, "iuml" : 239
-, "ntilde" : 241
-, "oacute" : 243
-, "ocirc" : 244
-, "ograve" : 242
-, "oslash" : 248
-, "otilde" : 245
-, "ouml" : 246
-, "szlig" : 223
-, "thorn" : 254
-, "uacute" : 250
-, "ucirc" : 251
-, "ugrave" : 249
-, "uuml" : 252
-, "yacute" : 253
-, "yuml" : 255
-, "copy" : 169
-, "reg" : 174
-, "nbsp" : 160
-, "iexcl" : 161
-, "cent" : 162
-, "pound" : 163
-, "curren" : 164
-, "yen" : 165
-, "brvbar" : 166
-, "sect" : 167
-, "uml" : 168
-, "ordf" : 170
-, "laquo" : 171
-, "not" : 172
-, "shy" : 173
-, "macr" : 175
-, "deg" : 176
-, "plusmn" : 177
-, "sup1" : 185
-, "sup2" : 178
-, "sup3" : 179
-, "acute" : 180
-, "micro" : 181
-, "para" : 182
-, "middot" : 183
-, "cedil" : 184
-, "ordm" : 186
-, "raquo" : 187
-, "frac14" : 188
-, "frac12" : 189
-, "frac34" : 190
-, "iquest" : 191
-, "times" : 215
-, "divide" : 247
-, "OElig" : 338
-, "oelig" : 339
-, "Scaron" : 352
-, "scaron" : 353
-, "Yuml" : 376
-, "fnof" : 402
-, "circ" : 710
-, "tilde" : 732
-, "Alpha" : 913
-, "Beta" : 914
-, "Gamma" : 915
-, "Delta" : 916
-, "Epsilon" : 917
-, "Zeta" : 918
-, "Eta" : 919
-, "Theta" : 920
-, "Iota" : 921
-, "Kappa" : 922
-, "Lambda" : 923
-, "Mu" : 924
-, "Nu" : 925
-, "Xi" : 926
-, "Omicron" : 927
-, "Pi" : 928
-, "Rho" : 929
-, "Sigma" : 931
-, "Tau" : 932
-, "Upsilon" : 933
-, "Phi" : 934
-, "Chi" : 935
-, "Psi" : 936
-, "Omega" : 937
-, "alpha" : 945
-, "beta" : 946
-, "gamma" : 947
-, "delta" : 948
-, "epsilon" : 949
-, "zeta" : 950
-, "eta" : 951
-, "theta" : 952
-, "iota" : 953
-, "kappa" : 954
-, "lambda" : 955
-, "mu" : 956
-, "nu" : 957
-, "xi" : 958
-, "omicron" : 959
-, "pi" : 960
-, "rho" : 961
-, "sigmaf" : 962
-, "sigma" : 963
-, "tau" : 964
-, "upsilon" : 965
-, "phi" : 966
-, "chi" : 967
-, "psi" : 968
-, "omega" : 969
-, "thetasym" : 977
-, "upsih" : 978
-, "piv" : 982
-, "ensp" : 8194
-, "emsp" : 8195
-, "thinsp" : 8201
-, "zwnj" : 8204
-, "zwj" : 8205
-, "lrm" : 8206
-, "rlm" : 8207
-, "ndash" : 8211
-, "mdash" : 8212
-, "lsquo" : 8216
-, "rsquo" : 8217
-, "sbquo" : 8218
-, "ldquo" : 8220
-, "rdquo" : 8221
-, "bdquo" : 8222
-, "dagger" : 8224
-, "Dagger" : 8225
-, "bull" : 8226
-, "hellip" : 8230
-, "permil" : 8240
-, "prime" : 8242
-, "Prime" : 8243
-, "lsaquo" : 8249
-, "rsaquo" : 8250
-, "oline" : 8254
-, "frasl" : 8260
-, "euro" : 8364
-, "image" : 8465
-, "weierp" : 8472
-, "real" : 8476
-, "trade" : 8482
-, "alefsym" : 8501
-, "larr" : 8592
-, "uarr" : 8593
-, "rarr" : 8594
-, "darr" : 8595
-, "harr" : 8596
-, "crarr" : 8629
-, "lArr" : 8656
-, "uArr" : 8657
-, "rArr" : 8658
-, "dArr" : 8659
-, "hArr" : 8660
-, "forall" : 8704
-, "part" : 8706
-, "exist" : 8707
-, "empty" : 8709
-, "nabla" : 8711
-, "isin" : 8712
-, "notin" : 8713
-, "ni" : 8715
-, "prod" : 8719
-, "sum" : 8721
-, "minus" : 8722
-, "lowast" : 8727
-, "radic" : 8730
-, "prop" : 8733
-, "infin" : 8734
-, "ang" : 8736
-, "and" : 8743
-, "or" : 8744
-, "cap" : 8745
-, "cup" : 8746
-, "int" : 8747
-, "there4" : 8756
-, "sim" : 8764
-, "cong" : 8773
-, "asymp" : 8776
-, "ne" : 8800
-, "equiv" : 8801
-, "le" : 8804
-, "ge" : 8805
-, "sub" : 8834
-, "sup" : 8835
-, "nsub" : 8836
-, "sube" : 8838
-, "supe" : 8839
-, "oplus" : 8853
-, "otimes" : 8855
-, "perp" : 8869
-, "sdot" : 8901
-, "lceil" : 8968
-, "rceil" : 8969
-, "lfloor" : 8970
-, "rfloor" : 8971
-, "lang" : 9001
-, "rang" : 9002
-, "loz" : 9674
-, "spades" : 9824
-, "clubs" : 9827
-, "hearts" : 9829
-, "diams" : 9830
-}
-
-Object.keys(sax.ENTITIES).forEach(function (key) {
+  var CDATA = '[CDATA['
+  var DOCTYPE = 'DOCTYPE'
+  var XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace'
+  var XMLNS_NAMESPACE = 'http://www.w3.org/2000/xmlns/'
+  var rootNS = { xml: XML_NAMESPACE, xmlns: XMLNS_NAMESPACE }
+
+  // http://www.w3.org/TR/REC-xml/#NT-NameStartChar
+  // This implementation works on strings, a single character at a time
+  // as such, it cannot ever support astral-plane characters (10000-EFFFF)
+  // without a significant breaking change to either this  parser, or the
+  // JavaScript language.  Implementation of an emoji-capable xml parser
+  // is left as an exercise for the reader.
+  var nameStart = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/
+
+  var nameBody = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/
+
+  var entityStart = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/
+  var entityBody = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/
+
+  function isWhitespace (c) {
+    return c === ' ' || c === '\n' || c === '\r' || c === '\t'
+  }
+
+  function isQuote (c) {
+    return c === '"' || c === '\''
+  }
+
+  function isAttribEnd (c) {
+    return c === '>' || isWhitespace(c)
+  }
+
+  function isMatch (regex, c) {
+    return regex.test(c)
+  }
+
+  function notMatch (regex, c) {
+    return !isMatch(regex, c)
+  }
+
+  var S = 0
+  sax.STATE = {
+    BEGIN: S++, // leading byte order mark or whitespace
+    BEGIN_WHITESPACE: S++, // leading whitespace
+    TEXT: S++, // general stuff
+    TEXT_ENTITY: S++, // &amp and such.
+    OPEN_WAKA: S++, // <
+    SGML_DECL: S++, // <!BLARG
+    SGML_DECL_QUOTED: S++, // <!BLARG foo "bar
+    DOCTYPE: S++, // <!DOCTYPE
+    DOCTYPE_QUOTED: S++, // <!DOCTYPE "//blah
+    DOCTYPE_DTD: S++, // <!DOCTYPE "//blah" [ ...
+    DOCTYPE_DTD_QUOTED: S++, // <!DOCTYPE "//blah" [ "foo
+    COMMENT_STARTING: S++, // <!-
+    COMMENT: S++, // <!--
+    COMMENT_ENDING: S++, // <!-- blah -
+    COMMENT_ENDED: S++, // <!-- blah --
+    CDATA: S++, // <![CDATA[ something
+    CDATA_ENDING: S++, // ]
+    CDATA_ENDING_2: S++, // ]]
+    PROC_INST: S++, // <?hi
+    PROC_INST_BODY: S++, // <?hi there
+    PROC_INST_ENDING: S++, // <?hi "there" ?
+    OPEN_TAG: S++, // <strong
+    OPEN_TAG_SLASH: S++, // <strong /
+    ATTRIB: S++, // <a
+    ATTRIB_NAME: S++, // <a foo
+    ATTRIB_NAME_SAW_WHITE: S++, // <a foo _
+    ATTRIB_VALUE: S++, // <a foo=
+    ATTRIB_VALUE_QUOTED: S++, // <a foo="bar
+    ATTRIB_VALUE_CLOSED: S++, // <a foo="bar"
+    ATTRIB_VALUE_UNQUOTED: S++, // <a foo=bar
+    ATTRIB_VALUE_ENTITY_Q: S++, // <foo bar="""
+    ATTRIB_VALUE_ENTITY_U: S++, // <foo bar=&quot
+    CLOSE_TAG: S++, // </a
+    CLOSE_TAG_SAW_WHITE: S++, // </a   >
+    SCRIPT: S++, // <script> ...
+    SCRIPT_ENDING: S++ // <script> ... <
+  }
+
+  sax.XML_ENTITIES = {
+    'amp': '&',
+    'gt': '>',
+    'lt': '<',
+    'quot': '"',
+    'apos': "'"
+  }
+
+  sax.ENTITIES = {
+    'amp': '&',
+    'gt': '>',
+    'lt': '<',
+    'quot': '"',
+    'apos': "'",
+    'AElig': 198,
+    'Aacute': 193,
+    'Acirc': 194,
+    'Agrave': 192,
+    'Aring': 197,
+    'Atilde': 195,
+    'Auml': 196,
+    'Ccedil': 199,
+    'ETH': 208,
+    'Eacute': 201,
+    'Ecirc': 202,
+    'Egrave': 200,
+    'Euml': 203,
+    'Iacute': 205,
+    'Icirc': 206,
+    'Igrave': 204,
+    'Iuml': 207,
+    'Ntilde': 209,
+    'Oacute': 211,
+    'Ocirc': 212,
+    'Ograve': 210,
+    'Oslash': 216,
+    'Otilde': 213,
+    'Ouml': 214,
+    'THORN': 222,
+    'Uacute': 218,
+    'Ucirc': 219,
+    'Ugrave': 217,
+    'Uuml': 220,
+    'Yacute': 221,
+    'aacute': 225,
+    'acirc': 226,
+    'aelig': 230,
+    'agrave': 224,
+    'aring': 229,
+    'atilde': 227,
+    'auml': 228,
+    'ccedil': 231,
+    'eacute': 233,
+    'ecirc': 234,
+    'egrave': 232,
+    'eth': 240,
+    'euml': 235,
+    'iacute': 237,
+    'icirc': 238,
+    'igrave': 236,
+    'iuml': 239,
+    'ntilde': 241,
+    'oacute': 243,
+    'ocirc': 244,
+    'ograve': 242,
+    'oslash': 248,
+    'otilde': 245,
+    'ouml': 246,
+    'szlig': 223,
+    'thorn': 254,
+    'uacute': 250,
+    'ucirc': 251,
+    'ugrave': 249,
+    'uuml': 252,
+    'yacute': 253,
+    'yuml': 255,
+    'copy': 169,
+    'reg': 174,
+    'nbsp': 160,
+    'iexcl': 161,
+    'cent': 162,
+    'pound': 163,
+    'curren': 164,
+    'yen': 165,
+    'brvbar': 166,
+    'sect': 167,
+    'uml': 168,
+    'ordf': 170,
+    'laquo': 171,
+    'not': 172,
+    'shy': 173,
+    'macr': 175,
+    'deg': 176,
+    'plusmn': 177,
+    'sup1': 185,
+    'sup2': 178,
+    'sup3': 179,
+    'acute': 180,
+    'micro': 181,
+    'para': 182,
+    'middot': 183,
+    'cedil': 184,
+    'ordm': 186,
+    'raquo': 187,
+    'frac14': 188,
+    'frac12': 189,
+    'frac34': 190,
+    'iquest': 191,
+    'times': 215,
+    'divide': 247,
+    'OElig': 338,
+    'oelig': 339,
+    'Scaron': 352,
+    'scaron': 353,
+    'Yuml': 376,
+    'fnof': 402,
+    'circ': 710,
+    'tilde': 732,
+    'Alpha': 913,
+    'Beta': 914,
+    'Gamma': 915,
+    'Delta': 916,
+    'Epsilon': 917,
+    'Zeta': 918,
+    'Eta': 919,
+    'Theta': 920,
+    'Iota': 921,
+    'Kappa': 922,
+    'Lambda': 923,
+    'Mu': 924,
+    'Nu': 925,
+    'Xi': 926,
+    'Omicron': 927,
+    'Pi': 928,
+    'Rho': 929,
+    'Sigma': 931,
+    'Tau': 932,
+    'Upsilon': 933,
+    'Phi': 934,
+    'Chi': 935,
+    'Psi': 936,
+    'Omega': 937,
+    'alpha': 945,
+    'beta': 946,
+    'gamma': 947,
+    'delta': 948,
+    'epsilon': 949,
+    'zeta': 950,
+    'eta': 951,
+    'theta': 952,
+    'iota': 953,
+    'kappa': 954,
+    'lambda': 955,
+    'mu': 956,
+    'nu': 957,
+    'xi': 958,
+    'omicron': 959,
+    'pi': 960,
+    'rho': 961,
+    'sigmaf': 962,
+    'sigma': 963,
+    'tau': 964,
+    'upsilon': 965,
+    'phi': 966,
+    'chi': 967,
+    'psi': 968,
+    'omega': 969,
+    'thetasym': 977,
+    'upsih': 978,
+    'piv': 982,
+    'ensp': 8194,
+    'emsp': 8195,
+    'thinsp': 8201,
+    'zwnj': 8204,
+    'zwj': 8205,
+    'lrm': 8206,
+    'rlm': 8207,
+    'ndash': 8211,
+    'mdash': 8212,
+    'lsquo': 8216,
+    'rsquo': 8217,
+    'sbquo': 8218,
+    'ldquo': 8220,
+    'rdquo': 8221,
+    'bdquo': 8222,
+    'dagger': 8224,
+    'Dagger': 8225,
+    'bull': 8226,
+    'hellip': 8230,
+    'permil': 8240,
+    'prime': 8242,
+    'Prime': 8243,
+    'lsaquo': 8249,
+    'rsaquo': 8250,
+    'oline': 8254,
+    'frasl': 8260,
+    'euro': 8364,
+    'image': 8465,
+    'weierp': 8472,
+    'real': 8476,
+    'trade': 8482,
+    'alefsym': 8501,
+    'larr': 8592,
+    'uarr': 8593,
+    'rarr': 8594,
+    'darr': 8595,
+    'harr': 8596,
+    'crarr': 8629,
+    'lArr': 8656,
+    'uArr': 8657,
+    'rArr': 8658,
+    'dArr': 8659,
+    'hArr': 8660,
+    'forall': 8704,
+    'part': 8706,
+    'exist': 8707,
+    'empty': 8709,
+    'nabla': 8711,
+    'isin': 8712,
+    'notin': 8713,
+    'ni': 8715,
+    'prod': 8719,
+    'sum': 8721,
+    'minus': 8722,
+    'lowast': 8727,
+    'radic': 8730,
+    'prop': 8733,
+    'infin': 8734,
+    'ang': 8736,
+    'and': 8743,
+    'or': 8744,
+    'cap': 8745,
+    'cup': 8746,
+    'int': 8747,
+    'there4': 8756,
+    'sim': 8764,
+    'cong': 8773,
+    'asymp': 8776,
+    'ne': 8800,
+    'equiv': 8801,
+    'le': 8804,
+    'ge': 8805,
+    'sub': 8834,
+    'sup': 8835,
+    'nsub': 8836,
+    'sube': 8838,
+    'supe': 8839,
+    'oplus': 8853,
+    'otimes': 8855,
+    'perp': 8869,
+    'sdot': 8901,
+    'lceil': 8968,
+    'rceil': 8969,
+    'lfloor': 8970,
+    'rfloor': 8971,
+    'lang': 9001,
+    'rang': 9002,
+    'loz': 9674,
+    'spades': 9824,
+    'clubs': 9827,
+    'hearts': 9829,
+    'diams': 9830
+  }
+
+  Object.keys(sax.ENTITIES).forEach(function (key) {
     var e = sax.ENTITIES[key]
     var s = typeof e === 'number' ? String.fromCharCode(e) : e
     sax.ENTITIES[key] = s
-})
-
-for (var S in sax.STATE) sax.STATE[sax.STATE[S]] = S
-
-// shorthand
-S = sax.STATE
-
-function emit (parser, event, data) {
-  parser[event] && parser[event](data)
-}
-
-function emitNode (parser, nodeType, data) {
-  if (parser.textNode) closeText(parser)
-  emit(parser, nodeType, data)
-}
-
-function closeText (parser) {
-  parser.textNode = textopts(parser.opt, parser.textNode)
-  if (parser.textNode) emit(parser, "ontext", parser.textNode)
-  parser.textNode = ""
-}
-
-function textopts (opt, text) {
-  if (opt.trim) text = text.trim()
-  if (opt.normalize) text = text.replace(/\s+/g, " ")
-  return text
-}
-
-function error (parser, er) {
-  closeText(parser)
-  if (parser.trackPosition) {
-    er += "\nLine: "+parser.line+
-          "\nColumn: "+parser.column+
-          "\nChar: "+parser.c
+  })
+
+  for (var s in sax.STATE) {
+    sax.STATE[sax.STATE[s]] = s
   }
-  er = new Error(er)
-  parser.error = er
-  emit(parser, "onerror", er)
-  return parser
-}
-
-function end (parser) {
-  if (!parser.closedRoot) strictFail(parser, "Unclosed root tag")
-  if (parser.state !== S.TEXT) error(parser, "Unexpected end")
-  closeText(parser)
-  parser.c = ""
-  parser.closed = true
-  emit(parser, "onend")
-  SAXParser.call(parser, parser.strict, parser.opt)
-  return parser
-}
-
-function strictFail (parser, message) {
-  if (typeof parser !== 'object' || !(parser instanceof SAXParser))
-    throw new Error('bad call to strictFail');
-  if (parser.strict) error(parser, message)
-}
-
-function newTag (parser) {
-  if (!parser.strict) parser.tagName = parser.tagName[parser.looseCase]()
-  var parent = parser.tags[parser.tags.length - 1] || parser
-    , tag = parser.tag = { name : parser.tagName, attributes : {} }
-
-  // will be overridden if tag contails an xmlns="foo" or xmlns:foo="bar"
-  if (parser.opt.xmlns) tag.ns = parent.ns
-  parser.attribList.length = 0
-}
-
-function qname (name) {
-  var i = name.indexOf(":")
-    , qualName = i < 0 ? [ "", name ] : name.split(":")
-    , prefix = qualName[0]
-    , local = qualName[1]
-
-  // <x "xmlns"="http://foo">
-  if (name === "xmlns") {
-    prefix = "xmlns"
-    local = ""
+
+  // shorthand
+  S = sax.STATE
+
+  function emit (parser, event, data) {
+    parser[event] && parser[event](data)
   }
 
-  return { prefix: prefix, local: local }
-}
+  function emitNode (parser, nodeType, data) {
+    if (parser.textNode) closeText(parser)
+    emit(parser, nodeType, data)
+  }
 
-function attrib (parser) {
-  if (!parser.strict) parser.attribName = parser.attribName[parser.looseCase]()
+  function closeText (parser) {
+    parser.textNode = textopts(parser.opt, parser.textNode)
+    if (parser.textNode) emit(parser, 'ontext', parser.textNode)
+    parser.textNode = ''
+  }
 
-  if (parser.attribList.indexOf(parser.attribName) !== -1 ||
-      parser.tag.attributes.hasOwnProperty(parser.attribName)) {
-    return parser.attribName = parser.attribValue = ""
+  function textopts (opt, text) {
+    if (opt.trim) text = text.trim()
+    if (opt.normalize) text = text.replace(/\s+/g, ' ')
+    return text
   }
 
-  if (parser.opt.xmlns) {
-    var qn = qname(parser.attribName)
-      , prefix = qn.prefix
-      , local = qn.local
-
-    if (prefix === "xmlns") {
-      // namespace binding attribute; push the binding into scope
-      if (local === "xml" && parser.attribValue !== XML_NAMESPACE) {
-        strictFail( parser
-                  , "xml: prefix must be bound to " + XML_NAMESPACE + "\n"
-                  + "Actual: " + parser.attribValue )
-      } else if (local === "xmlns" && parser.attribValue !== XMLNS_NAMESPACE) {
-        strictFail( parser
-                  , "xmlns: prefix must be bound to " + XMLNS_NAMESPACE + "\n"
-                  + "Actual: " + parser.attribValue )
-      } else {
-        var tag = parser.tag
-          , parent = parser.tags[parser.tags.length - 1] || parser
-        if (tag.ns === parent.ns) {
-          tag.ns = Object.create(parent.ns)
-        }
-        tag.ns[local] = parser.attribValue
-      }
+  function error (parser, er) {
+    closeText(parser)
+    if (parser.trackPosition) {
+      er += '\nLine: ' + parser.line +
+        '\nColumn: ' + parser.column +
+        '\nChar: ' + parser.c
     }
+    er = new Error(er)
+    parser.error = er
+    emit(parser, 'onerror', er)
+    return parser
+  }
 
-    // defer onattribute events until all attributes have been seen
-    // so any new bindings can take effect; preserve attribute order
-    // so deferred events can be emitted in document order
-    parser.attribList.push([parser.attribName, parser.attribValue])
-  } else {
-    // in non-xmlns mode, we can emit the event right away
-    parser.tag.attributes[parser.attribName] = parser.attribValue
-    emitNode( parser
-            , "onattribute"
-            , { name: parser.attribName
-              , value: parser.attribValue } )
+  function end (parser) {
+    if (parser.sawRoot && !parser.closedRoot) strictFail(parser, 'Unclosed root tag')
+    if ((parser.state !== S.BEGIN) &&
+      (parser.state !== S.BEGIN_WHITESPACE) &&
+      (parser.state !== S.TEXT)) {
+      error(parser, 'Unexpected end')
+    }
+    closeText(parser)
+    parser.c = ''
+    parser.closed = true
+    emit(parser, 'onend')
+    SAXParser.call(parser, parser.strict, parser.opt)
+    return parser
   }
 
-  parser.attribName = parser.attribValue = ""
-}
+  function strictFail (parser, message) {
+    if (typeof parser !== 'object' || !(parser instanceof SAXParser)) {
+      throw new Error('bad call to strictFail')
+    }
+    if (parser.strict) {
+      error(parser, message)
+    }
+  }
 
-function openTag (parser, selfClosing) {
-  if (parser.opt.xmlns) {
-    // emit namespace binding events
-    var tag = parser.tag
+  function newTag (parser) {
+    if (!parser.strict) parser.tagName = parser.tagName[parser.looseCase]()
+    var parent = parser.tags[parser.tags.length - 1] || parser
+    var tag = parser.tag = { name: parser.tagName, attributes: {} }
+
+    // will be overridden if tag contails an xmlns="foo" or xmlns:foo="bar"
+    if (parser.opt.xmlns) {
+      tag.ns = parent.ns
+    }
+    parser.attribList.length = 0
+    emitNode(parser, 'onopentagstart', tag)
+  }
 
-    // add namespace info to tag
-    var qn = qname(parser.tagName)
-    tag.prefix = qn.prefix
-    tag.local = qn.local
-    tag.uri = tag.ns[qn.prefix] || ""
+  function qname (name, attribute) {
+    var i = name.indexOf(':')
+    var qualName = i < 0 ? [ '', name ] : name.split(':')
+    var prefix = qualName[0]
+    var local = qualName[1]
 
-    if (tag.prefix && !tag.uri) {
-      strictFail(parser, "Unbound namespace prefix: "
-                       + JSON.stringify(parser.tagName))
-      tag.uri = qn.prefix
+    // <x "xmlns"="http://foo">
+    if (attribute && name === 'xmlns') {
+      prefix = 'xmlns'
+      local = ''
     }
 
-    var parent = parser.tags[parser.tags.length - 1] || parser
-    if (tag.ns && parent.ns !== tag.ns) {
-      Object.keys(tag.ns).forEach(function (p) {
-        emitNode( parser
-                , "onopennamespace"
-                , { prefix: p , uri: tag.ns[p] } )
-      })
+    return { prefix: prefix, local: local }
+  }
+
+  function attrib (parser) {
+    if (!parser.strict) {
+      parser.attribName = parser.attribName[parser.looseCase]()
     }
 
-    // handle deferred onattribute events
-    // Note: do not apply default ns to attributes:
-    //   http://www.w3.org/TR/REC-xml-names/#defaulting
-    for (var i = 0, l = parser.attribList.length; i < l; i ++) {
-      var nv = parser.attribList[i]
-      var name = nv[0]
-        , value = nv[1]
-        , qualName = qname(name)
-        , prefix = qualName.prefix
-        , local = qualName.local
-        , uri = prefix == "" ? "" : (tag.ns[prefix] || "")
-        , a = { name: name
-              , value: value
-              , prefix: prefix
-              , local: local
-              , uri: uri
-              }
+    if (parser.attribList.indexOf(parser.attribName) !== -1 ||
+      parser.tag.attributes.hasOwnProperty(parser.attribName)) {
+      parser.attribName = parser.attribValue = ''
+      return
+    }
 
-      // if there's any attributes with an undefined namespace,
-      // then fail on them now.
-      if (prefix && prefix != "xmlns" && !uri) {
-        strictFail(parser, "Unbound namespace prefix: "
-                         + JSON.stringify(prefix))
-        a.uri = prefix
+    if (parser.opt.xmlns) {
+      var qn = qname(parser.attribName, true)
+      var prefix = qn.prefix
+      var local = qn.local
+
+      if (prefix === 'xmlns') {
+        // namespace binding attribute. push the binding into scope
+        if (local === 'xml' && parser.attribValue !== XML_NAMESPACE) {
+          strictFail(parser,
+            'xml: prefix must be bound to ' + XML_NAMESPACE + '\n' +
+            'Actual: ' + parser.attribValue)
+        } else if (local === 'xmlns' && parser.attribValue !== XMLNS_NAMESPACE) {
+          strictFail(parser,
+            'xmlns: prefix must be bound to ' + XMLNS_NAMESPACE + '\n' +
+            'Actual: ' + parser.attribValue)
+        } else {
+          var tag = parser.tag
+          var parent = parser.tags[parser.tags.length - 1] || parser
+          if (tag.ns === parent.ns) {
+            tag.ns = Object.create(parent.ns)
+          }
+          tag.ns[local] = parser.attribValue
+        }
       }
-      parser.tag.attributes[name] = a
-      emitNode(parser, "onattribute", a)
+
+      // defer onattribute events until all attributes have been seen
+      // so any new bindings can take effect. preserve attribute order
+      // so deferred events can be emitted in document order
+      parser.attribList.push([parser.attribName, parser.attribValue])
+    } else {
+      // in non-xmlns mode, we can emit the event right away
+      parser.tag.attributes[parser.attribName] = parser.attribValue
+      emitNode(parser, 'onattribute', {
+        name: parser.attribName,
+        value: parser.attribValue
+      })
     }
-    parser.attribList.length = 0
+
+    parser.attribName = parser.attribValue = ''
   }
 
-  parser.tag.isSelfClosing = !!selfClosing
+  function openTag (parser, selfClosing) {
+    if (parser.opt.xmlns) {
+      // emit namespace binding events
+      var tag = parser.tag
+
+      // add namespace info to tag
+      var qn = qname(parser.tagName)
+      tag.prefix = qn.prefix
+      tag.local = qn.local
+      tag.uri = tag.ns[qn.prefix] || ''
+
+      if (tag.prefix && !tag.uri) {
+        strictFail(parser, 'Unbound namespace prefix: ' +
+          JSON.stringify(parser.tagName))
+        tag.uri = qn.prefix
+      }
 
-  // process the tag
-  parser.sawRoot = true
-  parser.tags.push(parser.tag)
-  emitNode(parser, "onopentag", parser.tag)
-  if (!selfClosing) {
-    // special case for <script> in non-strict mode.
-    if (!parser.noscript && parser.tagName.toLowerCase() === "script") {
-      parser.state = S.SCRIPT
-    } else {
-      parser.state = S.TEXT
+      var parent = parser.tags[parser.tags.length - 1] || parser
+      if (tag.ns && parent.ns !== tag.ns) {
+        Object.keys(tag.ns).forEach(function (p) {
+          emitNode(parser, 'onopennamespace', {
+            prefix: p,
+            uri: tag.ns[p]
+          })
+        })
+      }
+
+      // handle deferred onattribute events
+      // Note: do not apply default ns to attributes:
+      //   http://www.w3.org/TR/REC-xml-names/#defaulting
+      for (var i = 0, l = parser.attribList.length; i < l; i++) {
+        var nv = parser.attribList[i]
+        var name = nv[0]
+        var value = nv[1]
+        var qualName = qname(name, true)
+        var prefix = qualName.prefix
+        var local = qualName.local
+        var uri = prefix === '' ? '' : (tag.ns[prefix] || '')
+        var a = {
+          name: name,
+          value: value,
+          prefix: prefix,
+          local: local,
+          uri: uri
+        }
+
+        // if there's any attributes with an undefined namespace,
+        // then fail on them now.
+        if (prefix && prefix !== 'xmlns' && !uri) {
+          strictFail(parser, 'Unbound namespace prefix: ' +
+            JSON.stringify(prefix))
+          a.uri = prefix
+        }
+        parser.tag.attributes[name] = a
+        emitNode(parser, 'onattribute', a)
+      }
+      parser.attribList.length = 0
     }
-    parser.tag = null
-    parser.tagName = ""
-  }
-  parser.attribName = parser.attribValue = ""
-  parser.attribList.length = 0
-}
-
-function closeTag (parser) {
-  if (!parser.tagName) {
-    strictFail(parser, "Weird empty close tag.")
-    parser.textNode += "</>"
-    parser.state = S.TEXT
-    return
+
+    parser.tag.isSelfClosing = !!selfClosing
+
+    // process the tag
+    parser.sawRoot = true
+    parser.tags.push(parser.tag)
+    emitNode(parser, 'onopentag', parser.tag)
+    if (!selfClosing) {
+      // special case for <script> in non-strict mode.
+      if (!parser.noscript && parser.tagName.toLowerCase() === 'script') {
+        parser.state = S.SCRIPT
+      } else {
+        parser.state = S.TEXT
+      }
+      parser.tag = null
+      parser.tagName = ''
+    }
+    parser.attribName = parser.attribValue = ''
+    parser.attribList.length = 0
   }
 
-  if (parser.script) {
-    if (parser.tagName !== "script") {
-      parser.script += "</" + parser.tagName + ">"
-      parser.tagName = ""
-      parser.state = S.SCRIPT
+  function closeTag (parser) {
+    if (!parser.tagName) {
+      strictFail(parser, 'Weird empty close tag.')
+      parser.textNode += '</>'
+      parser.state = S.TEXT
       return
     }
-    emitNode(parser, "onscript", parser.script)
-    parser.script = ""
-  }
 
-  // first make sure that the closing tag actually exists.
-  // <a><b></c></b></a> will close everything, otherwise.
-  var t = parser.tags.length
-  var tagName = parser.tagName
-  if (!parser.strict) tagName = tagName[parser.looseCase]()
-  var closeTo = tagName
-  while (t --) {
-    var close = parser.tags[t]
-    if (close.name !== closeTo) {
-      // fail the first time in strict mode
-      strictFail(parser, "Unexpected close tag")
-    } else break
-  }
+    if (parser.script) {
+      if (parser.tagName !== 'script') {
+        parser.script += '</' + parser.tagName + '>'
+        parser.tagName = ''
+        parser.state = S.SCRIPT
+        return
+      }
+      emitNode(parser, 'onscript', parser.script)
+      parser.script = ''
+    }
+
+    // first make sure that the closing tag actually exists.
+    // <a><b></c></b></a> will close everything, otherwise.
+    var t = parser.tags.length
+    var tagName = parser.tagName
+    if (!parser.strict) {
+      tagName = tagName[parser.looseCase]()
+    }
+    var closeTo = tagName
+    while (t--) {
+      var close = parser.tags[t]
+      if (close.name !== closeTo) {
+        // fail the first time in strict mode
+        strictFail(parser, 'Unexpected close tag')
+      } else {
+        break
+      }
+    }
 
-  // didn't find it.  we already failed for strict, so just abort.
-  if (t < 0) {
-    strictFail(parser, "Unmatched closing tag: "+parser.tagName)
-    parser.textNode += "</" + parser.tagName + ">"
+    // didn't find it.  we already failed for strict, so just abort.
+    if (t < 0) {
+      strictFail(parser, 'Unmatched closing tag: ' + parser.tagName)
+      parser.textNode += '</' + parser.tagName + '>'
+      parser.state = S.TEXT
+      return
+    }
+    parser.tagName = tagName
+    var s = parser.tags.length
+    while (s-- > t) {
+      var tag = parser.tag = parser.tags.pop()
+      parser.tagName = parser.tag.name
+      emitNode(parser, 'onclosetag', parser.tagName)
+
+      var x = {}
+      for (var i in tag.ns) {
+        x[i] = tag.ns[i]
+      }
+
+      var parent = parser.tags[parser.tags.length - 1] || parser
+      if (parser.opt.xmlns && tag.ns !== parent.ns) {
+        // remove namespace bindings introduced by tag
+        Object.keys(tag.ns).forEach(function (p) {
+          var n = tag.ns[p]
+          emitNode(parser, 'onclosenamespace', { prefix: p, uri: n })
+        })
+      }
+    }
+    if (t === 0) parser.closedRoot = true
+    parser.tagName = parser.attribValue = parser.attribName = ''
+    parser.attribList.length = 0
     parser.state = S.TEXT
-    return
   }
-  parser.tagName = tagName
-  var s = parser.tags.length
-  while (s --> t) {
-    var tag = parser.tag = parser.tags.pop()
-    parser.tagName = parser.tag.name
-    emitNode(parser, "onclosetag", parser.tagName)
 
-    var x = {}
-    for (var i in tag.ns) x[i] = tag.ns[i]
+  function parseEntity (parser) {
+    var entity = parser.entity
+    var entityLC = entity.toLowerCase()
+    var num
+    var numStr = ''
 
-    var parent = parser.tags[parser.tags.length - 1] || parser
-    if (parser.opt.xmlns && tag.ns !== parent.ns) {
-      // remove namespace bindings introduced by tag
-      Object.keys(tag.ns).forEach(function (p) {
-        var n = tag.ns[p]
-        emitNode(parser, "onclosenamespace", { prefix: p, uri: n })
-      })
+    if (parser.ENTITIES[entity]) {
+      return parser.ENTITIES[entity]
+    }
+    if (parser.ENTITIES[entityLC]) {
+      return parser.ENTITIES[entityLC]
+    }
+    entity = entityLC
+    if (entity.charAt(0) === '#') {
+      if (entity.charAt(1) === 'x') {
+        entity = entity.slice(2)
+        num = parseInt(entity, 16)
+        numStr = num.toString(16)
+      } else {
+        entity = entity.slice(1)
+        num = parseInt(entity, 10)
+        numStr = num.toString(10)
+      }
     }
+    entity = entity.replace(/^0+/, '')
+    if (isNaN(num) || numStr.toLowerCase() !== entity) {
+      strictFail(parser, 'Invalid character entity')
+      return '&' + parser.entity + ';'
+    }
+
+    return String.fromCodePoint(num)
   }
-  if (t === 0) parser.closedRoot = true
-  parser.tagName = parser.attribValue = parser.attribName = ""
-  parser.attribList.length = 0
-  parser.state = S.TEXT
-}
-
-function parseEntity (parser) {
-  var entity = parser.entity
-    , entityLC = entity.toLowerCase()
-    , num
-    , numStr = ""
-  if (parser.ENTITIES[entity])
-    return parser.ENTITIES[entity]
-  if (parser.ENTITIES[entityLC])
-    return parser.ENTITIES[entityLC]
-  entity = entityLC
-  if (entity.charAt(0) === "#") {
-    if (entity.charAt(1) === "x") {
-      entity = entity.slice(2)
-      num = parseInt(entity, 16)
-      numStr = num.toString(16)
-    } else {
-      entity = entity.slice(1)
-      num = parseInt(entity, 10)
-      numStr = num.toString(10)
+
+  function beginWhiteSpace (parser, c) {
+    if (c === '<') {
+      parser.state = S.OPEN_WAKA
+      parser.startTagPosition = parser.position
+    } else if (!isWhitespace(c)) {
+      // have to process this as a text node.
+      // weird, but happens.
+      strictFail(parser, 'Non-whitespace before first tag.')
+      parser.textNode = c
+      parser.state = S.TEXT
     }
   }
-  entity = entity.replace(/^0+/, "")
-  if (numStr.toLowerCase() !== entity) {
-    strictFail(parser, "Invalid character entity")
-    return "&"+parser.entity + ";"
+
+  function charAt (chunk, i) {
+    var result = ''
+    if (i < chunk.length) {
+      result = chunk.charAt(i)
+    }
+    return result
   }
-  return String.fromCharCode(num)
-}
-
-function write (chunk) {
-  var parser = this
-  if (this.error) throw this.error
-  if (parser.closed) return error(parser,
-    "Cannot write after close. Assign an onready handler.")
-  if (chunk === null) return end(parser)
-  var i = 0, c = ""
-  while (parser.c = c = chunk.charAt(i++)) {
-    if (parser.trackPosition) {
-      parser.position ++
-      if (c === "\n") {
-        parser.line ++
-        parser.column = 0
-      } else parser.column ++
+
+  function write (chunk) {
+    var parser = this
+    if (this.error) {
+      throw this.error
+    }
+    if (parser.closed) {
+      return error(parser,
+        'Cannot write after close. Assign an onready handler.')
+    }
+    if (chunk === null) {
+      return end(parser)
     }
-    switch (parser.state) {
-
-      case S.BEGIN:
-        if (c === "<") {
-          parser.state = S.OPEN_WAKA
-          parser.startTagPosition = parser.position
-        } else if (not(whitespace,c)) {
-          // have to process this as a text node.
-          // weird, but happens.
-          strictFail(parser, "Non-whitespace before first tag.")
-          parser.textNode = c
-          parser.state = S.TEXT
+    if (typeof chunk === 'object') {
+      chunk = chunk.toString()
+    }
+    var i = 0
+    var c = ''
+    while (true) {
+      c = charAt(chunk, i++)
+      parser.c = c
+
+      if (!c) {
+        break
+      }
+
+      if (parser.trackPosition) {
+        parser.position++
+        if (c === '\n') {
+          parser.line++
+          parser.column = 0
+        } else {
+          parser.column++
         }
-      continue
-
-      case S.TEXT:
-        if (parser.sawRoot && !parser.closedRoot) {
-          var starti = i-1
-          while (c && c!=="<" && c!=="&") {
-            c = chunk.charAt(i++)
-            if (c && parser.trackPosition) {
-              parser.position ++
-              if (c === "\n") {
-                parser.line ++
-                parser.column = 0
-              } else parser.column ++
+      }
+
+      switch (parser.state) {
+        case S.BEGIN:
+          parser.state = S.BEGIN_WHITESPACE
+          if (c === '\uFEFF') {
+            continue
+          }
+          beginWhiteSpace(parser, c)
+          continue
+
+        case S.BEGIN_WHITESPACE:
+          beginWhiteSpace(parser, c)
+          continue
+
+        case S.TEXT:
+          if (parser.sawRoot && !parser.closedRoot) {
+            var starti = i - 1
+            while (c && c !== '<' && c !== '&') {
+              c = charAt(chunk, i++)
+              if (c && parser.trackPosition) {
+                parser.position++
+                if (c === '\n') {
+                  parser.line++
+                  parser.column = 0
+                } else {
+                  parser.column++
+                }
+              }
             }
+            parser.textNode += chunk.substring(starti, i - 1)
           }
-          parser.textNode += chunk.substring(starti, i-1)
-        }
-        if (c === "<") {
-          parser.state = S.OPEN_WAKA
-          parser.startTagPosition = parser.position
-        } else {
-          if (not(whitespace, c) && (!parser.sawRoot || parser.closedRoot))
-            strictFail(parser, "Text data outside of root node.")
-          if (c === "&") parser.state = S.TEXT_ENTITY
-          else parser.textNode += c
-        }
-      continue
-
-      case S.SCRIPT:
-        // only non-strict
-        if (c === "<") {
-          parser.state = S.SCRIPT_ENDING
-        } else parser.script += c
-      continue
-
-      case S.SCRIPT_ENDING:
-        if (c === "/") {
-          parser.state = S.CLOSE_TAG
-        } else {
-          parser.script += "<" + c
-          parser.state = S.SCRIPT
-        }
-      continue
-
-      case S.OPEN_WAKA:
-        // either a /, ?, !, or text is coming next.
-        if (c === "!") {
-          parser.state = S.SGML_DECL
-          parser.sgmlDecl = ""
-        } else if (is(whitespace, c)) {
-          // wait for it...
-        } else if (is(nameStart,c)) {
-          parser.state = S.OPEN_TAG
-          parser.tagName = c
-        } else if (c === "/") {
-          parser.state = S.CLOSE_TAG
-          parser.tagName = ""
-        } else if (c === "?") {
-          parser.state = S.PROC_INST
-          parser.procInstName = parser.procInstBody = ""
-        } else {
-          strictFail(parser, "Unencoded <")
-          // if there was some whitespace, then add that in.
-          if (parser.startTagPosition + 1 < parser.position) {
-            var pad = parser.position - parser.startTagPosition
-            c = new Array(pad).join(" ") + c
+          if (c === '<' && !(parser.sawRoot && parser.closedRoot && !parser.strict)) {
+            parser.state = S.OPEN_WAKA
+            parser.startTagPosition = parser.position
+          } else {
+            if (!isWhitespace(c) && (!parser.sawRoot || parser.closedRoot)) {
+              strictFail(parser, 'Text data outside of root node.')
+            }
+            if (c === '&') {
+              parser.state = S.TEXT_ENTITY
+            } else {
+              parser.textNode += c
+            }
+          }
+          continue
+
+        case S.SCRIPT:
+          // only non-strict
+          if (c === '<') {
+            parser.state = S.SCRIPT_ENDING
+          } else {
+            parser.script += c
+          }
+          continue
+
+        case S.SCRIPT_ENDING:
+          if (c === '/') {
+            parser.state = S.CLOSE_TAG
+          } else {
+            parser.script += '<' + c
+            parser.state = S.SCRIPT
+          }
+          continue
+
+        case S.OPEN_WAKA:
+          // either a /, ?, !, or text is coming next.
+          if (c === '!') {
+            parser.state = S.SGML_DECL
+            parser.sgmlDecl = ''
+          } else if (isWhitespace(c)) {
+            // wait for it...
+          } else if (isMatch(nameStart, c)) {
+            parser.state = S.OPEN_TAG
+            parser.tagName = c
+          } else if (c === '/') {
+            parser.state = S.CLOSE_TAG
+            parser.tagName = ''
+          } else if (c === '?') {
+            parser.state = S.PROC_INST
+            parser.procInstName = parser.procInstBody = ''
+          } else {
+            strictFail(parser, 'Unencoded <')
+            // if there was some whitespace, then add that in.
+            if (parser.startTagPosition + 1 < parser.position) {
+              var pad = parser.position - parser.startTagPosition
+              c = new Array(pad).join(' ') + c
+            }
+            parser.textNode += '<' + c
+            parser.state = S.TEXT
+          }
+          continue
+
+        case S.SGML_DECL:
+          if ((parser.sgmlDecl + c).toUpperCase() === CDATA) {
+            emitNode(parser, 'onopencdata')
+            parser.state = S.CDATA
+            parser.sgmlDecl = ''
+            parser.cdata = ''
+          } else if (parser.sgmlDecl + c === '--') {
+            parser.state = S.COMMENT
+            parser.comment = ''
+            parser.sgmlDecl = ''
+          } else if ((parser.sgmlDecl + c).toUpperCase() === DOCTYPE) {
+            parser.state = S.DOCTYPE
+            if (parser.doctype || parser.sawRoot) {
+              strictFail(parser,
+                'Inappropriately located doctype declaration')
+            }
+            parser.doctype = ''
+            parser.sgmlDecl = ''
+          } else if (c === '>') {
+            emitNode(parser, 'onsgmldeclaration', parser.sgmlDecl)
+            parser.sgmlDecl = ''
+            parser.state = S.TEXT
+          } else if (isQuote(c)) {
+            parser.state = S.SGML_DECL_QUOTED
+            parser.sgmlDecl += c
+          } else {
+            parser.sgmlDecl += c
+          }
+          continue
+
+        case S.SGML_DECL_QUOTED:
+          if (c === parser.q) {
+            parser.state = S.SGML_DECL
+            parser.q = ''
           }
-          parser.textNode += "<" + c
-          parser.state = S.TEXT
-        }
-      continue
-
-      case S.SGML_DECL:
-        if ((parser.sgmlDecl+c).toUpperCase() === CDATA) {
-          emitNode(parser, "onopencdata")
-          parser.state = S.CDATA
-          parser.sgmlDecl = ""
-          parser.cdata = ""
-        } else if (parser.sgmlDecl+c === "--") {
-          parser.state = S.COMMENT
-          parser.comment = ""
-          parser.sgmlDecl = ""
-        } else if ((parser.sgmlDecl+c).toUpperCase() === DOCTYPE) {
-          parser.state = S.DOCTYPE
-          if (parser.doctype || parser.sawRoot) strictFail(parser,
-            "Inappropriately located doctype declaration")
-          parser.doctype = ""
-          parser.sgmlDecl = ""
-        } else if (c === ">") {
-          emitNode(parser, "onsgmldeclaration", parser.sgmlDecl)
-          parser.sgmlDecl = ""
-          parser.state = S.TEXT
-        } else if (is(quote, c)) {
-          parser.state = S.SGML_DECL_QUOTED
           parser.sgmlDecl += c
-        } else parser.sgmlDecl += c
-      continue
+          continue
 
-      case S.SGML_DECL_QUOTED:
-        if (c === parser.q) {
-          parser.state = S.SGML_DECL
-          parser.q = ""
-        }
-        parser.sgmlDecl += c
-      continue
-
-      case S.DOCTYPE:
-        if (c === ">") {
-          parser.state = S.TEXT
-          emitNode(parser, "ondoctype", parser.doctype)
-          parser.doctype = true // just remember that we saw it.
-        } else {
+        case S.DOCTYPE:
+          if (c === '>') {
+            parser.state = S.TEXT
+            emitNode(parser, 'ondoctype', parser.doctype)
+            parser.doctype = true // just remember that we saw it.
+          } else {
+            parser.doctype += c
+            if (c === '[') {
+              parser.state = S.DOCTYPE_DTD
+            } else if (isQuote(c)) {
+              parser.state = S.DOCTYPE_QUOTED
+              parser.q = c
+            }
+          }
+          continue
+
+        case S.DOCTYPE_QUOTED:
           parser.doctype += c
-          if (c === "[") parser.state = S.DOCTYPE_DTD
-          else if (is(quote, c)) {
-            parser.state = S.DOCTYPE_QUOTED
+          if (c === parser.q) {
+            parser.q = ''
+            parser.state = S.DOCTYPE
+          }
+          continue
+
+        case S.DOCTYPE_DTD:
+          parser.doctype += c
+          if (c === ']') {
+            parser.state = S.DOCTYPE
+          } else if (isQuote(c)) {
+            parser.state = S.DOCTYPE_DTD_QUOTED
             parser.q = c
           }
-        }
-      continue
+          continue
 
-      case S.DOCTYPE_QUOTED:
-        parser.doctype += c
-        if (c === parser.q) {
-          parser.q = ""
-          parser.state = S.DOCTYPE
-        }
-      continue
-
-      case S.DOCTYPE_DTD:
-        parser.doctype += c
-        if (c === "]") parser.state = S.DOCTYPE
-        else if (is(quote,c)) {
-          parser.state = S.DOCTYPE_DTD_QUOTED
-          parser.q = c
-        }
-      continue
+        case S.DOCTYPE_DTD_QUOTED:
+          parser.doctype += c
+          if (c === parser.q) {
+            parser.state = S.DOCTYPE_DTD
+            parser.q = ''
+          }
+          continue
 
-      case S.DOCTYPE_DTD_QUOTED:
-        parser.doctype += c
-        if (c === parser.q) {
-          parser.state = S.DOCTYPE_DTD
-          parser.q = ""
-        }
-      continue
-
-      case S.COMMENT:
-        if (c === "-") parser.state = S.COMMENT_ENDING
-        else parser.comment += c
-      continue
-
-      case S.COMMENT_ENDING:
-        if (c === "-") {
-          parser.state = S.COMMENT_ENDED
-          parser.comment = textopts(parser.opt, parser.comment)
-          if (parser.comment) emitNode(parser, "oncomment", parser.comment)
-          parser.comment = ""
-        } else {
-          parser.comment += "-" + c
-          parser.state = S.COMMENT
-        }
-      continue
-
-      case S.COMMENT_ENDED:
-        if (c !== ">") {
-          strictFail(parser, "Malformed comment")
-          // allow <!-- blah -- bloo --> in non-strict mode,
-          // which is a comment of " blah -- bloo "
-          parser.comment += "--" + c
-          parser.state = S.COMMENT
-        } else parser.state = S.TEXT
-      continue
-
-      case S.CDATA:
-        if (c === "]") parser.state = S.CDATA_ENDING
-        else parser.cdata += c
-      continue
-
-      case S.CDATA_ENDING:
-        if (c === "]") parser.state = S.CDATA_ENDING_2
-        else {
-          parser.cdata += "]" + c
-          parser.state = S.CDATA
-        }
-      continue
-
-      case S.CDATA_ENDING_2:
-        if (c === ">") {
-          if (parser.cdata) emitNode(parser, "oncdata", parser.cdata)
-          emitNode(parser, "onclosecdata")
-          parser.cdata = ""
-          parser.state = S.TEXT
-        } else if (c === "]") {
-          parser.cdata += "]"
-        } else {
-          parser.cdata += "]]" + c
-          parser.state = S.CDATA
-        }
-      continue
-
-      case S.PROC_INST:
-        if (c === "?") parser.state = S.PROC_INST_ENDING
-        else if (is(whitespace, c)) parser.state = S.PROC_INST_BODY
-        else parser.procInstName += c
-      continue
-
-      case S.PROC_INST_BODY:
-        if (!parser.procInstBody && is(whitespace, c)) continue
-        else if (c === "?") parser.state = S.PROC_INST_ENDING
-        else parser.procInstBody += c
-      continue
-
-      case S.PROC_INST_ENDING:
-        if (c === ">") {
-          emitNode(parser, "onprocessinginstruction", {
-            name : parser.procInstName,
-            body : parser.procInstBody
-          })
-          parser.procInstName = parser.procInstBody = ""
-          parser.state = S.TEXT
-        } else {
-          parser.procInstBody += "?" + c
-          parser.state = S.PROC_INST_BODY
-        }
-      continue
-
-      case S.OPEN_TAG:
-        if (is(nameBody, c)) parser.tagName += c
-        else {
-          newTag(parser)
-          if (c === ">") openTag(parser)
-          else if (c === "/") parser.state = S.OPEN_TAG_SLASH
-          else {
-            if (not(whitespace, c)) strictFail(
-              parser, "Invalid character in tag name")
+        case S.COMMENT:
+          if (c === '-') {
+            parser.state = S.COMMENT_ENDING
+          } else {
+            parser.comment += c
+          }
+          continue
+
+        case S.COMMENT_ENDING:
+          if (c === '-') {
+            parser.state = S.COMMENT_ENDED
+            parser.comment = textopts(parser.opt, parser.comment)
+            if (parser.comment) {
+              emitNode(parser, 'oncomment', parser.comment)
+            }
+            parser.comment = ''
+          } else {
+            parser.comment += '-' + c
+            parser.state = S.COMMENT
+          }
+          continue
+
+        case S.COMMENT_ENDED:
+          if (c !== '>') {
+            strictFail(parser, 'Malformed comment')
+            // allow <!-- blah -- bloo --> in non-strict mode,
+            // which is a comment of " blah -- bloo "
+            parser.comment += '--' + c
+            parser.state = S.COMMENT
+          } else {
+            parser.state = S.TEXT
+          }
+          continue
+
+        case S.CDATA:
+          if (c === ']') {
+            parser.state = S.CDATA_ENDING
+          } else {
+            parser.cdata += c
+          }
+          continue
+
+        case S.CDATA_ENDING:
+          if (c === ']') {
+            parser.state = S.CDATA_ENDING_2
+          } else {
+            parser.cdata += ']' + c
+            parser.state = S.CDATA
+          }
+          continue
+
+        case S.CDATA_ENDING_2:
+          if (c === '>') {
+            if (parser.cdata) {
+              emitNode(parser, 'oncdata', parser.cdata)
+            }
+            emitNode(parser, 'onclosecdata')
+            parser.cdata = ''
+            parser.state = S.TEXT
+          } else if (c === ']') {
+            parser.cdata += ']'
+          } else {
+            parser.cdata += ']]' + c
+            parser.state = S.CDATA
+          }
+          continue
+
+        case S.PROC_INST:
+          if (c === '?') {
+            parser.state = S.PROC_INST_ENDING
+          } else if (isWhitespace(c)) {
+            parser.state = S.PROC_INST_BODY
+          } else {
+            parser.procInstName += c
+          }
+          continue
+
+        case S.PROC_INST_BODY:
+          if (!parser.procInstBody && isWhitespace(c)) {
+            continue
+          } else if (c === '?') {
+            parser.state = S.PROC_INST_ENDING
+          } else {
+            parser.procInstBody += c
+          }
+          continue
+
+        case S.PROC_INST_ENDING:
+          if (c === '>') {
+            emitNode(parser, 'onprocessinginstruction', {
+              name: parser.procInstName,
+              body: parser.procInstBody
+            })
+            parser.procInstName = parser.procInstBody = ''
+            parser.state = S.TEXT
+          } else {
+            parser.procInstBody += '?' + c
+            parser.state = S.PROC_INST_BODY
+          }
+          continue
+
+        case S.OPEN_TAG:
+          if (isMatch(nameBody, c)) {
+            parser.tagName += c
+          } else {
+            newTag(parser)
+            if (c === '>') {
+              openTag(parser)
+            } else if (c === '/') {
+              parser.state = S.OPEN_TAG_SLASH
+            } else {
+              if (!isWhitespace(c)) {
+                strictFail(parser, 'Invalid character in tag name')
+              }
+              parser.state = S.ATTRIB
+            }
+          }
+          continue
+
+        case S.OPEN_TAG_SLASH:
+          if (c === '>') {
+            openTag(parser, true)
+            closeTag(parser)
+          } else {
+            strictFail(parser, 'Forward-slash in opening tag not followed by >')
             parser.state = S.ATTRIB
           }
-        }
-      continue
+          continue
 
-      case S.OPEN_TAG_SLASH:
-        if (c === ">") {
-          openTag(parser, true)
-          closeTag(parser)
-        } else {
-          strictFail(parser, "Forward-slash in opening tag not followed by >")
-          parser.state = S.ATTRIB
-        }
-      continue
-
-      case S.ATTRIB:
-        // haven't read the attribute name yet.
-        if (is(whitespace, c)) continue
-        else if (c === ">") openTag(parser)
-        else if (c === "/") parser.state = S.OPEN_TAG_SLASH
-        else if (is(nameStart, c)) {
-          parser.attribName = c
-          parser.attribValue = ""
-          parser.state = S.ATTRIB_NAME
-        } else strictFail(parser, "Invalid attribute name")
-      continue
-
-      case S.ATTRIB_NAME:
-        if (c === "=") parser.state = S.ATTRIB_VALUE
-        else if (c === ">") {
-          strictFail(parser, "Attribute without value")
-          parser.attribValue = parser.attribName
-          attrib(parser)
-          openTag(parser)
-        }
-        else if (is(whitespace, c)) parser.state = S.ATTRIB_NAME_SAW_WHITE
-        else if (is(nameBody, c)) parser.attribName += c
-        else strictFail(parser, "Invalid attribute name")
-      continue
-
-      case S.ATTRIB_NAME_SAW_WHITE:
-        if (c === "=") parser.state = S.ATTRIB_VALUE
-        else if (is(whitespace, c)) continue
-        else {
-          strictFail(parser, "Attribute without value")
-          parser.tag.attributes[parser.attribName] = ""
-          parser.attribValue = ""
-          emitNode(parser, "onattribute",
-                   { name : parser.attribName, value : "" })
-          parser.attribName = ""
-          if (c === ">") openTag(parser)
-          else if (is(nameStart, c)) {
+        case S.ATTRIB:
+          // haven't read the attribute name yet.
+          if (isWhitespace(c)) {
+            continue
+          } else if (c === '>') {
+            openTag(parser)
+          } else if (c === '/') {
+            parser.state = S.OPEN_TAG_SLASH
+          } else if (isMatch(nameStart, c)) {
             parser.attribName = c
+            parser.attribValue = ''
             parser.state = S.ATTRIB_NAME
           } else {
-            strictFail(parser, "Invalid attribute name")
-            parser.state = S.ATTRIB
+            strictFail(parser, 'Invalid attribute name')
           }
-        }
-      continue
+          continue
 
-      case S.ATTRIB_VALUE:
-        if (is(whitespace, c)) continue
-        else if (is(quote, c)) {
-          parser.q = c
-          parser.state = S.ATTRIB_VALUE_QUOTED
-        } else {
-          strictFail(parser, "Unquoted attribute value")
-          parser.state = S.ATTRIB_VALUE_UNQUOTED
-          parser.attribValue = c
-        }
-      continue
+        case S.ATTRIB_NAME:
+          if (c === '=') {
+            parser.state = S.ATTRIB_VALUE
+          } else if (c === '>') {
+            strictFail(parser, 'Attribute without value')
+            parser.attribValue = parser.attribName
+            attrib(parser)
+            openTag(parser)
+          } else if (isWhitespace(c)) {
+            parser.state = S.ATTRIB_NAME_SAW_WHITE
+          } else if (isMatch(nameBody, c)) {
+            parser.attribName += c
+          } else {
+            strictFail(parser, 'Invalid attribute name')
+          }
+          continue
 
-      case S.ATTRIB_VALUE_QUOTED:
-        if (c !== parser.q) {
-          if (c === "&") parser.state = S.ATTRIB_VALUE_ENTITY_Q
-          else parser.attribValue += c
+        case S.ATTRIB_NAME_SAW_WHITE:
+          if (c === '=') {
+            parser.state = S.ATTRIB_VALUE
+          } else if (isWhitespace(c)) {
+            continue
+          } else {
+            strictFail(parser, 'Attribute without value')
+            parser.tag.attributes[parser.attribName] = ''
+            parser.attribValue = ''
+            emitNode(parser, 'onattribute', {
+              name: parser.attribName,
+              value: ''
+            })
+            parser.attribName = ''
+            if (c === '>') {
+              openTag(parser)
+            } else if (isMatch(nameStart, c)) {
+              parser.attribName = c
+              parser.state = S.ATTRIB_NAME
+            } else {
+              strictFail(parser, 'Invalid attribute name')
+              parser.state = S.ATTRIB
+            }
+          }
           continue
-        }
-        attrib(parser)
-        parser.q = ""
-        parser.state = S.ATTRIB
-      continue
-
-      case S.ATTRIB_VALUE_UNQUOTED:
-        if (not(attribEnd,c)) {
-          if (c === "&") parser.state = S.ATTRIB_VALUE_ENTITY_U
-          else parser.attribValue += c
+
+        case S.ATTRIB_VALUE:
+          if (isWhitespace(c)) {
+            continue
+          } else if (isQuote(c)) {
+            parser.q = c
+            parser.state = S.ATTRIB_VALUE_QUOTED
+          } else {
+            strictFail(parser, 'Unquoted attribute value')
+            parser.state = S.ATTRIB_VALUE_UNQUOTED
+            parser.attribValue = c
+          }
           continue
-        }
-        attrib(parser)
-        if (c === ">") openTag(parser)
-        else parser.state = S.ATTRIB
-      continue
-
-      case S.CLOSE_TAG:
-        if (!parser.tagName) {
-          if (is(whitespace, c)) continue
-          else if (not(nameStart, c)) {
-            if (parser.script) {
-              parser.script += "</" + c
-              parser.state = S.SCRIPT
+
+        case S.ATTRIB_VALUE_QUOTED:
+          if (c !== parser.q) {
+            if (c === '&') {
+              parser.state = S.ATTRIB_VALUE_ENTITY_Q
             } else {
-              strictFail(parser, "Invalid tagname in closing tag.")
+              parser.attribValue += c
             }
-          } else parser.tagName = c
-        }
-        else if (c === ">") closeTag(parser)
-        else if (is(nameBody, c)) parser.tagName += c
-        else if (parser.script) {
-          parser.script += "</" + parser.tagName
-          parser.tagName = ""
-          parser.state = S.SCRIPT
-        } else {
-          if (not(whitespace, c)) strictFail(parser,
-            "Invalid tagname in closing tag")
-          parser.state = S.CLOSE_TAG_SAW_WHITE
-        }
-      continue
-
-      case S.CLOSE_TAG_SAW_WHITE:
-        if (is(whitespace, c)) continue
-        if (c === ">") closeTag(parser)
-        else strictFail(parser, "Invalid characters in closing tag")
-      continue
-
-      case S.TEXT_ENTITY:
-      case S.ATTRIB_VALUE_ENTITY_Q:
-      case S.ATTRIB_VALUE_ENTITY_U:
-        switch(parser.state) {
-          case S.TEXT_ENTITY:
-            var returnState = S.TEXT, buffer = "textNode"
-          break
-
-          case S.ATTRIB_VALUE_ENTITY_Q:
-            var returnState = S.ATTRIB_VALUE_QUOTED, buffer = "attribValue"
-          break
-
-          case S.ATTRIB_VALUE_ENTITY_U:
-            var returnState = S.ATTRIB_VALUE_UNQUOTED, buffer = "attribValue"
-          break
-        }
-        if (c === ";") {
-          parser[buffer] += parseEntity(parser)
-          parser.entity = ""
-          parser.state = returnState
-        }
-        else if (is(entity, c)) parser.entity += c
-        else {
-          strictFail(parser, "Invalid character entity")
-          parser[buffer] += "&" + parser.entity + c
-          parser.entity = ""
-          parser.state = returnState
-        }
-      continue
+            continue
+          }
+          attrib(parser)
+          parser.q = ''
+          parser.state = S.ATTRIB_VALUE_CLOSED
+          continue
+
+        case S.ATTRIB_VALUE_CLOSED:
+          if (isWhitespace(c)) {
+            parser.state = S.ATTRIB
+          } else if (c === '>') {
+            openTag(parser)
+          } else if (c === '/') {
+            parser.state = S.OPEN_TAG_SLASH
+          } else if (isMatch(nameStart, c)) {
+            strictFail(parser, 'No whitespace between attributes')
+            parser.attribName = c
+            parser.attribValue = ''
+            parser.state = S.ATTRIB_NAME
+          } else {
+            strictFail(parser, 'Invalid attribute name')
+          }
+          continue
+
+        case S.ATTRIB_VALUE_UNQUOTED:
+          if (!isAttribEnd(c)) {
+            if (c === '&') {
+              parser.state = S.ATTRIB_VALUE_ENTITY_U
+            } else {
+              parser.attribValue += c
+            }
+            continue
+          }
+          attrib(parser)
+          if (c === '>') {
+            openTag(parser)
+          } else {
+            parser.state = S.ATTRIB
+          }
+          continue
+
+        case S.CLOSE_TAG:
+          if (!parser.tagName) {
+            if (isWhitespace(c)) {
+              continue
+            } else if (notMatch(nameStart, c)) {
+              if (parser.script) {
+                parser.script += '</' + c
+                parser.state = S.SCRIPT
+              } else {
+                strictFail(parser, 'Invalid tagname in closing tag.')
+              }
+            } else {
+              parser.tagName = c
+            }
+          } else if (c === '>') {
+            closeTag(parser)
+          } else if (isMatch(nameBody, c)) {
+            parser.tagName += c
+          } else if (parser.script) {
+            parser.script += '</' + parser.tagName
+            parser.tagName = ''
+            parser.state = S.SCRIPT
+          } else {
+            if (!isWhitespace(c)) {
+              strictFail(parser, 'Invalid tagname in closing tag')
+            }
+            parser.state = S.CLOSE_TAG_SAW_WHITE
+          }
+          continue
+
+        case S.CLOSE_TAG_SAW_WHITE:
+          if (isWhitespace(c)) {
+            continue
+          }
+          if (c === '>') {
+            closeTag(parser)
+          } else {
+            strictFail(parser, 'Invalid characters in closing tag')
+          }
+          continue
+
+        case S.TEXT_ENTITY:
+        case S.ATTRIB_VALUE_ENTITY_Q:
+        case S.ATTRIB_VALUE_ENTITY_U:
+          var returnState
+          var buffer
+          switch (parser.state) {
+            case S.TEXT_ENTITY:
+              returnState = S.TEXT
+              buffer = 'textNode'
+              break
+
+            case S.ATTRIB_VALUE_ENTITY_Q:
+              returnState = S.ATTRIB_VALUE_QUOTED
+              buffer = 'attribValue'
+              break
+
+            case S.ATTRIB_VALUE_ENTITY_U:
+              returnState = S.ATTRIB_VALUE_UNQUOTED
+              buffer = 'attribValue'
+              break
+          }
+
+          if (c === ';') {
+            parser[buffer] += parseEntity(parser)
+            parser.entity = ''
+            parser.state = returnState
+          } else if (isMatch(parser.entity.length ? entityBody : entityStart, c)) {
+            parser.entity += c
+          } else {
+            strictFail(parser, 'Invalid character in entity name')
+            parser[buffer] += '&' + parser.entity + c
+            parser.entity = ''
+            parser.state = returnState
+          }
+
+          continue
+
+        default:
+          throw new Error(parser, 'Unknown state: ' + parser.state)
+      }
+    } // while
 
-      default:
-        throw new Error(parser, "Unknown state: " + parser.state)
+    if (parser.position >= parser.bufferCheckPosition) {
+      checkBufferLength(parser)
     }
-  } // while
-  // cdata blocks can get very big under normal conditions. emit and move on.
-  // if (parser.state === S.CDATA && parser.cdata) {
-  //   emitNode(parser, "oncdata", parser.cdata)
-  //   parser.cdata = ""
-  // }
-  if (parser.position >= parser.bufferCheckPosition) checkBufferLength(parser)
-  return parser
-}
-
-})(typeof exports === "undefined" ? sax = {} : exports)
+    return parser
+  }
+
+  /*! http://mths.be/fromcodepoint v0.1.0 by @mathias */
+  /* istanbul ignore next */
+  if (!String.fromCodePoint) {
+    (function () {
+      var stringFromCharCode = String.fromCharCode
+      var floor = Math.floor
+      var fromCodePoint = function () {
+        var MAX_SIZE = 0x4000
+        var codeUnits = []
+        var highSurrogate
+        var lowSurrogate
+        var index = -1
+        var length = arguments.length
+        if (!length) {
+          return ''
+        }
+        var result = ''
+        while (++index < length) {
+          var codePoint = Number(arguments[index])
+          if (
+            !isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
+            codePoint < 0 || // not a valid Unicode code point
+            codePoint > 0x10FFFF || // not a valid Unicode code point
+            floor(codePoint) !== codePoint // not an integer
+          ) {
+            throw RangeError('Invalid code point: ' + codePoint)
+          }
+          if (codePoint <= 0xFFFF) { // BMP code point
+            codeUnits.push(codePoint)
+          } else { // Astral code point; split in surrogate halves
+            // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+            codePoint -= 0x10000
+            highSurrogate = (codePoint >> 10) + 0xD800
+            lowSurrogate = (codePoint % 0x400) + 0xDC00
+            codeUnits.push(highSurrogate, lowSurrogate)
+          }
+          if (index + 1 === length || codeUnits.length > MAX_SIZE) {
+            result += stringFromCharCode.apply(null, codeUnits)
+            codeUnits.length = 0
+          }
+        }
+        return result
+      }
+      /* istanbul ignore next */
+      if (Object.defineProperty) {
+        Object.defineProperty(String, 'fromCodePoint', {
+          value: fromCodePoint,
+          configurable: true,
+          writable: true
+        })
+      } else {
+        String.fromCodePoint = fromCodePoint
+      }
+    }())
+  }
+})(typeof exports === 'undefined' ? this.sax = {} : exports)
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..d3febe7
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,2604 @@
+{
+  "name": "sax",
+  "version": "1.2.4",
+  "lockfileVersion": 1,
+  "dependencies": {
+    "acorn": {
+      "version": "https://registry.npmjs.org/acorn/-/acorn-4.0.4.tgz",
+      "integrity": "sha1-F6jWp6bE71OLgU7Jq6wneSk78wo=",
+      "dev": true
+    },
+    "acorn-jsx": {
+      "version": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
+      "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
+      "dev": true,
+      "dependencies": {
+        "acorn": {
+          "version": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
+          "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
+          "dev": true
+        }
+      }
+    },
+    "ajv": {
+      "version": "https://registry.npmjs.org/ajv/-/ajv-4.11.2.tgz",
+      "integrity": "sha1-8WbDwRy8bLncwQKlvP5bcslSh+Y=",
+      "dev": true
+    },
+    "ajv-keywords": {
+      "version": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz",
+      "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=",
+      "dev": true
+    },
+    "ansi-escapes": {
+      "version": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
+      "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
+      "dev": true
+    },
+    "ansi-regex": {
+      "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz",
+      "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=",
+      "dev": true
+    },
+    "ansi-styles": {
+      "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz",
+      "integrity": "sha1-mQ90cUaSe1Wakyv5KVkWPWDA0OI=",
+      "dev": true
+    },
+    "argparse": {
+      "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
+      "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=",
+      "dev": true
+    },
+    "array-union": {
+      "version": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+      "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+      "dev": true
+    },
+    "array-uniq": {
+      "version": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+      "dev": true
+    },
+    "arrify": {
+      "version": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+      "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+      "dev": true
+    },
+    "asn1": {
+      "version": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
+      "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
+      "dev": true
+    },
+    "assert-plus": {
+      "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
+      "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=",
+      "dev": true
+    },
+    "asynckit": {
+      "version": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+      "dev": true
+    },
+    "aws-sign2": {
+      "version": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
+      "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=",
+      "dev": true
+    },
+    "aws4": {
+      "version": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
+      "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
+      "dev": true
+    },
+    "babel-code-frame": {
+      "version": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz",
+      "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=",
+      "dev": true,
+      "dependencies": {
+        "esutils": {
+          "version": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+          "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+          "dev": true
+        }
+      }
+    },
+    "balanced-match": {
+      "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz",
+      "integrity": "sha1-qRzdHr7xqGZZ5w/03vAWJfwtZ1Y=",
+      "dev": true
+    },
+    "bcrypt-pbkdf": {
+      "version": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
+      "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
+      "dev": true,
+      "optional": true
+    },
+    "bind-obj-methods": {
+      "version": "https://registry.npmjs.org/bind-obj-methods/-/bind-obj-methods-1.0.0.tgz",
+      "integrity": "sha1-T1l5ysFXk633DkiBYeRj4gnKUJw=",
+      "dev": true
+    },
+    "bluebird": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz",
+      "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=",
+      "dev": true
+    },
+    "boom": {
+      "version": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
+      "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
+      "dev": true
+    },
+    "brace-expansion": {
+      "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz",
+      "integrity": "sha1-Rr/1ARXUf8mriYVKu4fZgHihCZE=",
+      "dev": true
+    },
+    "buffer-shims": {
+      "version": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz",
+      "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=",
+      "dev": true
+    },
+    "caller-path": {
+      "version": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
+      "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
+      "dev": true
+    },
+    "callsites": {
+      "version": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
+      "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
+      "dev": true
+    },
+    "caseless": {
+      "version": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
+      "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=",
+      "dev": true
+    },
+    "chalk": {
+      "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz",
+      "integrity": "sha1-UJr7ZwZudJn36zU1x3RFdyri0Bk=",
+      "dev": true,
+      "dependencies": {
+        "supports-color": {
+          "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+          "dev": true
+        }
+      }
+    },
+    "circular-json": {
+      "version": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz",
+      "integrity": "sha1-vos2rvzN6LPKeqLWr8B6NyQsDS0=",
+      "dev": true
+    },
+    "clean-yaml-object": {
+      "version": "https://registry.npmjs.org/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz",
+      "integrity": "sha1-Y/sRDcLOGoTcIfbZM0h20BCui2g=",
+      "dev": true
+    },
+    "cli-cursor": {
+      "version": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
+      "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=",
+      "dev": true
+    },
+    "cli-width": {
+      "version": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz",
+      "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=",
+      "dev": true
+    },
+    "co": {
+      "version": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+      "dev": true
+    },
+    "code-point-at": {
+      "version": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.0.0.tgz",
+      "integrity": "sha1-9psZLT99keOC5Lcb3bd4eGGasMY=",
+      "dev": true
+    },
+    "color-support": {
+      "version": "https://registry.npmjs.org/color-support/-/color-support-1.1.2.tgz",
+      "integrity": "sha1-ScyZuJ0b3vEpLp2TI8ZpcaM+uJ0=",
+      "dev": true
+    },
+    "combined-stream": {
+      "version": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
+      "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "concat-stream": {
+      "version": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz",
+      "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=",
+      "dev": true,
+      "dependencies": {
+        "inherits": {
+          "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+          "dev": true
+        },
+        "isarray": {
+          "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "process-nextick-args": {
+          "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+          "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz",
+          "integrity": "sha1-qeb+w8fdqF+LsbO6cChgRVb8gl4=",
+          "dev": true
+        }
+      }
+    },
+    "core-util-is": {
+      "version": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
+    },
+    "coveralls": {
+      "version": "https://registry.npmjs.org/coveralls/-/coveralls-2.11.16.tgz",
+      "integrity": "sha1-2pBhJlFC3e6VT2g3kSK+l76KtLE=",
+      "dev": true,
+      "dependencies": {
+        "esprima": {
+          "version": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+          "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+          "dev": true
+        },
+        "js-yaml": {
+          "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz",
+          "integrity": "sha1-bl/mfYsgXOTSL60Ft3geja3MSzA=",
+          "dev": true
+        },
+        "minimist": {
+          "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        }
+      }
+    },
+    "cross-spawn": {
+      "version": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
+      "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": {
+          "version": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz",
+          "integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=",
+          "dev": true
+        },
+        "which": {
+          "version": "https://registry.npmjs.org/which/-/which-1.2.12.tgz",
+          "integrity": "sha1-3me15FAmnxlJCe8j7OTr5Bb6EZI=",
+          "dev": true
+        }
+      }
+    },
+    "cryptiles": {
+      "version": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
+      "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
+      "dev": true
+    },
+    "d": {
+      "version": "https://registry.npmjs.org/d/-/d-0.1.1.tgz",
+      "integrity": "sha1-2hhMU10Y2O57oqoim5FACfrhEwk=",
+      "dev": true
+    },
+    "dashdash": {
+      "version": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+      "dev": true,
+      "dependencies": {
+        "assert-plus": {
+          "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+          "dev": true
+        }
+      }
+    },
+    "debug": {
+      "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+      "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+      "dev": true
+    },
+    "debug-log": {
+      "version": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz",
+      "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=",
+      "dev": true
+    },
+    "deep-is": {
+      "version": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+      "dev": true
+    },
+    "deglob": {
+      "version": "https://registry.npmjs.org/deglob/-/deglob-2.1.0.tgz",
+      "integrity": "sha1-TUSr4W7zLHebSXK9FBqAMlApoUo=",
+      "dev": true,
+      "dependencies": {
+        "glob": {
+          "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
+          "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=",
+          "dev": true
+        },
+        "minimatch": {
+          "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz",
+          "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=",
+          "dev": true
+        }
+      }
+    },
+    "del": {
+      "version": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
+      "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
+      "dev": true
+    },
+    "delayed-stream": {
+      "version": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+      "dev": true
+    },
+    "diff": {
+      "version": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz",
+      "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=",
+      "dev": true
+    },
+    "doctrine": {
+      "version": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
+      "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
+      "dev": true,
+      "dependencies": {
+        "esutils": {
+          "version": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+          "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+          "dev": true
+        },
+        "isarray": {
+          "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        }
+      }
+    },
+    "ecc-jsbn": {
+      "version": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
+      "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+      "dev": true,
+      "optional": true
+    },
+    "es5-ext": {
+      "version": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.8.tgz",
+      "integrity": "sha1-9IxDQk+nx9lvkD4pSHBc+Cb2nDI=",
+      "dev": true
+    },
+    "es6-iterator": {
+      "version": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.0.tgz",
+      "integrity": "sha1-vZaFZ9YWNeM8C4BydhPJy0sJa6w=",
+      "dev": true
+    },
+    "es6-map": {
+      "version": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.4.tgz",
+      "integrity": "sha1-o0sUe+IkdzpNfagHJ5TO+jYyuJc=",
+      "dev": true,
+      "dependencies": {
+        "es5-ext": {
+          "version": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.12.tgz",
+          "integrity": "sha1-qoRkHU23a2Krul5F/YBey6sUAEc=",
+          "dev": true
+        },
+        "es6-symbol": {
+          "version": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz",
+          "integrity": "sha1-lEgcZV56fK2C66gy2X1UM0ltf/o=",
+          "dev": true
+        }
+      }
+    },
+    "es6-set": {
+      "version": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.4.tgz",
+      "integrity": "sha1-lRa2dhwpZLkv9HlFYjOiR9xwfOg=",
+      "dev": true,
+      "dependencies": {
+        "es5-ext": {
+          "version": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.12.tgz",
+          "integrity": "sha1-qoRkHU23a2Krul5F/YBey6sUAEc=",
+          "dev": true,
+          "dependencies": {
+            "es6-symbol": {
+              "version": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz",
+              "integrity": "sha1-lEgcZV56fK2C66gy2X1UM0ltf/o=",
+              "dev": true
+            }
+          }
+        }
+      }
+    },
+    "es6-symbol": {
+      "version": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.0.0.tgz",
+      "integrity": "sha1-PsMQg0pQqiRBqTVaRjYNmSQlzrg=",
+      "dev": true
+    },
+    "es6-weak-map": {
+      "version": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.1.tgz",
+      "integrity": "sha1-DSu9iCfrX7S6j5f7/qUNQ9sh6oE=",
+      "dev": true
+    },
+    "escape-string-regexp": {
+      "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz",
+      "integrity": "sha1-ni2LJbwlVcMzZyN1DgPwmcJzW7U=",
+      "dev": true
+    },
+    "escope": {
+      "version": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
+      "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
+      "dev": true,
+      "dependencies": {
+        "estraverse": {
+          "version": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+          "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+          "dev": true
+        }
+      }
+    },
+    "eslint": {
+      "version": "https://registry.npmjs.org/eslint/-/eslint-3.10.2.tgz",
+      "integrity": "sha1-yaEOi/bp1lZRIEd4xQM0Hx6sPOc=",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": {
+          "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true
+        },
+        "estraverse": {
+          "version": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+          "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+          "dev": true
+        },
+        "esutils": {
+          "version": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+          "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+          "dev": true
+        },
+        "fast-levenshtein": {
+          "version": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+          "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+          "dev": true
+        },
+        "glob": {
+          "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
+          "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=",
+          "dev": true
+        },
+        "js-yaml": {
+          "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.1.tgz",
+          "integrity": "sha1-eCulAgC+e55ahTcAG3gE2zrQJig=",
+          "dev": true
+        },
+        "levn": {
+          "version": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+          "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+          "dev": true
+        },
+        "lodash": {
+          "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+          "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
+          "dev": true
+        },
+        "minimatch": {
+          "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz",
+          "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=",
+          "dev": true
+        },
+        "optionator": {
+          "version": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+          "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+          "dev": true
+        },
+        "strip-bom": {
+          "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+          "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+          "dev": true
+        },
+        "type-check": {
+          "version": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+          "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+          "dev": true
+        }
+      }
+    },
+    "eslint-config-standard": {
+      "version": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-6.2.1.tgz",
+      "integrity": "sha1-06aKr8cZFjnn7kQec0hzkCY1QpI=",
+      "dev": true
+    },
+    "eslint-config-standard-jsx": {
+      "version": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-3.2.0.tgz",
+      "integrity": "sha1-wkDibtkZoRpCqk3oBZRys4Jo1iA=",
+      "dev": true
+    },
+    "eslint-plugin-promise": {
+      "version": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.4.1.tgz",
+      "integrity": "sha1-aRGpAQv4ThfYLhngqw+AqzrW20w=",
+      "dev": true
+    },
+    "eslint-plugin-react": {
+      "version": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.7.1.tgz",
+      "integrity": "sha1-Gvlq6lRYVoJRV9l8G1DVqPtkpac=",
+      "dev": true
+    },
+    "eslint-plugin-standard": {
+      "version": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-2.0.1.tgz",
+      "integrity": "sha1-NYlpn/nJF/LCX3apFmh/ZBw2n/M=",
+      "dev": true
+    },
+    "espree": {
+      "version": "https://registry.npmjs.org/espree/-/espree-3.4.0.tgz",
+      "integrity": "sha1-QWVvpWKOBCh4Al70Z+ePEly4bh0=",
+      "dev": true
+    },
+    "esprima": {
+      "version": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+      "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=",
+      "dev": true
+    },
+    "esrecurse": {
+      "version": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz",
+      "integrity": "sha1-RxO2U2rffyrE8yfVWed1a/9kgiA=",
+      "dev": true,
+      "dependencies": {
+        "estraverse": {
+          "version": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz",
+          "integrity": "sha1-9srKcokzqFDvkGYdDheYK6RxEaI=",
+          "dev": true
+        }
+      }
+    },
+    "event-emitter": {
+      "version": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.4.tgz",
+      "integrity": "sha1-jWPd+0z+H647MsomXExyAiIIC7U=",
+      "dev": true
+    },
+    "events-to-array": {
+      "version": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.0.2.tgz",
+      "integrity": "sha1-s0hEZVNP5P9m+90ag7d3cTukBKo=",
+      "dev": true
+    },
+    "exit-hook": {
+      "version": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
+      "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
+      "dev": true
+    },
+    "extsprintf": {
+      "version": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz",
+      "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=",
+      "dev": true
+    },
+    "figures": {
+      "version": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+      "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+      "dev": true,
+      "dependencies": {
+        "escape-string-regexp": {
+          "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+          "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+          "dev": true
+        }
+      }
+    },
+    "file-entry-cache": {
+      "version": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
+      "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
+      "dev": true
+    },
+    "find-root": {
+      "version": "https://registry.npmjs.org/find-root/-/find-root-1.0.0.tgz",
+      "integrity": "sha1-li/yEaqyXGUg/u641ih/j26VgHo=",
+      "dev": true
+    },
+    "flat-cache": {
+      "version": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz",
+      "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=",
+      "dev": true
+    },
+    "foreground-child": {
+      "version": "1.5.6",
+      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz",
+      "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=",
+      "dev": true,
+      "dependencies": {
+        "signal-exit": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+          "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+          "dev": true
+        }
+      }
+    },
+    "forever-agent": {
+      "version": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+      "dev": true
+    },
+    "form-data": {
+      "version": "https://registry.npmjs.org/form-data/-/form-data-2.1.2.tgz",
+      "integrity": "sha1-icNTQAi5fq2ky7FX1Y9vXfAl6uQ=",
+      "dev": true
+    },
+    "fs-exists-cached": {
+      "version": "https://registry.npmjs.org/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz",
+      "integrity": "sha1-zyVVTKBQ3EmuZla0HeQiWJidy84=",
+      "dev": true
+    },
+    "fs.realpath": {
+      "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "function-loop": {
+      "version": "https://registry.npmjs.org/function-loop/-/function-loop-1.0.1.tgz",
+      "integrity": "sha1-gHa7MF6OajzO7ikgdl8zDRkPNAw=",
+      "dev": true
+    },
+    "generate-function": {
+      "version": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
+      "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=",
+      "dev": true
+    },
+    "generate-object-property": {
+      "version": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
+      "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
+      "dev": true
+    },
+    "get-stdin": {
+      "version": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz",
+      "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=",
+      "dev": true
+    },
+    "getpass": {
+      "version": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz",
+      "integrity": "sha1-KD/9n8ElaECHUxHBtg6MQBhxEOY=",
+      "dev": true,
+      "dependencies": {
+        "assert-plus": {
+          "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+          "dev": true
+        }
+      }
+    },
+    "glob": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+      "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+      "dev": true
+    },
+    "globals": {
+      "version": "https://registry.npmjs.org/globals/-/globals-9.14.0.tgz",
+      "integrity": "sha1-iFmTavADh0EmMFOznQ52yiQeQDQ=",
+      "dev": true
+    },
+    "globby": {
+      "version": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
+      "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
+      "dev": true,
+      "dependencies": {
+        "glob": {
+          "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
+          "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=",
+          "dev": true
+        },
+        "minimatch": {
+          "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz",
+          "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=",
+          "dev": true
+        }
+      }
+    },
+    "graceful-fs": {
+      "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+      "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
+      "dev": true
+    },
+    "graceful-readlink": {
+      "version": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+      "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
+      "dev": true
+    },
+    "har-validator": {
+      "version": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
+      "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=",
+      "dev": true,
+      "dependencies": {
+        "commander": {
+          "version": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+          "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
+          "dev": true
+        },
+        "is-my-json-valid": {
+          "version": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz",
+          "integrity": "sha1-k27do8o8IR/ZjzstPgjaQ/eykVs=",
+          "dev": true
+        },
+        "jsonpointer": {
+          "version": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
+          "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
+          "dev": true
+        },
+        "pinkie": {
+          "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+          "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+          "dev": true
+        },
+        "pinkie-promise": {
+          "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+          "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+          "dev": true
+        }
+      }
+    },
+    "has-ansi": {
+      "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "dev": true
+    },
+    "hawk": {
+      "version": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
+      "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
+      "dev": true
+    },
+    "hoek": {
+      "version": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+      "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
+      "dev": true
+    },
+    "home-or-tmp": {
+      "version": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
+      "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
+      "dev": true
+    },
+    "http-signature": {
+      "version": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
+      "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
+      "dev": true
+    },
+    "ignore": {
+      "version": "https://registry.npmjs.org/ignore/-/ignore-3.2.2.tgz",
+      "integrity": "sha1-HFHh71O6tt3BXbTZrE7BOezrNBA=",
+      "dev": true
+    },
+    "imurmurhash": {
+      "version": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+      "dev": true
+    },
+    "inflight": {
+      "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
+      "integrity": "sha1-bLtFIevVHODsCpNr/XZX736bFyo=",
+      "dev": true
+    },
+    "inherits": {
+      "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+      "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
+      "dev": true
+    },
+    "inquirer": {
+      "version": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
+      "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=",
+      "dev": true,
+      "dependencies": {
+        "lodash": {
+          "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+          "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
+          "dev": true
+        }
+      }
+    },
+    "interpret": {
+      "version": "https://registry.npmjs.org/interpret/-/interpret-1.0.1.tgz",
+      "integrity": "sha1-1Xn7f2k7hYAElHrzn6DbSfeVYCw=",
+      "dev": true
+    },
+    "is-fullwidth-code-point": {
+      "version": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+      "dev": true
+    },
+    "is-my-json-valid": {
+      "version": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz",
+      "integrity": "sha1-k27do8o8IR/ZjzstPgjaQ/eykVs=",
+      "dev": true
+    },
+    "is-path-cwd": {
+      "version": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+      "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
+      "dev": true
+    },
+    "is-path-in-cwd": {
+      "version": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz",
+      "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=",
+      "dev": true
+    },
+    "is-path-inside": {
+      "version": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz",
+      "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=",
+      "dev": true
+    },
+    "is-property": {
+      "version": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
+      "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
+      "dev": true
+    },
+    "is-resolvable": {
+      "version": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz",
+      "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=",
+      "dev": true
+    },
+    "is-typedarray": {
+      "version": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+      "dev": true
+    },
+    "isarray": {
+      "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+      "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+      "dev": true
+    },
+    "isexe": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz",
+      "integrity": "sha1-NvPiLmB1CSD15yQaR2qMakInWtA=",
+      "dev": true
+    },
+    "isstream": {
+      "version": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+      "dev": true
+    },
+    "jodid25519": {
+      "version": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz",
+      "integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=",
+      "dev": true,
+      "optional": true
+    },
+    "js-tokens": {
+      "version": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz",
+      "integrity": "sha1-COnxMkhKLEWjCQfp3E1VZ7fxFNc=",
+      "dev": true
+    },
+    "js-yaml": {
+      "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.2.tgz",
+      "integrity": "sha1-EJQjg+5LnCwg7eI4jBsPOHiisM4=",
+      "dev": true,
+      "dependencies": {
+        "argparse": {
+          "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.2.tgz",
+          "integrity": "sha1-vPrjkFllbRlz0LnmoadBVLWpoTY=",
+          "dev": true
+        },
+        "esprima": {
+          "version": "https://registry.npmjs.org/esprima/-/esprima-2.2.0.tgz",
+          "integrity": "sha1-QpLB1o5Bc9gV+iKQ3Hr8ltgfzYM=",
+          "dev": true
+        }
+      }
+    },
+    "jsbn": {
+      "version": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz",
+      "integrity": "sha1-ZQmH2g3XT06/WhE3eiqi0nPpff0=",
+      "dev": true,
+      "optional": true
+    },
+    "json-schema": {
+      "version": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+      "dev": true
+    },
+    "json-stable-stringify": {
+      "version": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
+      "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
+      "dev": true
+    },
+    "json-stringify-safe": {
+      "version": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+      "dev": true
+    },
+    "jsonify": {
+      "version": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+      "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
+      "dev": true
+    },
+    "jsonpointer": {
+      "version": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
+      "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
+      "dev": true
+    },
+    "jsprim": {
+      "version": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz",
+      "integrity": "sha1-KnJW9wQSop7jZwqspiWZTE3P8lI=",
+      "dev": true
+    },
+    "jsx-ast-utils": {
+      "version": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.0.tgz",
+      "integrity": "sha1-Wv44ho9WvIzHrq7wEAuox1vRJZE=",
+      "dev": true
+    },
+    "lcov-parse": {
+      "version": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz",
+      "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=",
+      "dev": true
+    },
+    "lodash": {
+      "version": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+      "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
+      "dev": true
+    },
+    "log-driver": {
+      "version": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz",
+      "integrity": "sha1-euTsJXMC/XkNVXyxDJcQDYV7AFY=",
+      "dev": true
+    },
+    "mime-db": {
+      "version": "https://registry.npmjs.org/mime-db/-/mime-db-1.26.0.tgz",
+      "integrity": "sha1-6v/NDk/Gk1z4E02iRuLmw1MFrf8=",
+      "dev": true
+    },
+    "mime-types": {
+      "version": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.14.tgz",
+      "integrity": "sha1-9+99l1g/yvO30oK2+LVnnaselO4=",
+      "dev": true
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+          "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+          "dev": true
+        },
+        "brace-expansion": {
+          "version": "1.1.8",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
+          "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
+          "dev": true
+        }
+      }
+    },
+    "minimist": {
+      "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+      "dev": true
+    },
+    "mkdirp": {
+      "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "dev": true
+    },
+    "ms": {
+      "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+      "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
+      "dev": true
+    },
+    "mute-stream": {
+      "version": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz",
+      "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=",
+      "dev": true
+    },
+    "natural-compare": {
+      "version": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+      "dev": true
+    },
+    "number-is-nan": {
+      "version": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz",
+      "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=",
+      "dev": true
+    },
+    "oauth-sign": {
+      "version": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
+      "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
+      "dev": true
+    },
+    "object-assign": {
+      "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "dev": true
+    },
+    "once": {
+      "version": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
+      "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=",
+      "dev": true
+    },
+    "onetime": {
+      "version": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
+      "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
+      "dev": true
+    },
+    "opener": {
+      "version": "https://registry.npmjs.org/opener/-/opener-1.4.2.tgz",
+      "integrity": "sha1-syWCCABCr4aAw4mkmRdbTFT/9SM=",
+      "dev": true
+    },
+    "os-homedir": {
+      "version": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz",
+      "integrity": "sha1-DWK99EuRb9O73PLKsZGUj7CU8Ac=",
+      "dev": true
+    },
+    "os-tmpdir": {
+      "version": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+      "dev": true
+    },
+    "own-or": {
+      "version": "https://registry.npmjs.org/own-or/-/own-or-1.0.0.tgz",
+      "integrity": "sha1-Tod/vtqaLsgAD7wLyuOWRe6L+Nw=",
+      "dev": true
+    },
+    "own-or-env": {
+      "version": "https://registry.npmjs.org/own-or-env/-/own-or-env-1.0.0.tgz",
+      "integrity": "sha1-nvkg/IHi5jz1nUEQElg2jPT8pPs=",
+      "dev": true
+    },
+    "path-is-absolute": {
+      "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz",
+      "integrity": "sha1-Jj2tpmqz8vsQv3+dJN2PPlcO+RI=",
+      "dev": true
+    },
+    "path-is-inside": {
+      "version": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+      "dev": true
+    },
+    "pify": {
+      "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+      "dev": true
+    },
+    "pinkie": {
+      "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+      "dev": true
+    },
+    "pinkie-promise": {
+      "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "dev": true
+    },
+    "pkg-config": {
+      "version": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz",
+      "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=",
+      "dev": true,
+      "dependencies": {
+        "xtend": {
+          "version": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+          "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
+          "dev": true
+        }
+      }
+    },
+    "pluralize": {
+      "version": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz",
+      "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=",
+      "dev": true
+    },
+    "prelude-ls": {
+      "version": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "dev": true
+    },
+    "process-nextick-args": {
+      "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz",
+      "integrity": "sha1-4nLu2CXV6fTqdNjXOx/jEcO+tjA=",
+      "dev": true
+    },
+    "progress": {
+      "version": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
+      "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=",
+      "dev": true
+    },
+    "pseudomap": {
+      "version": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+      "dev": true
+    },
+    "punycode": {
+      "version": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+      "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+      "dev": true
+    },
+    "qs": {
+      "version": "https://registry.npmjs.org/qs/-/qs-6.3.0.tgz",
+      "integrity": "sha1-9AOyZPI7wBIox0ExtAfxjV6l1EI=",
+      "dev": true
+    },
+    "readable-stream": {
+      "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
+      "integrity": "sha1-vsgb6ujPRVFovC5bKzH1vPrtmxs=",
+      "dev": true
+    },
+    "readline2": {
+      "version": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz",
+      "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=",
+      "dev": true
+    },
+    "rechoir": {
+      "version": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+      "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+      "dev": true
+    },
+    "request": {
+      "version": "https://registry.npmjs.org/request/-/request-2.79.0.tgz",
+      "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=",
+      "dev": true,
+      "dependencies": {
+        "extend": {
+          "version": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz",
+          "integrity": "sha1-WkdDU7nzNT3dgXbf03uRyDpG8dQ=",
+          "dev": true
+        }
+      }
+    },
+    "require-uncached": {
+      "version": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
+      "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
+      "dev": true
+    },
+    "resolve": {
+      "version": "https://registry.npmjs.org/resolve/-/resolve-1.1.6.tgz",
+      "integrity": "sha1-00kq0FTKgA9b76YS5hvqwe7Jj48=",
+      "dev": true
+    },
+    "resolve-from": {
+      "version": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
+      "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
+      "dev": true
+    },
+    "restore-cursor": {
+      "version": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
+      "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=",
+      "dev": true
+    },
+    "rimraf": {
+      "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.3.tgz",
+      "integrity": "sha1-5bUclDekxYKtuVXp8oz42UXicq8=",
+      "dev": true,
+      "dependencies": {
+        "glob": {
+          "version": "5.0.15",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+          "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+          "dev": true
+        }
+      }
+    },
+    "run-async": {
+      "version": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
+      "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=",
+      "dev": true
+    },
+    "run-parallel": {
+      "version": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.6.tgz",
+      "integrity": "sha1-KQA8miFj4B4tLfyQV18sbB1hoDk=",
+      "dev": true
+    },
+    "rx-lite": {
+      "version": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz",
+      "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=",
+      "dev": true
+    },
+    "safe-buffer": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+      "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
+      "dev": true,
+      "optional": true
+    },
+    "shelljs": {
+      "version": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.6.tgz",
+      "integrity": "sha1-N5zM+1a5HIYB5HkzVutTgpJN6a0=",
+      "dev": true,
+      "dependencies": {
+        "glob": {
+          "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
+          "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=",
+          "dev": true
+        },
+        "minimatch": {
+          "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz",
+          "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=",
+          "dev": true
+        }
+      }
+    },
+    "slice-ansi": {
+      "version": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
+      "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=",
+      "dev": true
+    },
+    "sntp": {
+      "version": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
+      "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
+      "dev": true
+    },
+    "source-map-support": {
+      "version": "0.4.15",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz",
+      "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=",
+      "dev": true,
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.6",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+          "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=",
+          "dev": true
+        }
+      }
+    },
+    "sprintf-js": {
+      "version": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+      "dev": true
+    },
+    "sshpk": {
+      "version": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.2.tgz",
+      "integrity": "sha1-1agEziJpVRVjjnmNviMnPeBwpfo=",
+      "dev": true,
+      "dependencies": {
+        "assert-plus": {
+          "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+          "dev": true
+        }
+      }
+    },
+    "stack-utils": {
+      "version": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.0.tgz",
+      "integrity": "sha1-I5LNjdvSIkku1sBHlg90FLRsD4M=",
+      "dev": true
+    },
+    "standard": {
+      "version": "https://registry.npmjs.org/standard/-/standard-8.6.0.tgz",
+      "integrity": "sha1-Y1Eyvnv7VnwpIQBfMPnjUOR1Kq0=",
+      "dev": true
+    },
+    "standard-engine": {
+      "version": "https://registry.npmjs.org/standard-engine/-/standard-engine-5.2.0.tgz",
+      "integrity": "sha1-QAZgrlrM6K/U22D/IhSpGQrXkKM=",
+      "dev": true,
+      "dependencies": {
+        "minimist": {
+          "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        }
+      }
+    },
+    "string_decoder": {
+      "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+      "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+      "dev": true
+    },
+    "string-width": {
+      "version": "https://registry.npmjs.org/string-width/-/string-width-1.0.1.tgz",
+      "integrity": "sha1-ySEptvHX9SrPmvQkom44ZKBc6wo=",
+      "dev": true
+    },
+    "stringstream": {
+      "version": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
+      "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
+      "dev": true
+    },
+    "strip-ansi": {
+      "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz",
+      "integrity": "sha1-dRC2ZVZ8qRTMtdfgcnY6yWi+NyQ=",
+      "dev": true
+    },
+    "strip-json-comments": {
+      "version": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
+      "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=",
+      "dev": true
+    },
+    "supports-color": {
+      "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+      "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+      "dev": true
+    },
+    "table": {
+      "version": "https://registry.npmjs.org/table/-/table-3.8.3.tgz",
+      "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=",
+      "dev": true,
+      "dependencies": {
+        "is-fullwidth-code-point": {
+          "version": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+          "dev": true
+        },
+        "lodash": {
+          "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+          "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
+          "dev": true
+        },
+        "string-width": {
+          "version": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz",
+          "integrity": "sha1-Y1xUNsxypuDDh87KJ41OLuxSaH4=",
+          "dev": true
+        }
+      }
+    },
+    "tap": {
+      "version": "10.5.1",
+      "resolved": "https://registry.npmjs.org/tap/-/tap-10.5.1.tgz",
+      "integrity": "sha512-1wfxVaE8y6JhVvZRJCn2HzC3ShiF5T17/kZynd2+tkszAWaOJ7ADzWcBKmxtTkXZ/6h4rZgt5qgw2OgQ02ehsw==",
+      "dev": true,
+      "dependencies": {
+        "inherits": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+          "dev": true,
+          "optional": true
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true,
+          "optional": true
+        },
+        "nyc": {
+          "version": "11.0.2",
+          "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.0.2.tgz",
+          "integrity": "sha512-31rRd6ME9NM17w0oPKqi51a6fzJAqYarnzQXK+iL8XaX+3H6VH0BQut7qHIgrv2mBASRic4oNi2KRgcbFODrsQ==",
+          "dev": true,
+          "dependencies": {
+            "align-text": {
+              "version": "0.1.4",
+              "bundled": true,
+              "dev": true
+            },
+            "amdefine": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "ansi-regex": {
+              "version": "2.1.1",
+              "bundled": true,
+              "dev": true
+            },
+            "ansi-styles": {
+              "version": "2.2.1",
+              "bundled": true,
+              "dev": true
+            },
+            "append-transform": {
+              "version": "0.4.0",
+              "bundled": true,
+              "dev": true
+            },
+            "archy": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "arr-diff": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "arr-flatten": {
+              "version": "1.0.3",
+              "bundled": true,
+              "dev": true
+            },
+            "array-unique": {
+              "version": "0.2.1",
+              "bundled": true,
+              "dev": true
+            },
+            "arrify": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "async": {
+              "version": "1.5.2",
+              "bundled": true,
+              "dev": true
+            },
+            "babel-code-frame": {
+              "version": "6.22.0",
+              "bundled": true,
+              "dev": true
+            },
+            "babel-generator": {
+              "version": "6.24.1",
+              "bundled": true,
+              "dev": true
+            },
+            "babel-messages": {
+              "version": "6.23.0",
+              "bundled": true,
+              "dev": true
+            },
+            "babel-runtime": {
+              "version": "6.23.0",
+              "bundled": true,
+              "dev": true
+            },
+            "babel-template": {
+              "version": "6.24.1",
+              "bundled": true,
+              "dev": true
+            },
+            "babel-traverse": {
+              "version": "6.24.1",
+              "bundled": true,
+              "dev": true
+            },
+            "babel-types": {
+              "version": "6.24.1",
+              "bundled": true,
+              "dev": true
+            },
+            "babylon": {
+              "version": "6.17.2",
+              "bundled": true,
+              "dev": true
+            },
+            "balanced-match": {
+              "version": "0.4.2",
+              "bundled": true,
+              "dev": true
+            },
+            "brace-expansion": {
+              "version": "1.1.7",
+              "bundled": true,
+              "dev": true
+            },
+            "braces": {
+              "version": "1.8.5",
+              "bundled": true,
+              "dev": true
+            },
+            "builtin-modules": {
+              "version": "1.1.1",
+              "bundled": true,
+              "dev": true
+            },
+            "caching-transform": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "center-align": {
+              "version": "0.1.3",
+              "bundled": true,
+              "dev": true,
+              "optional": true
+            },
+            "chalk": {
+              "version": "1.1.3",
+              "bundled": true,
+              "dev": true
+            },
+            "cliui": {
+              "version": "2.1.0",
+              "bundled": true,
+              "dev": true,
+              "optional": true,
+              "dependencies": {
+                "wordwrap": {
+                  "version": "0.0.2",
+                  "bundled": true,
+                  "dev": true,
+                  "optional": true
+                }
+              }
+            },
+            "code-point-at": {
+              "version": "1.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "commondir": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "concat-map": {
+              "version": "0.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "convert-source-map": {
+              "version": "1.5.0",
+              "bundled": true,
+              "dev": true
+            },
+            "core-js": {
+              "version": "2.4.1",
+              "bundled": true,
+              "dev": true
+            },
+            "cross-spawn": {
+              "version": "4.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "debug": {
+              "version": "2.6.8",
+              "bundled": true,
+              "dev": true
+            },
+            "debug-log": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "decamelize": {
+              "version": "1.2.0",
+              "bundled": true,
+              "dev": true
+            },
+            "default-require-extensions": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "detect-indent": {
+              "version": "4.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "error-ex": {
+              "version": "1.3.1",
+              "bundled": true,
+              "dev": true
+            },
+            "escape-string-regexp": {
+              "version": "1.0.5",
+              "bundled": true,
+              "dev": true
+            },
+            "esutils": {
+              "version": "2.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "execa": {
+              "version": "0.5.1",
+              "bundled": true,
+              "dev": true
+            },
+            "expand-brackets": {
+              "version": "0.1.5",
+              "bundled": true,
+              "dev": true
+            },
+            "expand-range": {
+              "version": "1.8.2",
+              "bundled": true,
+              "dev": true
+            },
+            "extglob": {
+              "version": "0.3.2",
+              "bundled": true,
+              "dev": true
+            },
+            "filename-regex": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "fill-range": {
+              "version": "2.2.3",
+              "bundled": true,
+              "dev": true
+            },
+            "find-cache-dir": {
+              "version": "0.1.1",
+              "bundled": true,
+              "dev": true
+            },
+            "find-up": {
+              "version": "2.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "for-in": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "for-own": {
+              "version": "0.1.5",
+              "bundled": true,
+              "dev": true
+            },
+            "foreground-child": {
+              "version": "1.5.6",
+              "bundled": true,
+              "dev": true
+            },
+            "fs.realpath": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "get-caller-file": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "get-stream": {
+              "version": "2.3.1",
+              "bundled": true,
+              "dev": true
+            },
+            "glob": {
+              "version": "7.1.2",
+              "bundled": true,
+              "dev": true
+            },
+            "glob-base": {
+              "version": "0.3.0",
+              "bundled": true,
+              "dev": true
+            },
+            "glob-parent": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "globals": {
+              "version": "9.17.0",
+              "bundled": true,
+              "dev": true
+            },
+            "graceful-fs": {
+              "version": "4.1.11",
+              "bundled": true,
+              "dev": true
+            },
+            "handlebars": {
+              "version": "4.0.10",
+              "bundled": true,
+              "dev": true,
+              "dependencies": {
+                "source-map": {
+                  "version": "0.4.4",
+                  "bundled": true,
+                  "dev": true
+                }
+              }
+            },
+            "has-ansi": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "has-flag": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "hosted-git-info": {
+              "version": "2.4.2",
+              "bundled": true,
+              "dev": true
+            },
+            "imurmurhash": {
+              "version": "0.1.4",
+              "bundled": true,
+              "dev": true
+            },
+            "inflight": {
+              "version": "1.0.6",
+              "bundled": true,
+              "dev": true
+            },
+            "inherits": {
+              "version": "2.0.3",
+              "bundled": true,
+              "dev": true
+            },
+            "invariant": {
+              "version": "2.2.2",
+              "bundled": true,
+              "dev": true
+            },
+            "invert-kv": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "is-arrayish": {
+              "version": "0.2.1",
+              "bundled": true,
+              "dev": true
+            },
+            "is-buffer": {
+              "version": "1.1.5",
+              "bundled": true,
+              "dev": true
+            },
+            "is-builtin-module": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "is-dotfile": {
+              "version": "1.0.3",
+              "bundled": true,
+              "dev": true
+            },
+            "is-equal-shallow": {
+              "version": "0.1.3",
+              "bundled": true,
+              "dev": true
+            },
+            "is-extendable": {
+              "version": "0.1.1",
+              "bundled": true,
+              "dev": true
+            },
+            "is-extglob": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "is-finite": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "is-fullwidth-code-point": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "is-glob": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "is-number": {
+              "version": "2.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "is-posix-bracket": {
+              "version": "0.1.1",
+              "bundled": true,
+              "dev": true
+            },
+            "is-primitive": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "is-stream": {
+              "version": "1.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "is-utf8": {
+              "version": "0.2.1",
+              "bundled": true,
+              "dev": true
+            },
+            "isarray": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "isexe": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "isobject": {
+              "version": "2.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "istanbul-lib-coverage": {
+              "version": "1.1.1",
+              "bundled": true,
+              "dev": true
+            },
+            "istanbul-lib-hook": {
+              "version": "1.0.7",
+              "bundled": true,
+              "dev": true
+            },
+            "istanbul-lib-instrument": {
+              "version": "1.7.2",
+              "bundled": true,
+              "dev": true
+            },
+            "istanbul-lib-report": {
+              "version": "1.1.1",
+              "bundled": true,
+              "dev": true,
+              "dependencies": {
+                "supports-color": {
+                  "version": "3.2.3",
+                  "bundled": true,
+                  "dev": true
+                }
+              }
+            },
+            "istanbul-lib-source-maps": {
+              "version": "1.2.1",
+              "bundled": true,
+              "dev": true
+            },
+            "istanbul-reports": {
+              "version": "1.1.1",
+              "bundled": true,
+              "dev": true
+            },
+            "js-tokens": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "jsesc": {
+              "version": "1.3.0",
+              "bundled": true,
+              "dev": true
+            },
+            "kind-of": {
+              "version": "3.2.2",
+              "bundled": true,
+              "dev": true
+            },
+            "lazy-cache": {
+              "version": "1.0.4",
+              "bundled": true,
+              "dev": true,
+              "optional": true
+            },
+            "lcid": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "load-json-file": {
+              "version": "1.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "locate-path": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true,
+              "dependencies": {
+                "path-exists": {
+                  "version": "3.0.0",
+                  "bundled": true,
+                  "dev": true
+                }
+              }
+            },
+            "lodash": {
+              "version": "4.17.4",
+              "bundled": true,
+              "dev": true
+            },
+            "longest": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "loose-envify": {
+              "version": "1.3.1",
+              "bundled": true,
+              "dev": true
+            },
+            "lru-cache": {
+              "version": "4.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "md5-hex": {
+              "version": "1.3.0",
+              "bundled": true,
+              "dev": true
+            },
+            "md5-o-matic": {
+              "version": "0.1.1",
+              "bundled": true,
+              "dev": true
+            },
+            "mem": {
+              "version": "1.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "merge-source-map": {
+              "version": "1.0.3",
+              "bundled": true,
+              "dev": true
+            },
+            "micromatch": {
+              "version": "2.3.11",
+              "bundled": true,
+              "dev": true
+            },
+            "mimic-fn": {
+              "version": "1.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "minimatch": {
+              "version": "3.0.4",
+              "bundled": true,
+              "dev": true
+            },
+            "minimist": {
+              "version": "0.0.8",
+              "bundled": true,
+              "dev": true
+            },
+            "mkdirp": {
+              "version": "0.5.1",
+              "bundled": true,
+              "dev": true
+            },
+            "ms": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "normalize-package-data": {
+              "version": "2.3.8",
+              "bundled": true,
+              "dev": true
+            },
+            "normalize-path": {
+              "version": "2.1.1",
+              "bundled": true,
+              "dev": true
+            },
+            "npm-run-path": {
+              "version": "2.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "number-is-nan": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "object-assign": {
+              "version": "4.1.1",
+              "bundled": true,
+              "dev": true
+            },
+            "object.omit": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "once": {
+              "version": "1.4.0",
+              "bundled": true,
+              "dev": true
+            },
+            "optimist": {
+              "version": "0.6.1",
+              "bundled": true,
+              "dev": true
+            },
+            "os-homedir": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "os-locale": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "p-finally": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "p-limit": {
+              "version": "1.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "p-locate": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "parse-glob": {
+              "version": "3.0.4",
+              "bundled": true,
+              "dev": true
+            },
+            "parse-json": {
+              "version": "2.2.0",
+              "bundled": true,
+              "dev": true
+            },
+            "path-exists": {
+              "version": "2.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "path-is-absolute": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "path-key": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "path-parse": {
+              "version": "1.0.5",
+              "bundled": true,
+              "dev": true
+            },
+            "path-type": {
+              "version": "1.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "pify": {
+              "version": "2.3.0",
+              "bundled": true,
+              "dev": true
+            },
+            "pinkie": {
+              "version": "2.0.4",
+              "bundled": true,
+              "dev": true
+            },
+            "pinkie-promise": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "pkg-dir": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "dependencies": {
+                "find-up": {
+                  "version": "1.1.2",
+                  "bundled": true,
+                  "dev": true
+                }
+              }
+            },
+            "preserve": {
+              "version": "0.2.0",
+              "bundled": true,
+              "dev": true
+            },
+            "pseudomap": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "randomatic": {
+              "version": "1.1.6",
+              "bundled": true,
+              "dev": true
+            },
+            "read-pkg": {
+              "version": "1.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "read-pkg-up": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true,
+              "dependencies": {
+                "find-up": {
+                  "version": "1.1.2",
+                  "bundled": true,
+                  "dev": true
+                }
+              }
+            },
+            "regenerator-runtime": {
+              "version": "0.10.5",
+              "bundled": true,
+              "dev": true
+            },
+            "regex-cache": {
+              "version": "0.4.3",
+              "bundled": true,
+              "dev": true
+            },
+            "remove-trailing-separator": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "repeat-element": {
+              "version": "1.1.2",
+              "bundled": true,
+              "dev": true
+            },
+            "repeat-string": {
+              "version": "1.6.1",
+              "bundled": true,
+              "dev": true
+            },
+            "repeating": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "require-directory": {
+              "version": "2.1.1",
+              "bundled": true,
+              "dev": true
+            },
+            "require-main-filename": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "resolve-from": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "right-align": {
+              "version": "0.1.3",
+              "bundled": true,
+              "dev": true,
+              "optional": true
+            },
+            "rimraf": {
+              "version": "2.6.1",
+              "bundled": true,
+              "dev": true
+            },
+            "semver": {
+              "version": "5.3.0",
+              "bundled": true,
+              "dev": true
+            },
+            "set-blocking": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "signal-exit": {
+              "version": "3.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "slide": {
+              "version": "1.1.6",
+              "bundled": true,
+              "dev": true
+            },
+            "source-map": {
+              "version": "0.5.6",
+              "bundled": true,
+              "dev": true
+            },
+            "spawn-wrap": {
+              "version": "1.3.6",
+              "bundled": true,
+              "dev": true
+            },
+            "spdx-correct": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "spdx-expression-parse": {
+              "version": "1.0.4",
+              "bundled": true,
+              "dev": true
+            },
+            "spdx-license-ids": {
+              "version": "1.2.2",
+              "bundled": true,
+              "dev": true
+            },
+            "string-width": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true,
+              "dependencies": {
+                "is-fullwidth-code-point": {
+                  "version": "2.0.0",
+                  "bundled": true,
+                  "dev": true
+                }
+              }
+            },
+            "strip-ansi": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "strip-bom": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "strip-eof": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "supports-color": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "test-exclude": {
+              "version": "4.1.1",
+              "bundled": true,
+              "dev": true
+            },
+            "to-fast-properties": {
+              "version": "1.0.3",
+              "bundled": true,
+              "dev": true
+            },
+            "trim-right": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "uglify-js": {
+              "version": "2.8.27",
+              "bundled": true,
+              "dev": true,
+              "optional": true,
+              "dependencies": {
+                "camelcase": {
+                  "version": "1.2.1",
+                  "bundled": true,
+                  "dev": true,
+                  "optional": true
+                },
+                "yargs": {
+                  "version": "3.10.0",
+                  "bundled": true,
+                  "dev": true,
+                  "optional": true
+                }
+              }
+            },
+            "uglify-to-browserify": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true,
+              "optional": true
+            },
+            "validate-npm-package-license": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "which": {
+              "version": "1.2.14",
+              "bundled": true,
+              "dev": true
+            },
+            "which-module": {
+              "version": "2.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "window-size": {
+              "version": "0.1.0",
+              "bundled": true,
+              "dev": true,
+              "optional": true
+            },
+            "wordwrap": {
+              "version": "0.0.3",
+              "bundled": true,
+              "dev": true
+            },
+            "wrap-ansi": {
+              "version": "2.1.0",
+              "bundled": true,
+              "dev": true,
+              "dependencies": {
+                "string-width": {
+                  "version": "1.0.2",
+                  "bundled": true,
+                  "dev": true
+                }
+              }
+            },
+            "wrappy": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "write-file-atomic": {
+              "version": "1.3.4",
+              "bundled": true,
+              "dev": true
+            },
+            "y18n": {
+              "version": "3.2.1",
+              "bundled": true,
+              "dev": true
+            },
+            "yallist": {
+              "version": "2.1.2",
+              "bundled": true,
+              "dev": true
+            },
+            "yargs": {
+              "version": "8.0.1",
+              "bundled": true,
+              "dev": true,
+              "dependencies": {
+                "camelcase": {
+                  "version": "4.1.0",
+                  "bundled": true,
+                  "dev": true
+                },
+                "cliui": {
+                  "version": "3.2.0",
+                  "bundled": true,
+                  "dev": true,
+                  "dependencies": {
+                    "string-width": {
+                      "version": "1.0.2",
+                      "bundled": true,
+                      "dev": true
+                    }
+                  }
+                },
+                "load-json-file": {
+                  "version": "2.0.0",
+                  "bundled": true,
+                  "dev": true
+                },
+                "path-type": {
+                  "version": "2.0.0",
+                  "bundled": true,
+                  "dev": true
+                },
+                "read-pkg": {
+                  "version": "2.0.0",
+                  "bundled": true,
+                  "dev": true
+                },
+                "read-pkg-up": {
+                  "version": "2.0.0",
+                  "bundled": true,
+                  "dev": true
+                },
+                "strip-bom": {
+                  "version": "3.0.0",
+                  "bundled": true,
+                  "dev": true
+                },
+                "yargs-parser": {
+                  "version": "7.0.0",
+                  "bundled": true,
+                  "dev": true
+                }
+              }
+            },
+            "yargs-parser": {
+              "version": "5.0.0",
+              "bundled": true,
+              "dev": true,
+              "dependencies": {
+                "camelcase": {
+                  "version": "3.0.0",
+                  "bundled": true,
+                  "dev": true
+                }
+              }
+            }
+          }
+        },
+        "process-nextick-args": {
+          "version": "1.0.7",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+          "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
+          "dev": true,
+          "optional": true
+        },
+        "signal-exit": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+          "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+          "dev": true
+        },
+        "string_decoder": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz",
+          "integrity": "sha1-sp4fThEl+pehA4K4pTNze3SR4Xk=",
+          "dev": true,
+          "optional": true,
+          "dependencies": {
+            "safe-buffer": {
+              "version": "5.0.1",
+              "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+              "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=",
+              "dev": true,
+              "optional": true
+            }
+          }
+        },
+        "tap-mocha-reporter": {
+          "version": "3.0.5",
+          "resolved": "https://registry.npmjs.org/tap-mocha-reporter/-/tap-mocha-reporter-3.0.5.tgz",
+          "integrity": "sha512-YIoWejBBb+6gKOdu5B4H4oIKQhmRJsYGHSE5a6Mv87jriBDy/fAVLRVuMHTAP/vufYPcI3CKAck9VvnZxtQ4mA==",
+          "dev": true,
+          "dependencies": {
+            "readable-stream": {
+              "version": "2.3.2",
+              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz",
+              "integrity": "sha1-WgTfBeT1f+Pw3Gj90R3FyXx+b00=",
+              "dev": true,
+              "optional": true
+            }
+          }
+        },
+        "tmatch": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/tmatch/-/tmatch-3.1.0.tgz",
+          "integrity": "sha512-W3MSATOCN4pVu2qFxmJLIArSifeSOFqnfx9hiUaVgOmeRoI2NbU7RNga+6G+L8ojlFeQge+ZPCclWyUpQ8UeNQ==",
+          "dev": true
+        }
+      }
+    },
+    "tap-parser": {
+      "version": "https://registry.npmjs.org/tap-parser/-/tap-parser-5.3.2.tgz",
+      "integrity": "sha1-JB4afGxmyaQEfJ4WxD2WrmHpvok=",
+      "dev": true
+    },
+    "text-table": {
+      "version": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "dev": true
+    },
+    "through": {
+      "version": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+      "dev": true
+    },
+    "tough-cookie": {
+      "version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",
+      "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=",
+      "dev": true
+    },
+    "trivial-deferred": {
+      "version": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-1.0.1.tgz",
+      "integrity": "sha1-N21NKdlR1jaKb3oK6FwvTV4GWPM=",
+      "dev": true
+    },
+    "tryit": {
+      "version": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz",
+      "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=",
+      "dev": true
+    },
+    "tsame": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/tsame/-/tsame-1.1.2.tgz",
+      "integrity": "sha512-ovCs24PGjmByVPr9tSIOs/yjUX9sJl0grEmOsj9dZA/UknQkgPOKcUqM84aSCvt9awHuhc/boMzTg3BHFalxWw==",
+      "dev": true
+    },
+    "tunnel-agent": {
+      "version": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz",
+      "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=",
+      "dev": true
+    },
+    "tweetnacl": {
+      "version": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+      "dev": true,
+      "optional": true
+    },
+    "typedarray": {
+      "version": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "dev": true
+    },
+    "unicode-length": {
+      "version": "https://registry.npmjs.org/unicode-length/-/unicode-length-1.0.3.tgz",
+      "integrity": "sha1-Wtp6f+1RhBpBijKM8UlHisg1irs=",
+      "dev": true,
+      "dependencies": {
+        "strip-ansi": {
+          "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+          "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+          "dev": true
+        }
+      }
+    },
+    "uniq": {
+      "version": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+      "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
+      "dev": true
+    },
+    "user-home": {
+      "version": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz",
+      "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=",
+      "dev": true
+    },
+    "util-deprecate": {
+      "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.1.tgz",
+      "integrity": "sha1-NVaj0TxMaqeYPX4kJUeBlxmbeIE=",
+      "dev": true
+    },
+    "uuid": {
+      "version": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz",
+      "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=",
+      "dev": true
+    },
+    "verror": {
+      "version": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz",
+      "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=",
+      "dev": true
+    },
+    "wordwrap": {
+      "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+      "dev": true
+    },
+    "wrappy": {
+      "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz",
+      "integrity": "sha1-HmWWmWXMvC20VIxrhKbyxa7dRzk=",
+      "dev": true
+    },
+    "write": {
+      "version": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
+      "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
+      "dev": true
+    },
+    "xtend": {
+      "version": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
+      "integrity": "sha1-i8Nv+Hrtvnzp6vC8o2sjVKdDhA8=",
+      "dev": true
+    },
+    "yallist": {
+      "version": "https://registry.npmjs.org/yallist/-/yallist-2.0.0.tgz",
+      "integrity": "sha1-MGxUODXwnuGkyyO3vOmrNByRzdQ=",
+      "dev": true
+    },
+    "yapool": {
+      "version": "https://registry.npmjs.org/yapool/-/yapool-1.0.0.tgz",
+      "integrity": "sha1-9pPymjFbUNmp2iZGp6ZkXJaYW2o=",
+      "dev": true
+    }
+  }
+}
diff --git a/package.json b/package.json
index 8ee1759..d2039bf 100644
--- a/package.json
+++ b/package.json
@@ -2,11 +2,24 @@
   "name": "sax",
   "description": "An evented streaming XML parser in JavaScript",
   "author": "Isaac Z. Schlueter <i at izs.me> (http://blog.izs.me/)",
-  "version": "0.5.5",
+  "version": "1.2.4",
   "main": "lib/sax.js",
-  "license": "BSD",
+  "license": "ISC",
   "scripts": {
-    "test": "node test/index.js"
+    "test": "tap test/*.js --cov -j4",
+    "posttest": "standard -F test/*.js lib/*.js",
+    "preversion": "npm test",
+    "postversion": "npm publish",
+    "postpublish": "git push origin --all; git push origin --tags"
   },
-  "repository": "git://github.com/isaacs/sax-js.git"
+  "repository": "git://github.com/isaacs/sax-js.git",
+  "files": [
+    "lib/sax.js",
+    "LICENSE",
+    "README.md"
+  ],
+  "devDependencies": {
+    "standard": "^8.6.0",
+    "tap": "^10.5.1"
+  }
 }
diff --git a/test/attribute-name.js b/test/attribute-name.js
index 9ebbe58..7037689 100644
--- a/test/attribute-name.js
+++ b/test/attribute-name.js
@@ -1,33 +1,44 @@
-require(__dirname).test(
-  { xml: "<root length='12345'></root>"
-  , expect: [
-    ["attribute", {
-      name: "length"
-    , value: "12345"
-    , prefix: ""
-    , local: "length"
-    , uri: ""
-    }]
-  , ["opentag", {
-      name: "root"
-    , prefix: ""
-    , local: "root"
-    , uri: ""
-    , attributes: {
-      length: {
-        name: "length"
-      , value: "12345"
-      , prefix: ""
-      , local: "length"
-      , uri: ""
+require(__dirname).test({
+  xml: "<root length='12345'></root>",
+  expect: [
+    [ 'opentagstart', { name: 'root', attributes: {}, ns: {} } ],
+    [
+      'attribute',
+      {
+        name: 'length',
+        value: '12345',
+        prefix: '',
+        local: 'length',
+        uri: ''
       }
-    }
-    , ns: {}
-    , isSelfClosing: false
-    }]
-  , ["closetag", "root"]
-  ]
-  , strict: true
-  , opt: { xmlns: true }
+    ],
+    [
+      'opentag',
+      {
+        name: 'root',
+        prefix: '',
+        local: 'root',
+        uri: '',
+        attributes: {
+          length: {
+            name: 'length',
+            value: '12345',
+            prefix: '',
+            local: 'length',
+            uri: ''
+          }
+        },
+        ns: {},
+        isSelfClosing: false
+      }
+    ],
+    [
+      'closetag',
+      'root'
+    ]
+  ],
+  strict: true,
+  opt: {
+    xmlns: true
   }
-)
+})
diff --git a/test/attribute-no-space.js b/test/attribute-no-space.js
new file mode 100644
index 0000000..90aec90
--- /dev/null
+++ b/test/attribute-no-space.js
@@ -0,0 +1,71 @@
+// non-strict: no error
+require(__dirname).test({
+  xml: '<root attr1="first"attr2="second"/>',
+  expect: [
+    [ 'opentagstart', { name: 'root', attributes: {} } ],
+    [ 'attribute', { name: 'attr1', value: 'first' } ],
+    [ 'attribute', { name: 'attr2', value: 'second' } ],
+    [ 'opentag', { name: 'root', attributes: { attr1: 'first', attr2: 'second' }, isSelfClosing: true } ],
+    [ 'closetag', 'root' ]
+  ],
+  strict: false,
+  opt: { lowercase: true }
+})
+
+// strict: should give an error, but still parse
+require(__dirname).test({
+  xml: '<root attr1="first"attr2="second"/>',
+  expect: [
+    [ 'opentagstart', { name: 'root', attributes: {} } ],
+    [ 'attribute', { name: 'attr1', value: 'first' } ],
+    [ 'error', 'No whitespace between attributes\nLine: 0\nColumn: 20\nChar: a' ],
+    [ 'attribute', { name: 'attr2', value: 'second' } ],
+    [ 'opentag', { name: 'root', attributes: { attr1: 'first', attr2: 'second' }, isSelfClosing: true } ],
+    [ 'closetag', 'root' ]
+  ],
+  strict: true,
+  opt: { }
+}
+)
+
+// strict: other cases should still pass
+require(__dirname).test({
+  xml: '<root attr1="first" attr2="second"/>',
+  expect: [
+    [ 'opentagstart', { name: 'root', attributes: {} } ],
+    [ 'attribute', { name: 'attr1', value: 'first' } ],
+    [ 'attribute', { name: 'attr2', value: 'second' } ],
+    [ 'opentag', { name: 'root', attributes: { attr1: 'first', attr2: 'second' }, isSelfClosing: true } ],
+    [ 'closetag', 'root' ]
+  ],
+  strict: true,
+  opt: { }
+})
+
+// strict: other cases should still pass
+require(__dirname).test({
+  xml: '<root attr1="first"\nattr2="second"/>',
+  expect: [
+    [ 'opentagstart', { name: 'root', attributes: {} } ],
+    [ 'attribute', { name: 'attr1', value: 'first' } ],
+    [ 'attribute', { name: 'attr2', value: 'second' } ],
+    [ 'opentag', { name: 'root', attributes: { attr1: 'first', attr2: 'second' }, isSelfClosing: true } ],
+    [ 'closetag', 'root' ]
+  ],
+  strict: true,
+  opt: { }
+})
+
+// strict: other cases should still pass
+require(__dirname).test({
+  xml: '<root attr1="first"  attr2="second"/>',
+  expect: [
+    [ 'opentagstart', { name: 'root', attributes: {} } ],
+    [ 'attribute', { name: 'attr1', value: 'first' } ],
+    [ 'attribute', { name: 'attr2', value: 'second' } ],
+    [ 'opentag', { name: 'root', attributes: { attr1: 'first', attr2: 'second' }, isSelfClosing: true } ],
+    [ 'closetag', 'root' ]
+  ],
+  strict: true,
+  opt: { }
+})
diff --git a/test/attribute-unquoted.js b/test/attribute-unquoted.js
new file mode 100644
index 0000000..40ca82b
--- /dev/null
+++ b/test/attribute-unquoted.js
@@ -0,0 +1,36 @@
+require(__dirname).test({
+  expect: [
+    [ 'opentagstart', { name: 'ROOT', attributes: {}, ns: {} } ],
+    [ 'attribute', {
+      name: 'LENGTH',
+      value: '12345',
+      prefix: '',
+      local: 'LENGTH',
+      uri: ''
+    } ],
+    [ 'opentag', {
+      name: 'ROOT',
+      attributes: {
+        LENGTH: {
+          name: 'LENGTH',
+          value: '12345',
+          prefix: '',
+          local: 'LENGTH',
+          uri: ''
+        }
+      },
+      ns: {},
+      prefix: '',
+      local: 'ROOT',
+      uri: '',
+      isSelfClosing: false
+    } ],
+    [ 'closetag', 'ROOT' ],
+    [ 'end' ],
+    [ 'ready' ]
+  ],
+  strict: false,
+  opt: {
+    xmlns: true
+  }
+}).write('<root length=12').write('345></root>').close()
diff --git a/test/bom.js b/test/bom.js
new file mode 100644
index 0000000..79d3909
--- /dev/null
+++ b/test/bom.js
@@ -0,0 +1,47 @@
+// BOM at the very begining of the stream should be ignored
+require(__dirname).test({
+  xml: '\uFEFF<P></P>',
+  expect: [
+    ['opentagstart', {'name': 'P', attributes: {}}],
+    ['opentag', {'name': 'P', attributes: {}, isSelfClosing: false}],
+    ['closetag', 'P']
+  ]
+})
+
+// In all other places it should be consumed
+require(__dirname).test({
+  xml: '\uFEFF<P BOM="\uFEFF">\uFEFFStarts and ends with BOM\uFEFF</P>',
+  expect: [
+    ['opentagstart', {'name': 'P', attributes: {}}],
+    ['attribute', {'name': 'BOM', 'value': '\uFEFF'}],
+    ['opentag', {'name': 'P', attributes: {'BOM': '\uFEFF'}, isSelfClosing: false}],
+    ['text', '\uFEFFStarts and ends with BOM\uFEFF'],
+    ['closetag', 'P']
+  ]
+})
+
+// BOM after a whitespace is an error
+require(__dirname).test({
+  xml: ' \uFEFF<P></P>',
+  expect: [
+    ['error', 'Non-whitespace before first tag.\nLine: 0\nColumn: 2\nChar: \uFEFF'],
+    ['text', '\uFEFF'],
+    ['opentagstart', {'name': 'P', attributes: {}}],
+    ['opentag', {'name': 'P', attributes: {}, isSelfClosing: false}],
+    ['closetag', 'P']
+  ],
+  strict: true
+})
+
+// There is only one BOM allowed at the start
+require(__dirname).test({
+  xml: '\uFEFF\uFEFF<P></P>',
+  expect: [
+    ['error', 'Non-whitespace before first tag.\nLine: 0\nColumn: 2\nChar: \uFEFF'],
+    ['text', '\uFEFF'],
+    ['opentagstart', {'name': 'P', attributes: {}}],
+    ['opentag', {'name': 'P', attributes: {}, isSelfClosing: false}],
+    ['closetag', 'P']
+  ],
+  strict: true
+})
diff --git a/test/buffer-overrun.js b/test/buffer-overrun.js
index 57d3c41..8d4d7a8 100644
--- a/test/buffer-overrun.js
+++ b/test/buffer-overrun.js
@@ -1,26 +1,30 @@
 // set this really low so that I don't have to put 64 MB of xml in here.
-var sax = require("../lib/sax")
+var sax = require('../lib/sax')
 var bl = sax.MAX_BUFFER_LENGTH
-sax.MAX_BUFFER_LENGTH = 5;
+sax.MAX_BUFFER_LENGTH = 5
 
 require(__dirname).test({
-  expect : [
-    ["error", "Max buffer length exceeded: tagName\nLine: 0\nColumn: 15\nChar: "],
-    ["error", "Max buffer length exceeded: tagName\nLine: 0\nColumn: 30\nChar: "],
-    ["error", "Max buffer length exceeded: tagName\nLine: 0\nColumn: 45\nChar: "],
-    ["opentag", {
-     "name": "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ",
-     "attributes": {},
-     "isSelfClosing": false
+  expect: [
+    ['error', 'Max buffer length exceeded: tagName\nLine: 0\nColumn: 15\nChar: '],
+    ['error', 'Max buffer length exceeded: tagName\nLine: 0\nColumn: 30\nChar: '],
+    ['error', 'Max buffer length exceeded: tagName\nLine: 0\nColumn: 45\nChar: '],
+    ['opentagstart', {
+      'name': 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ',
+      'attributes': {}
     }],
-    ["text", "yo"],
-    ["closetag", "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"]
+    ['opentag', {
+      'name': 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ',
+      'attributes': {},
+      'isSelfClosing': false
+    }],
+    ['text', 'yo'],
+    ['closetag', 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ']
   ]
-}).write("<abcdefghijklmn")
-  .write("opqrstuvwxyzABC")
-  .write("DEFGHIJKLMNOPQR")
-  .write("STUVWXYZ>")
-  .write("yo")
-  .write("</abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ>")
-  .close();
+}).write('<abcdefghijklmn')
+  .write('opqrstuvwxyzABC')
+  .write('DEFGHIJKLMNOPQR')
+  .write('STUVWXYZ>')
+  .write('yo')
+  .write('</abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ>')
+  .close()
 sax.MAX_BUFFER_LENGTH = bl
diff --git a/test/case.js b/test/case.js
index 9da78ab..5b7d2f9 100644
--- a/test/case.js
+++ b/test/case.js
@@ -1,50 +1,62 @@
 // default to uppercase
-require(__dirname).test
-  ( { xml :
-      "<span class=\"test\" hello=\"world\"></span>"
-    , expect :
-      [ [ "attribute", { name: "CLASS", value: "test" } ]
-      , [ "attribute", { name: "HELLO", value: "world" } ]
-      , [ "opentag", { name: "SPAN",
-                       attributes: { CLASS: "test", HELLO: "world" },
-                       isSelfClosing: false } ]
-      , [ "closetag", "SPAN" ]
-      ]
-    , strict : false
-    , opt : {}
-    }
-  )
+require(__dirname).test({
+  xml: '<span class="test" hello="world"></span>',
+  expect: [
+    [ 'opentagstart', {
+      name: 'SPAN',
+      attributes: {}
+    } ],
+    [ 'attribute', { name: 'CLASS', value: 'test' } ],
+    [ 'attribute', { name: 'HELLO', value: 'world' } ],
+    [ 'opentag', {
+      name: 'SPAN',
+      attributes: { CLASS: 'test', HELLO: 'world' },
+      isSelfClosing: false
+    } ],
+    [ 'closetag', 'SPAN' ]
+  ],
+  strict: false,
+  opt: {}
+})
 
 // lowercase option : lowercase tag/attribute names
-require(__dirname).test
-  ( { xml :
-      "<span class=\"test\" hello=\"world\"></span>"
-    , expect :
-      [ [ "attribute", { name: "class", value: "test" } ]
-      , [ "attribute", { name: "hello", value: "world" } ]
-      , [ "opentag", { name: "span",
-                       attributes: { class: "test", hello: "world" },
-                       isSelfClosing: false } ]
-      , [ "closetag", "span" ]
-      ]
-    , strict : false
-    , opt : {lowercase:true}
-    }
-  )
+require(__dirname).test({
+  xml: '<span class="test" hello="world"></span>',
+  expect: [
+    [ 'opentagstart', {
+      name: 'span',
+      attributes: {}
+    } ],
+    [ 'attribute', { name: 'class', value: 'test' } ],
+    [ 'attribute', { name: 'hello', value: 'world' } ],
+    [ 'opentag', {
+      name: 'span',
+      attributes: { class: 'test', hello: 'world' },
+      isSelfClosing: false
+    } ],
+    [ 'closetag', 'span' ]
+  ],
+  strict: false,
+  opt: {lowercase: true}
+})
 
 // backward compatibility with old lowercasetags opt
-require(__dirname).test
-  ( { xml :
-      "<span class=\"test\" hello=\"world\"></span>"
-    , expect :
-      [ [ "attribute", { name: "class", value: "test" } ]
-      , [ "attribute", { name: "hello", value: "world" } ]
-      , [ "opentag", { name: "span",
-                       attributes: { class: "test", hello: "world" },
-                       isSelfClosing: false } ]
-      , [ "closetag", "span" ]
-      ]
-    , strict : false
-    , opt : {lowercasetags:true}
-    }
-  )
+require(__dirname).test({
+  xml: '<span class="test" hello="world"></span>',
+  expect: [
+    [ 'opentagstart', {
+      name: 'span',
+      attributes: {}
+    } ],
+    [ 'attribute', { name: 'class', value: 'test' } ],
+    [ 'attribute', { name: 'hello', value: 'world' } ],
+    [ 'opentag', {
+      name: 'span',
+      attributes: { class: 'test', hello: 'world' },
+      isSelfClosing: false
+    } ],
+    [ 'closetag', 'span' ]
+  ],
+  strict: false,
+  opt: {lowercasetags: true}
+})
diff --git a/test/cdata-chunked.js b/test/cdata-chunked.js
index e3362bc..6ed94a0 100644
--- a/test/cdata-chunked.js
+++ b/test/cdata-chunked.js
@@ -1,11 +1,10 @@
-
 require(__dirname).test({
-  expect : [
-    ["opentag", {"name": "R","attributes": {}, "isSelfClosing": false}],
-    ["opencdata", undefined],
-    ["cdata", " this is character data  "],
-    ["closecdata", undefined],
-    ["closetag", "R"]
+  expect: [
+    ['opentagstart', {'name': 'R', 'attributes': {}}],
+    ['opentag', {'name': 'R', 'attributes': {}, 'isSelfClosing': false}],
+    ['opencdata', undefined],
+    ['cdata', ' this is character data  '],
+    ['closecdata', undefined],
+    ['closetag', 'R']
   ]
-}).write("<r><![CDATA[ this is ").write("character data  ").write("]]></r>").close();
-
+}).write('<r><![CDATA[ this is ').write('character data  ').write(']]></r>').close()
diff --git a/test/cdata-end-split.js b/test/cdata-end-split.js
index 34f3450..09dd612 100644
--- a/test/cdata-end-split.js
+++ b/test/cdata-end-split.js
@@ -1,15 +1,14 @@
-
 require(__dirname).test({
-  expect : [
-    ["opentag", {"name": "R","attributes": {}, "isSelfClosing": false}],
-    ["opencdata", undefined],
-    ["cdata", " this is "],
-    ["closecdata", undefined],
-    ["closetag", "R"]
+  expect: [
+    ['opentagstart', {'name': 'R', 'attributes': {}}],
+    ['opentag', {'name': 'R', 'attributes': {}, 'isSelfClosing': false}],
+    ['opencdata', undefined],
+    ['cdata', ' this is '],
+    ['closecdata', undefined],
+    ['closetag', 'R']
   ]
 })
-  .write("<r><![CDATA[ this is ]")
-  .write("]>")
-  .write("</r>")
-  .close();
-
+  .write('<r><![CDATA[ this is ]')
+  .write(']>')
+  .write('</r>')
+  .close()
diff --git a/test/cdata-fake-end.js b/test/cdata-fake-end.js
index ccafa1b..668ad69 100644
--- a/test/cdata-fake-end.js
+++ b/test/cdata-fake-end.js
@@ -1,28 +1,28 @@
-
 var p = require(__dirname).test({
-  expect : [
-    ["opentag", {"name": "R","attributes": {}, "isSelfClosing": false}],
-    ["opencdata", undefined],
-    ["cdata", "[[[[[[[[]]]]]]]]"],
-    ["closecdata", undefined],
-    ["closetag", "R"]
+  expect: [
+    ['opentagstart', {'name': 'R', 'attributes': {}}],
+    ['opentag', {'name': 'R', 'attributes': {}, 'isSelfClosing': false}],
+    ['opencdata', undefined],
+    ['cdata', '[[[[[[[[]]]]]]]]'],
+    ['closecdata', undefined],
+    ['closetag', 'R']
   ]
 })
-var x = "<r><![CDATA[[[[[[[[[]]]]]]]]]]></r>"
-for (var i = 0; i < x.length ; i ++) {
+var x = '<r><![CDATA[[[[[[[[[]]]]]]]]]]></r>'
+for (var i = 0; i < x.length; i++) {
   p.write(x.charAt(i))
 }
-p.close();
-
+p.close()
 
 var p2 = require(__dirname).test({
-  expect : [
-    ["opentag", {"name": "R","attributes": {}, "isSelfClosing": false}],
-    ["opencdata", undefined],
-    ["cdata", "[[[[[[[[]]]]]]]]"],
-    ["closecdata", undefined],
-    ["closetag", "R"]
+  expect: [
+    ['opentagstart', {'name': 'R', 'attributes': {}}],
+    ['opentag', {'name': 'R', 'attributes': {}, 'isSelfClosing': false}],
+    ['opencdata', undefined],
+    ['cdata', '[[[[[[[[]]]]]]]]'],
+    ['closecdata', undefined],
+    ['closetag', 'R']
   ]
 })
-var x = "<r><![CDATA[[[[[[[[[]]]]]]]]]]></r>"
-p2.write(x).close();
+x = '<r><![CDATA[[[[[[[[[]]]]]]]]]]></r>'
+p2.write(x).close()
diff --git a/test/cdata-multiple.js b/test/cdata-multiple.js
index 8e2f911..10dce54 100644
--- a/test/cdata-multiple.js
+++ b/test/cdata-multiple.js
@@ -1,15 +1,14 @@
-
 require(__dirname).test({
-  expect : [
-    ["opentag", {"name": "R","attributes": {}, "isSelfClosing": false}],
-    ["opencdata", undefined],
-    ["cdata", " this is "],
-    ["closecdata", undefined],
-    ["opencdata", undefined],
-    ["cdata", "character data  "],
-    ["closecdata", undefined],
-    ["closetag", "R"]
+  expect: [
+    ['opentagstart', {'name': 'R', 'attributes': {}}],
+    ['opentag', {'name': 'R', 'attributes': {}, 'isSelfClosing': false}],
+    ['opencdata', undefined],
+    ['cdata', ' this is '],
+    ['closecdata', undefined],
+    ['opencdata', undefined],
+    ['cdata', 'character data  '],
+    ['closecdata', undefined],
+    ['closetag', 'R']
   ]
-}).write("<r><![CDATA[ this is ]]>").write("<![CDA").write("T").write("A[")
-  .write("character data  ").write("]]></r>").close();
-
+}).write('<r><![CDATA[ this is ]]>').write('<![CDA').write('T').write('A[')
+  .write('character data  ').write(']]></r>').close()
diff --git a/test/cdata.js b/test/cdata.js
index 31a8a30..9fb8744 100644
--- a/test/cdata.js
+++ b/test/cdata.js
@@ -1,10 +1,11 @@
 require(__dirname).test({
-  xml : "<r><![CDATA[ this is character data  ]]></r>",
-  expect : [
-    ["opentag", {"name": "R","attributes": {}, "isSelfClosing": false}],
-    ["opencdata", undefined],
-    ["cdata", " this is character data  "],
-    ["closecdata", undefined],
-    ["closetag", "R"]
+  xml: '<r><![CDATA[ this is character data  ]]></r>',
+  expect: [
+    ['opentagstart', {'name': 'R', 'attributes': {}}],
+    ['opentag', {'name': 'R', 'attributes': {}, 'isSelfClosing': false}],
+    ['opencdata', undefined],
+    ['cdata', ' this is character data  '],
+    ['closecdata', undefined],
+    ['closetag', 'R']
   ]
-});
+})
diff --git a/test/cyrillic.js b/test/cyrillic.js
index f05dd1b..2740f06 100644
--- a/test/cyrillic.js
+++ b/test/cyrillic.js
@@ -1,8 +1,9 @@
 require(__dirname).test({
   xml: '<Р>тест</Р>',
   expect: [
-    ['opentag', {'name':'Р', attributes:{}, isSelfClosing: false}],
+    ['opentagstart', {'name': 'Р', attributes: {}}],
+    ['opentag', {'name': 'Р', attributes: {}, isSelfClosing: false}],
     ['text', 'тест'],
     ['closetag', 'Р']
   ]
-});
+})
diff --git a/test/duplicate-attribute.js b/test/duplicate-attribute.js
index a21eb41..0030362 100644
--- a/test/duplicate-attribute.js
+++ b/test/duplicate-attribute.js
@@ -1,13 +1,18 @@
-require(__dirname).test
-  ( { xml :
-      "<span id=\"hello\" id=\"there\"></span>"
-    , expect :
-      [ [ "attribute", { name: "ID", value: "hello" } ]
-      , [ "opentag", { name: "SPAN",
-                       attributes: { ID: "hello" }, isSelfClosing: false } ]
-      , [ "closetag", "SPAN" ]
-      ]
-    , strict : false
-    , opt : {}
-    }
-  )
+require(__dirname).test({
+  xml: '<span id="hello" id="there"></span>',
+  expect: [
+    [ 'opentagstart', {
+      name: 'SPAN',
+      attributes: {}
+    } ],
+    [ 'attribute', { name: 'ID', value: 'hello' } ],
+    [ 'opentag', {
+      name: 'SPAN',
+      attributes: { ID: 'hello' },
+      isSelfClosing: false
+    } ],
+    [ 'closetag', 'SPAN' ]
+  ],
+  strict: false,
+  opt: {}
+})
diff --git a/test/emoji.js b/test/emoji.js
new file mode 100644
index 0000000..bddf177
--- /dev/null
+++ b/test/emoji.js
@@ -0,0 +1,12 @@
+// split high-order numeric attributes into surrogate pairs
+require(__dirname).test({
+  xml: '<a>&#x1f525;</a>',
+  expect: [
+    [ 'opentagstart', { name: 'A', attributes: {} } ],
+    [ 'opentag', { name: 'A', attributes: {}, isSelfClosing: false } ],
+    [ 'text', '\ud83d\udd25' ],
+    [ 'closetag', 'A' ]
+  ],
+  strict: false,
+  opt: {}
+})
diff --git a/test/end_empty_stream.js b/test/end_empty_stream.js
new file mode 100644
index 0000000..f55efa8
--- /dev/null
+++ b/test/end_empty_stream.js
@@ -0,0 +1,5 @@
+var tap = require('tap')
+var saxStream = require('../lib/sax').createStream()
+tap.doesNotThrow(function () {
+  saxStream.end()
+})
diff --git a/test/entities.js b/test/entities.js
index 4901667..516ee17 100644
--- a/test/entities.js
+++ b/test/entities.js
@@ -1,10 +1,11 @@
 require(__dirname).test({
   xml: '<r>⌋ ' +
-       '♠ © → & ' +
-        '< < <  <   < > ℜ ℘ €</r>',
+    '♠ © → & ' +
+    '< < <  <   < > ℜ ℘ €</r>',
   expect: [
-    ['opentag', {'name':'R', attributes:{}, isSelfClosing: false}],
+    ['opentagstart', {'name': 'R', attributes: {}}],
+    ['opentag', {'name': 'R', attributes: {}, isSelfClosing: false}],
     ['text', '⌋ ♠ © → & < < <  <   < > ℜ ℘ €'],
     ['closetag', 'R']
   ]
-});
+})
diff --git a/test/entity-mega.js b/test/entity-mega.js
index 4759a02..d2c8d6b 100644
--- a/test/entity-mega.js
+++ b/test/entity-mega.js
@@ -1,6 +1,6 @@
-var sax = require('../');
-var xml = '<r>';
-var text = '';
+var sax = require('../')
+var xml = '<r>'
+var text = ''
 for (var i in sax.ENTITIES) {
   xml += '&' + i + ';'
   text += sax.ENTITIES[i]
@@ -9,8 +9,9 @@ xml += '</r>'
 require(__dirname).test({
   xml: xml,
   expect: [
-    ['opentag', {'name':'R', attributes:{}, isSelfClosing: false}],
+    ['opentagstart', {'name': 'R', attributes: {}}],
+    ['opentag', {'name': 'R', attributes: {}, isSelfClosing: false}],
     ['text', text],
     ['closetag', 'R']
   ]
-});
+})
diff --git a/test/entity-nan.js b/test/entity-nan.js
new file mode 100644
index 0000000..a56be4b
--- /dev/null
+++ b/test/entity-nan.js
@@ -0,0 +1,9 @@
+require(__dirname).test({
+  xml: '<r>&#NaN;</r>',
+  expect: [
+    ['opentagstart', {'name': 'R', attributes: {}}],
+    ['opentag', {'name': 'R', attributes: {}, isSelfClosing: false}],
+    ['text', '&#NaN;'],
+    ['closetag', 'R']
+  ]
+})
diff --git a/test/flush.js b/test/flush.js
new file mode 100644
index 0000000..b8b21e9
--- /dev/null
+++ b/test/flush.js
@@ -0,0 +1,14 @@
+var parser = require(__dirname).test({
+  expect: [
+    ['opentagstart', {'name': 'T', attributes: {}}],
+    ['opentag', {'name': 'T', attributes: {}, isSelfClosing: false}],
+    ['text', 'flush'],
+    ['text', 'rest'],
+    ['closetag', 'T']
+  ]
+})
+
+parser.write('<T>flush')
+parser.flush()
+parser.write('rest</T>')
+parser.close()
diff --git a/test/index.js b/test/index.js
index d4e1ef4..1df008f 100644
--- a/test/index.js
+++ b/test/index.js
@@ -1,9 +1,6 @@
-var globalsBefore = JSON.stringify(Object.keys(global))
-  , util = require("util")
-  , assert = require("assert")
-  , fs = require("fs")
-  , path = require("path")
-  , sax = require("../lib/sax")
+var sax = require('../lib/sax')
+
+var t = require('tap')
 
 exports.sax = sax
 
@@ -12,75 +9,49 @@ exports.sax = sax
 // otherwise, it's assumed that the test will write and close.
 exports.test = function test (options) {
   var xml = options.xml
-    , parser = sax.parser(options.strict, options.opt)
-    , expect = options.expect
-    , e = 0
+  var parser = sax.parser(options.strict, options.opt)
+  var expect = options.expect
+  var e = 0
   sax.EVENTS.forEach(function (ev) {
-    parser["on" + ev] = function (n) {
+    parser['on' + ev] = function (n) {
       if (process.env.DEBUG) {
-        console.error({ expect: expect[e]
-                      , actual: [ev, n] })
+        console.error({
+          expect: expect[e],
+          actual: [ev, n]
+        })
+      }
+      if (e >= expect.length && (ev === 'end' || ev === 'ready')) {
+        return
+      }
+      t.ok(e < expect.length, 'no unexpected events')
+
+      if (!expect[e]) {
+        t.fail('did not expect this event', {
+          event: ev,
+          expect: expect,
+          data: n
+        })
+        return
+      }
+
+      t.equal(ev, expect[e][0])
+      if (ev === 'error') {
+        t.equal(n.message, expect[e][1])
+      } else {
+        t.deepEqual(n, expect[e][1])
       }
-      if (e >= expect.length && (ev === "end" || ev === "ready")) return
-      assert.ok( e < expect.length,
-        "expectation #"+e+" "+util.inspect(expect[e])+"\n"+
-        "Unexpected event: "+ev+" "+(n ? util.inspect(n) : ""))
-      var inspected = n instanceof Error ? "\n"+ n.message : util.inspect(n)
-      assert.equal(ev, expect[e][0],
-        "expectation #"+e+"\n"+
-        "Didn't get expected event\n"+
-        "expect: "+expect[e][0] + " " +util.inspect(expect[e][1])+"\n"+
-        "actual: "+ev+" "+inspected+"\n")
-      if (ev === "error") assert.equal(n.message, expect[e][1])
-      else assert.deepEqual(n, expect[e][1],
-        "expectation #"+e+"\n"+
-        "Didn't get expected argument\n"+
-        "expect: "+expect[e][0] + " " +util.inspect(expect[e][1])+"\n"+
-        "actual: "+ev+" "+inspected+"\n")
       e++
-      if (ev === "error") parser.resume()
+      if (ev === 'error') {
+        parser.resume()
+      }
     }
   })
-  if (xml) parser.write(xml).close()
+  if (xml) {
+    parser.write(xml).close()
+  }
   return parser
 }
 
 if (module === require.main) {
-  var running = true
-    , failures = 0
-
-  function fail (file, er) {
-    util.error("Failed: "+file)
-    util.error(er.stack || er.message)
-    failures ++
-  }
-
-  fs.readdir(__dirname, function (error, files) {
-    files = files.filter(function (file) {
-      return (/\.js$/.exec(file) && file !== 'index.js')
-    })
-    var n = files.length
-      , i = 0
-    console.log("0.." + n)
-    files.forEach(function (file) {
-      // run this test.
-      try {
-        require(path.resolve(__dirname, file))
-        var globalsAfter = JSON.stringify(Object.keys(global))
-        if (globalsAfter !== globalsBefore) {
-          var er = new Error("new globals introduced\n"+
-                             "expected: "+globalsBefore+"\n"+
-                             "actual:   "+globalsAfter)
-          globalsBefore = globalsAfter
-          throw er
-        }
-        console.log("ok " + (++i) + " - " + file)
-      } catch (er) {
-        console.log("not ok "+ (++i) + " - " + file)
-        fail(file, er)
-      }
-    })
-    if (!failures) return console.log("#all pass")
-    else return console.error(failures + " failure" + (failures > 1 ? "s" : ""))
-  })
+  t.pass('common test file')
 }
diff --git a/test/issue-23.js b/test/issue-23.js
index ccbdc35..9ebee7e 100644
--- a/test/issue-23.js
+++ b/test/issue-23.js
@@ -1,43 +1,46 @@
-
-require(__dirname).test
-  ( { xml :
-      "<compileClassesResponse>"+
-        "<result>"+
-          "<bodyCrc>653724009</bodyCrc>"+
-          "<column>-1</column>"+
-          "<id>01pG0000002KoSUIA0</id>"+
-          "<line>-1</line>"+
-          "<name>CalendarController</name>"+
-          "<success>true</success>"+
-        "</result>"+
-      "</compileClassesResponse>"
-
-    , expect :
-      [ [ "opentag", { name: "COMPILECLASSESRESPONSE", attributes: {}, isSelfClosing: false } ]
-      , [ "opentag", { name : "RESULT", attributes: {}, isSelfClosing: false } ]
-      , [ "opentag", { name: "BODYCRC", attributes: {}, isSelfClosing: false } ]
-      , [ "text", "653724009" ]
-      , [ "closetag", "BODYCRC" ]
-      , [ "opentag", { name: "COLUMN", attributes: {}, isSelfClosing: false } ]
-      , [ "text", "-1" ]
-      , [ "closetag", "COLUMN" ]
-      , [ "opentag", { name: "ID", attributes: {}, isSelfClosing: false } ]
-      , [ "text", "01pG0000002KoSUIA0" ]
-      , [ "closetag", "ID" ]
-      , [ "opentag", {name: "LINE", attributes: {}, isSelfClosing: false } ]
-      , [ "text", "-1" ]
-      , [ "closetag", "LINE" ]
-      , [ "opentag", {name: "NAME", attributes: {}, isSelfClosing: false } ]
-      , [ "text", "CalendarController" ]
-      , [ "closetag", "NAME" ]
-      , [ "opentag", {name: "SUCCESS", attributes: {}, isSelfClosing: false } ]
-      , [ "text", "true" ]
-      , [ "closetag", "SUCCESS" ]
-      , [ "closetag", "RESULT" ]
-      , [ "closetag", "COMPILECLASSESRESPONSE" ]
-      ]
-    , strict : false
-    , opt : {}
-    }
-  )
-
+require(__dirname).test({
+  xml: '<compileClassesResponse>' +
+    '<result>' +
+    '<bodyCrc>653724009</bodyCrc>' +
+    '<column>-1</column>' +
+    '<id>01pG0000002KoSUIA0</id>' +
+    '<line>-1</line>' +
+    '<name>CalendarController</name>' +
+    '<success>true</success>' +
+    '</result>' +
+    '</compileClassesResponse>',
+  expect: [
+    [ 'opentagstart', { name: 'COMPILECLASSESRESPONSE', attributes: {} } ],
+    [ 'opentag', { name: 'COMPILECLASSESRESPONSE', attributes: {}, isSelfClosing: false } ],
+    [ 'opentagstart', { name: 'RESULT', attributes: {} } ],
+    [ 'opentag', { name: 'RESULT', attributes: {}, isSelfClosing: false } ],
+    [ 'opentagstart', { name: 'BODYCRC', attributes: {} } ],
+    [ 'opentag', { name: 'BODYCRC', attributes: {}, isSelfClosing: false } ],
+    [ 'text', '653724009' ],
+    [ 'closetag', 'BODYCRC' ],
+    [ 'opentagstart', { name: 'COLUMN', attributes: {} } ],
+    [ 'opentag', { name: 'COLUMN', attributes: {}, isSelfClosing: false } ],
+    [ 'text', '-1' ],
+    [ 'closetag', 'COLUMN' ],
+    [ 'opentagstart', { name: 'ID', attributes: {} } ],
+    [ 'opentag', { name: 'ID', attributes: {}, isSelfClosing: false } ],
+    [ 'text', '01pG0000002KoSUIA0' ],
+    [ 'closetag', 'ID' ],
+    [ 'opentagstart', { name: 'LINE', attributes: {} } ],
+    [ 'opentag', { name: 'LINE', attributes: {}, isSelfClosing: false } ],
+    [ 'text', '-1' ],
+    [ 'closetag', 'LINE' ],
+    [ 'opentagstart', { name: 'NAME', attributes: {} } ],
+    [ 'opentag', { name: 'NAME', attributes: {}, isSelfClosing: false } ],
+    [ 'text', 'CalendarController' ],
+    [ 'closetag', 'NAME' ],
+    [ 'opentagstart', { name: 'SUCCESS', attributes: {} } ],
+    [ 'opentag', { name: 'SUCCESS', attributes: {}, isSelfClosing: false } ],
+    [ 'text', 'true' ],
+    [ 'closetag', 'SUCCESS' ],
+    [ 'closetag', 'RESULT' ],
+    [ 'closetag', 'COMPILECLASSESRESPONSE' ]
+  ],
+  strict: false,
+  opt: {}
+})
diff --git a/test/issue-30.js b/test/issue-30.js
index 771b14e..0c79cb2 100644
--- a/test/issue-30.js
+++ b/test/issue-30.js
@@ -1,24 +1,23 @@
 // https://github.com/isaacs/sax-js/issues/33
-require(__dirname).test
-  ( { xml : "<xml>\n"+
-            "<!-- \n"+
-            "  comment with a single dash- in it\n"+
-            "-->\n"+
-            "<data/>\n"+
-            "</xml>"
-
-    , expect :
-      [ [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ]
-      , [ "text", "\n" ]
-      , [ "comment", " \n  comment with a single dash- in it\n" ]
-      , [ "text", "\n" ]
-      , [ "opentag", { name: "data", attributes: {}, isSelfClosing: true } ]
-      , [ "closetag", "data" ]
-      , [ "text", "\n" ]
-      , [ "closetag", "xml" ]
-      ]
-    , strict : true
-    , opt : {}
-    }
-  )
-
+require(__dirname).test({
+  xml: '<xml>\n' +
+    '<!-- \n' +
+    '  comment with a single dash- in it\n' +
+    '-->\n' +
+    '<data/>\n' +
+    '</xml>',
+  expect: [
+    [ 'opentagstart', { name: 'xml', attributes: {} } ],
+    [ 'opentag', { name: 'xml', attributes: {}, isSelfClosing: false } ],
+    [ 'text', '\n' ],
+    [ 'comment', ' \n  comment with a single dash- in it\n' ],
+    [ 'text', '\n' ],
+    [ 'opentagstart', { name: 'data', attributes: {} } ],
+    [ 'opentag', { name: 'data', attributes: {}, isSelfClosing: true } ],
+    [ 'closetag', 'data' ],
+    [ 'text', '\n' ],
+    [ 'closetag', 'xml' ]
+  ],
+  strict: true,
+  opt: {}
+})
diff --git a/test/issue-35.js b/test/issue-35.js
index 64d67b3..ed0c6c0 100644
--- a/test/issue-35.js
+++ b/test/issue-35.js
@@ -1,15 +1,12 @@
 // https://github.com/isaacs/sax-js/issues/35
-require(__dirname).test
-  ( { xml : "<xml>&#Xd;&#X0d;\n"+
-            "</xml>"
-
-    , expect :
-      [ [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ]
-      , [ "text", "\r\r\n" ]
-      , [ "closetag", "xml" ]
-      ]
-    , strict : true
-    , opt : {}
-    }
-  )
-
+require(__dirname).test({
+  xml: '<xml>&#Xd;&#X0d;\n</xml>',
+  expect: [
+    [ 'opentagstart', { name: 'xml', attributes: {} } ],
+    [ 'opentag', { name: 'xml', attributes: {}, isSelfClosing: false } ],
+    [ 'text', '\r\r\n' ],
+    [ 'closetag', 'xml' ]
+  ],
+  strict: true,
+  opt: {}
+})
diff --git a/test/issue-47.js b/test/issue-47.js
index 661584a..2b85e13 100644
--- a/test/issue-47.js
+++ b/test/issue-47.js
@@ -1,12 +1,11 @@
 // https://github.com/isaacs/sax-js/issues/47
-require(__dirname).test
-  ( { xml : '<a href="query.svc?x=1&y=2&z=3"/>'
-    , expect : [
-        [ "attribute", { name:'HREF', value:"query.svc?x=1&y=2&z=3"} ],
-        [ "opentag", { name: "A", attributes: { HREF:"query.svc?x=1&y=2&z=3"}, isSelfClosing: true } ],
-        [ "closetag", "A" ]
-      ]
-    , opt : {}
-    }
-  )
-
+require(__dirname).test({
+  xml: '<a href="query.svc?x=1&y=2&z=3"/>',
+  expect: [
+    [ 'opentagstart', { name: 'A', attributes: {} } ],
+    [ 'attribute', { name: 'HREF', value: 'query.svc?x=1&y=2&z=3' } ],
+    [ 'opentag', { name: 'A', attributes: { HREF: 'query.svc?x=1&y=2&z=3' }, isSelfClosing: true } ],
+    [ 'closetag', 'A' ]
+  ],
+  opt: {}
+})
diff --git a/test/issue-49.js b/test/issue-49.js
index ff2fbf7..7918666 100644
--- a/test/issue-49.js
+++ b/test/issue-49.js
@@ -1,31 +1,32 @@
 // https://github.com/isaacs/sax-js/issues/49
-require(__dirname).test
-  ( { xml : "<xml><script>hello world</script></xml>"
-    , expect :
-      [ [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ]
-      , [ "opentag", { name: "script", attributes: {}, isSelfClosing: false } ]
-      , [ "text", "hello world" ]
-      , [ "closetag", "script" ]
-      , [ "closetag", "xml" ]
-      ]
-    , strict : false
-    , opt : { lowercasetags: true, noscript: true }
-    }
-  )
-
-require(__dirname).test
-  ( { xml : "<xml><script><![CDATA[hello world]]></script></xml>"
-    , expect :
-      [ [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ]
-      , [ "opentag", { name: "script", attributes: {}, isSelfClosing: false } ]
-      , [ "opencdata", undefined ]
-      , [ "cdata", "hello world" ]
-      , [ "closecdata", undefined ]
-      , [ "closetag", "script" ]
-      , [ "closetag", "xml" ]
-      ]
-    , strict : false
-    , opt : { lowercasetags: true, noscript: true }
-    }
-  )
+require(__dirname).test({
+  xml: '<xml><script>hello world</script></xml>',
+  expect: [
+    [ 'opentagstart', { name: 'xml', attributes: {} } ],
+    [ 'opentag', { name: 'xml', attributes: {}, isSelfClosing: false } ],
+    [ 'opentagstart', { name: 'script', attributes: {} } ],
+    [ 'opentag', { name: 'script', attributes: {}, isSelfClosing: false } ],
+    [ 'text', 'hello world' ],
+    [ 'closetag', 'script' ],
+    [ 'closetag', 'xml' ]
+  ],
+  strict: false,
+  opt: { lowercasetags: true, noscript: true }
+})
 
+require(__dirname).test({
+  xml: '<xml><script><![CDATA[hello world]]></script></xml>',
+  expect: [
+    [ 'opentagstart', { name: 'xml', attributes: {} } ],
+    [ 'opentag', { name: 'xml', attributes: {}, isSelfClosing: false } ],
+    [ 'opentagstart', { name: 'script', attributes: {} } ],
+    [ 'opentag', { name: 'script', attributes: {}, isSelfClosing: false } ],
+    [ 'opencdata', undefined ],
+    [ 'cdata', 'hello world' ],
+    [ 'closecdata', undefined ],
+    [ 'closetag', 'script' ],
+    [ 'closetag', 'xml' ]
+  ],
+  strict: false,
+  opt: { lowercasetags: true, noscript: true }
+})
diff --git a/test/issue-84.js b/test/issue-84.js
index 0e7ee69..9a2195e 100644
--- a/test/issue-84.js
+++ b/test/issue-84.js
@@ -1,13 +1,13 @@
 // https://github.com/isaacs/sax-js/issues/49
-require(__dirname).test
-  ( { xml : "<?has unbalanced \"quotes?><xml>body</xml>"
-    , expect :
-      [ [ "processinginstruction", { name: "has", body: "unbalanced \"quotes" } ],
-        [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ]
-      , [ "text", "body" ]
-      , [ "closetag", "xml" ]
-      ]
-    , strict : false
-    , opt : { lowercasetags: true, noscript: true }
-    }
-  )
+require(__dirname).test({
+  xml: '<?has unbalanced "quotes?><xml>body</xml>',
+  expect: [
+    [ 'processinginstruction', { name: 'has', body: 'unbalanced "quotes' } ],
+    [ 'opentagstart', { name: 'xml', attributes: {} } ],
+    [ 'opentag', { name: 'xml', attributes: {}, isSelfClosing: false } ],
+    [ 'text', 'body' ],
+    [ 'closetag', 'xml' ]
+  ],
+  strict: false,
+  opt: { lowercasetags: true, noscript: true }
+})
diff --git a/test/issue-86.js b/test/issue-86.js
new file mode 100644
index 0000000..00e27d5
--- /dev/null
+++ b/test/issue-86.js
@@ -0,0 +1,85 @@
+require(__dirname).test({
+  xml: '<root>abc</root>de<f',
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'ROOT',
+        attributes: {}
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'ROOT',
+        attributes: {},
+        isSelfClosing: false
+      }
+    ],
+    [
+      'text',
+      'abc'
+    ],
+    [
+      'closetag',
+      'ROOT'
+    ],
+    [
+      'text',
+      'de<f'
+    ]
+  ],
+  strict: false,
+  opt: {}
+})
+
+require(__dirname).test({
+  xml: '<root>abc</root>de<f',
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'root',
+        attributes: {}
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'root',
+        attributes: {},
+        isSelfClosing: false
+      }
+    ],
+    [
+      'text',
+      'abc'
+    ],
+    [
+      'closetag',
+      'root'
+    ],
+    [
+      'error',
+      'Text data outside of root node.\nLine: 0\nColumn: 17\nChar: d'
+    ],
+    [
+      'text',
+      'd'
+    ],
+    [
+      'error',
+      'Text data outside of root node.\nLine: 0\nColumn: 18\nChar: e'
+    ],
+    [
+      'text',
+      'e'
+    ],
+    [
+      'error',
+      'Unexpected end\nLine: 0\nColumn: 20\nChar: '
+    ]
+  ],
+  strict: true,
+  opt: {}
+})
diff --git a/test/not-string.js b/test/not-string.js
new file mode 100644
index 0000000..86111e3
--- /dev/null
+++ b/test/not-string.js
@@ -0,0 +1,8 @@
+var parser = require('../').parser(true)
+var t = require('tap')
+t.plan(1)
+parser.onopentag = function (node) {
+  t.same(node, { name: 'x', attributes: {}, isSelfClosing: false })
+}
+var xml = new Buffer('<x>y</x>')
+parser.write(xml).close()
diff --git a/test/opentagstart.js b/test/opentagstart.js
new file mode 100644
index 0000000..6aeb019
--- /dev/null
+++ b/test/opentagstart.js
@@ -0,0 +1,86 @@
+require(__dirname).test({
+  xml: "<root length='12345'></root>",
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'root',
+        ns: {},
+        attributes: {}
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'length',
+        value: '12345',
+        prefix: '',
+        local: 'length',
+        uri: ''
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'root',
+        prefix: '',
+        local: 'root',
+        uri: '',
+        attributes: {
+          length: {
+            name: 'length',
+            value: '12345',
+            prefix: '',
+            local: 'length',
+            uri: ''
+          }
+        },
+        ns: {},
+        isSelfClosing: false
+      }
+    ],
+    [
+      'closetag',
+      'root'
+    ]
+  ],
+  strict: true,
+  opt: {
+    xmlns: true
+  }
+})
+
+require(__dirname).test({
+  xml: "<root length='12345'></root>",
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'root',
+        attributes: {}
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'length',
+        value: '12345'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'root',
+        attributes: {
+          length: '12345'
+        },
+        isSelfClosing: false
+      }
+    ],
+    [
+      'closetag',
+      'root'
+    ]
+  ],
+  strict: true
+})
diff --git a/test/parser-position.js b/test/parser-position.js
index e4a68b1..3e04887 100644
--- a/test/parser-position.js
+++ b/test/parser-position.js
@@ -1,28 +1,30 @@
-var sax = require("../lib/sax"),
-    assert = require("assert")
+var sax = require('../lib/sax')
+var tap = require('tap')
 
-function testPosition(chunks, expectedEvents) {
-  var parser = sax.parser();
-  expectedEvents.forEach(function(expectation) {
-    parser['on' + expectation[0]] = function() {
+function testPosition (chunks, expectedEvents) {
+  var parser = sax.parser()
+  expectedEvents.forEach(function (expectation) {
+    parser['on' + expectation[0]] = function () {
       for (var prop in expectation[1]) {
-        assert.equal(parser[prop], expectation[1][prop]);
+        tap.equal(parser[prop], expectation[1][prop])
       }
     }
-  });
-  chunks.forEach(function(chunk) {
-    parser.write(chunk);
-  });
-};
+  })
+  chunks.forEach(function (chunk) {
+    parser.write(chunk)
+  })
+}
 
-testPosition(['<div>abcdefgh</div>'],
-             [ ['opentag',  { position:  5, startTagPosition:  1 }]
-             , ['text',     { position: 19, startTagPosition: 14 }]
-             , ['closetag', { position: 19, startTagPosition: 14 }]
-             ]);
+testPosition(['<div>abcdefgh</div>'], [
+  [ 'opentagstart', { position: 5, startTagPosition: 1 } ],
+  [ 'opentag', { position: 5, startTagPosition: 1 } ],
+  [ 'text', { position: 19, startTagPosition: 14 } ],
+  [ 'closetag', { position: 19, startTagPosition: 14 } ]
+])
 
-testPosition(['<div>abcde','fgh</div>'],
-             [ ['opentag',  { position:  5, startTagPosition:  1 }]
-             , ['text',     { position: 19, startTagPosition: 14 }]
-             , ['closetag', { position: 19, startTagPosition: 14 }]
-             ]);
+testPosition(['<div>abcde', 'fgh</div>'], [
+  ['opentagstart', { position: 5, startTagPosition: 1 }],
+  ['opentag', { position: 5, startTagPosition: 1 }],
+  ['text', { position: 19, startTagPosition: 14 }],
+  ['closetag', { position: 19, startTagPosition: 14 }]
+])
diff --git a/test/script-close-better.js b/test/script-close-better.js
index f4887b9..a796693 100644
--- a/test/script-close-better.js
+++ b/test/script-close-better.js
@@ -1,12 +1,15 @@
 require(__dirname).test({
-  xml : "<html><head><script>'<div>foo</div></'</script></head></html>",
-  expect : [
-    ["opentag", {"name": "HTML","attributes": {}, isSelfClosing: false}],
-    ["opentag", {"name": "HEAD","attributes": {}, isSelfClosing: false}],
-    ["opentag", {"name": "SCRIPT","attributes": {}, isSelfClosing: false}],
-    ["script", "'<div>foo</div></'"],
-    ["closetag", "SCRIPT"],
-    ["closetag", "HEAD"],
-    ["closetag", "HTML"]
+  xml: "<html><head><script>'<div>foo</div></'</script></head></html>",
+  expect: [
+    ['opentagstart', {'name': 'HTML', 'attributes': {}}],
+    ['opentag', {'name': 'HTML', 'attributes': {}, isSelfClosing: false}],
+    ['opentagstart', {'name': 'HEAD', 'attributes': {}}],
+    ['opentag', {'name': 'HEAD', 'attributes': {}, isSelfClosing: false}],
+    ['opentagstart', {'name': 'SCRIPT', 'attributes': {}}],
+    ['opentag', {'name': 'SCRIPT', 'attributes': {}, isSelfClosing: false}],
+    ['script', "'<div>foo</div></'"],
+    ['closetag', 'SCRIPT'],
+    ['closetag', 'HEAD'],
+    ['closetag', 'HTML']
   ]
-});
+})
diff --git a/test/script.js b/test/script.js
index fbda1f6..c30d6dc 100644
--- a/test/script.js
+++ b/test/script.js
@@ -1,12 +1,66 @@
 require(__dirname).test({
-  xml : "<html><head><script>if (1 < 0) { console.log('elo there'); }</script></head></html>",
-  expect : [
-    ["opentag", {"name": "HTML","attributes": {}, "isSelfClosing": false}],
-    ["opentag", {"name": "HEAD","attributes": {}, "isSelfClosing": false}],
-    ["opentag", {"name": "SCRIPT","attributes": {}, "isSelfClosing": false}],
-    ["script", "if (1 < 0) { console.log('elo there'); }"],
-    ["closetag", "SCRIPT"],
-    ["closetag", "HEAD"],
-    ["closetag", "HTML"]
+  xml: "<html><head><script>if (1 < 0) { console.log('elo there'); }</script></head></html>",
+  expect: [
+    [
+      'opentagstart',
+      {
+        'name': 'HTML',
+        'attributes': {}
+      }
+    ],
+    [
+      'opentag',
+      {
+        'name': 'HTML',
+        'attributes': {},
+        'isSelfClosing': false
+      }
+    ],
+    [
+      'opentagstart',
+      {
+        'name': 'HEAD',
+        'attributes': {}
+      }
+    ],
+    [
+      'opentag',
+      {
+        'name': 'HEAD',
+        'attributes': {},
+        'isSelfClosing': false
+      }
+    ],
+    [
+      'opentagstart',
+      {
+        'name': 'SCRIPT',
+        'attributes': {}
+      }
+    ],
+    [
+      'opentag',
+      {
+        'name': 'SCRIPT',
+        'attributes': {},
+        'isSelfClosing': false
+      }
+    ],
+    [
+      'script',
+      "if (1 < 0) { console.log('elo there'); }"
+    ],
+    [
+      'closetag',
+      'SCRIPT'
+    ],
+    [
+      'closetag',
+      'HEAD'
+    ],
+    [
+      'closetag',
+      'HTML'
+    ]
   ]
-});
+})
diff --git a/test/self-closing-child-strict.js b/test/self-closing-child-strict.js
index 3d6e985..359670a 100644
--- a/test/self-closing-child-strict.js
+++ b/test/self-closing-child-strict.js
@@ -1,44 +1,57 @@
-
 require(__dirname).test({
-  xml :
-  "<root>"+
-    "<child>" +
-      "<haha />" +
-    "</child>" +
-    "<monkey>" +
-      "=(|)" +
-    "</monkey>" +
-  "</root>",
-  expect : [
-    ["opentag", {
-     "name": "root",
-     "attributes": {},
-     "isSelfClosing": false
-    }],
-    ["opentag", {
-     "name": "child",
-     "attributes": {},
-     "isSelfClosing": false
-    }],
-    ["opentag", {
-     "name": "haha",
-     "attributes": {},
-     "isSelfClosing": true
-    }],
-    ["closetag", "haha"],
-    ["closetag", "child"],
-    ["opentag", {
-     "name": "monkey",
-     "attributes": {},
-     "isSelfClosing": false
-    }],
-    ["text", "=(|)"],
-    ["closetag", "monkey"],
-    ["closetag", "root"],
-    ["end"],
-    ["ready"]
+  xml: '<root>' +
+    '<child>' +
+    '<haha />' +
+    '</child>' +
+    '<monkey>' +
+    '=(|)' +
+    '</monkey>' +
+    '</root>',
+  expect: [
+    ['opentagstart', {
+      'name': 'root',
+      'attributes': {}
+    }],
+    ['opentag', {
+      'name': 'root',
+      'attributes': {},
+      'isSelfClosing': false
+    }],
+    ['opentagstart', {
+      'name': 'child',
+      'attributes': {}
+    }],
+    ['opentag', {
+      'name': 'child',
+      'attributes': {},
+      'isSelfClosing': false
+    }],
+    ['opentagstart', {
+      'name': 'haha',
+      'attributes': {}
+    }],
+    ['opentag', {
+      'name': 'haha',
+      'attributes': {},
+      'isSelfClosing': true
+    }],
+    ['closetag', 'haha'],
+    ['closetag', 'child'],
+    ['opentagstart', {
+      'name': 'monkey',
+      'attributes': {}
+    }],
+    ['opentag', {
+      'name': 'monkey',
+      'attributes': {},
+      'isSelfClosing': false
+    }],
+    ['text', '=(|)'],
+    ['closetag', 'monkey'],
+    ['closetag', 'root'],
+    ['end'],
+    ['ready']
   ],
-  strict : true,
-  opt : {}
-});
-
+  strict: true,
+  opt: {}
+})
diff --git a/test/self-closing-child.js b/test/self-closing-child.js
index f31c366..e24a17b 100644
--- a/test/self-closing-child.js
+++ b/test/self-closing-child.js
@@ -1,44 +1,57 @@
-
 require(__dirname).test({
-  xml :
-  "<root>"+
-    "<child>" +
-      "<haha />" +
-    "</child>" +
-    "<monkey>" +
-      "=(|)" +
-    "</monkey>" +
-  "</root>",
-  expect : [
-    ["opentag", {
-     "name": "ROOT",
-     "attributes": {},
-     "isSelfClosing": false
-    }],
-    ["opentag", {
-     "name": "CHILD",
-     "attributes": {},
-     "isSelfClosing": false
-    }],
-    ["opentag", {
-     "name": "HAHA",
-     "attributes": {},
-     "isSelfClosing": true
-    }],
-    ["closetag", "HAHA"],
-    ["closetag", "CHILD"],
-    ["opentag", {
-     "name": "MONKEY",
-     "attributes": {},
-     "isSelfClosing": false
-    }],
-    ["text", "=(|)"],
-    ["closetag", "MONKEY"],
-    ["closetag", "ROOT"],
-    ["end"],
-    ["ready"]
+  xml: '<root>' +
+    '<child>' +
+    '<haha />' +
+    '</child>' +
+    '<monkey>' +
+    '=(|)' +
+    '</monkey>' +
+    '</root>',
+  expect: [
+    ['opentagstart', {
+      'name': 'ROOT',
+      'attributes': {}
+    }],
+    ['opentag', {
+      'name': 'ROOT',
+      'attributes': {},
+      'isSelfClosing': false
+    }],
+    ['opentagstart', {
+      'name': 'CHILD',
+      'attributes': {}
+    }],
+    ['opentag', {
+      'name': 'CHILD',
+      'attributes': {},
+      'isSelfClosing': false
+    }],
+    ['opentagstart', {
+      'name': 'HAHA',
+      'attributes': {}
+    }],
+    ['opentag', {
+      'name': 'HAHA',
+      'attributes': {},
+      'isSelfClosing': true
+    }],
+    ['closetag', 'HAHA'],
+    ['closetag', 'CHILD'],
+    ['opentagstart', {
+      'name': 'MONKEY',
+      'attributes': {}
+    }],
+    ['opentag', {
+      'name': 'MONKEY',
+      'attributes': {},
+      'isSelfClosing': false
+    }],
+    ['text', '=(|)'],
+    ['closetag', 'MONKEY'],
+    ['closetag', 'ROOT'],
+    ['end'],
+    ['ready']
   ],
-  strict : false,
-  opt : {}
-});
-
+  strict: false,
+  opt: {}
+})
diff --git a/test/self-closing-tag.js b/test/self-closing-tag.js
index d1d8b7c..4e1bd7d 100644
--- a/test/self-closing-tag.js
+++ b/test/self-closing-tag.js
@@ -1,25 +1,27 @@
-
 require(__dirname).test({
-  xml :
-  "<root>   "+
-    "<haha /> "+
-    "<haha/>  "+
-    "<monkey> "+
-      "=(|)     "+
-    "</monkey>"+
-  "</root>  ",
-  expect : [
-    ["opentag", {name:"ROOT", attributes:{}, isSelfClosing: false}],
-    ["opentag", {name:"HAHA", attributes:{}, isSelfClosing: true}],
-    ["closetag", "HAHA"],
-    ["opentag", {name:"HAHA", attributes:{}, isSelfClosing: true}],
-    ["closetag", "HAHA"],
+  xml: '<root>   ' +
+    '<haha /> ' +
+    '<haha/>  ' +
+    '<monkey> ' +
+    '=(|)     ' +
+    '</monkey>' +
+    '</root>  ',
+  expect: [
+    ['opentagstart', {name: 'ROOT', attributes: {}}],
+    ['opentag', {name: 'ROOT', attributes: {}, isSelfClosing: false}],
+    ['opentagstart', {name: 'HAHA', attributes: {}}],
+    ['opentag', {name: 'HAHA', attributes: {}, isSelfClosing: true}],
+    ['closetag', 'HAHA'],
+    ['opentagstart', {name: 'HAHA', attributes: {}}],
+    ['opentag', {name: 'HAHA', attributes: {}, isSelfClosing: true}],
+    ['closetag', 'HAHA'],
     // ["opentag", {name:"HAHA", attributes:{}}],
     // ["closetag", "HAHA"],
-    ["opentag", {name:"MONKEY", attributes:{}, isSelfClosing: false}],
-    ["text", "=(|)"],
-    ["closetag", "MONKEY"],
-    ["closetag", "ROOT"]
+    ['opentagstart', {name: 'MONKEY', attributes: {}}],
+    ['opentag', {name: 'MONKEY', attributes: {}, isSelfClosing: false}],
+    ['text', '=(|)'],
+    ['closetag', 'MONKEY'],
+    ['closetag', 'ROOT']
   ],
-  opt : { trim : true }
-});
\ No newline at end of file
+  opt: { trim: true }
+})
diff --git a/test/stand-alone-comment.js b/test/stand-alone-comment.js
new file mode 100644
index 0000000..a13a8b0
--- /dev/null
+++ b/test/stand-alone-comment.js
@@ -0,0 +1,12 @@
+// https://github.com/isaacs/sax-js/issues/124
+require(__dirname).test({
+  xml: '<!-- stand alone comment -->',
+  expect: [
+    [
+      'comment',
+      ' stand alone comment '
+    ]
+  ],
+  strict: true,
+  opt: {}
+})
diff --git a/test/stray-ending.js b/test/stray-ending.js
index bec467b..2577c48 100644
--- a/test/stray-ending.js
+++ b/test/stray-ending.js
@@ -1,17 +1,51 @@
 // stray ending tags should just be ignored in non-strict mode.
 // https://github.com/isaacs/sax-js/issues/32
-require(__dirname).test
-  ( { xml :
-      "<a><b></c></b></a>"
-    , expect :
-      [ [ "opentag", { name: "A", attributes: {}, isSelfClosing: false } ]
-      , [ "opentag", { name: "B", attributes: {}, isSelfClosing: false } ]
-      , [ "text", "</c>" ]
-      , [ "closetag", "B" ]
-      , [ "closetag", "A" ]
-      ]
-    , strict : false
-    , opt : {}
-    }
-  )
-
+require(__dirname).test({
+  xml: '<a><b></c></b></a>',
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'A',
+        attributes: {}
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'A',
+        attributes: {},
+        isSelfClosing: false
+      }
+    ],
+    [
+      'opentagstart',
+      {
+        name: 'B',
+        attributes: {}
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'B',
+        attributes: {},
+        isSelfClosing: false
+      }
+    ],
+    [
+      'text',
+      '</c>'
+    ],
+    [
+      'closetag',
+      'B'
+    ],
+    [
+      'closetag',
+      'A'
+    ]
+  ],
+  strict: false,
+  opt: {}
+})
diff --git a/test/trailing-attribute-no-value.js b/test/trailing-attribute-no-value.js
index 222837f..e640322 100644
--- a/test/trailing-attribute-no-value.js
+++ b/test/trailing-attribute-no-value.js
@@ -1,10 +1,9 @@
-
 require(__dirname).test({
-  xml :
-  "<root attrib>",
-  expect : [
-    ["attribute", {name:"ATTRIB", value:"attrib"}],
-    ["opentag", {name:"ROOT", attributes:{"ATTRIB":"attrib"}, isSelfClosing: false}]
+  xml: '<root attrib>',
+  expect: [
+    ['opentagstart', {name: 'ROOT', attributes: {}}],
+    ['attribute', {name: 'ATTRIB', value: 'attrib'}],
+    ['opentag', {name: 'ROOT', attributes: {'ATTRIB': 'attrib'}, isSelfClosing: false}]
   ],
-  opt : { trim : true }
-});
+  opt: { trim: true }
+})
diff --git a/test/trailing-non-whitespace.js b/test/trailing-non-whitespace.js
index 619578b..8212d6c 100644
--- a/test/trailing-non-whitespace.js
+++ b/test/trailing-non-whitespace.js
@@ -1,18 +1,21 @@
-
 require(__dirname).test({
-  xml : "<span>Welcome,</span> to monkey land",
-  expect : [
-    ["opentag", {
-     "name": "SPAN",
-     "attributes": {},
-     isSelfClosing: false
+  xml: '<span>Welcome,</span> to monkey land',
+  expect: [
+    ['opentagstart', {
+      'name': 'SPAN',
+      'attributes': {}
     }],
-    ["text", "Welcome,"],
-    ["closetag", "SPAN"],
-    ["text", " to monkey land"],
-    ["end"],
-    ["ready"]
+    ['opentag', {
+      'name': 'SPAN',
+      'attributes': {},
+      isSelfClosing: false
+    }],
+    ['text', 'Welcome,'],
+    ['closetag', 'SPAN'],
+    ['text', ' to monkey land'],
+    ['end'],
+    ['ready']
   ],
-  strict : false,
-  opt : {}
-});
+  strict: false,
+  opt: {}
+})
diff --git a/test/unclosed-root.js b/test/unclosed-root.js
index f4eeac6..dbd1178 100644
--- a/test/unclosed-root.js
+++ b/test/unclosed-root.js
@@ -1,11 +1,26 @@
-require(__dirname).test
-  ( { xml : "<root>"
-
-    , expect :
-      [ [ "opentag", { name: "root", attributes: {}, isSelfClosing: false } ]
-      , [ "error", "Unclosed root tag\nLine: 0\nColumn: 6\nChar: " ]
-      ]
-    , strict : true
-    , opt : {}
-    }
-  )
+require(__dirname).test({
+  xml: '<root>',
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'root',
+        attributes: {}
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'root',
+        attributes: {},
+        isSelfClosing: false
+      }
+    ],
+    [
+      'error',
+      'Unclosed root tag\nLine: 0\nColumn: 6\nChar: '
+    ]
+  ],
+  strict: true,
+  opt: {}
+})
diff --git a/test/unquoted.js b/test/unquoted.js
index b3a9a81..4bbd511 100644
--- a/test/unquoted.js
+++ b/test/unquoted.js
@@ -1,18 +1,45 @@
 // unquoted attributes should be ok in non-strict mode
 // https://github.com/isaacs/sax-js/issues/31
-require(__dirname).test
-  ( { xml :
-      "<span class=test hello=world></span>"
-    , expect :
-      [ [ "attribute", { name: "CLASS", value: "test" } ]
-      , [ "attribute", { name: "HELLO", value: "world" } ]
-      , [ "opentag", { name: "SPAN",
-                       attributes: { CLASS: "test", HELLO: "world" },
-                       isSelfClosing: false } ]
-      , [ "closetag", "SPAN" ]
-      ]
-    , strict : false
-    , opt : {}
-    }
-  )
-
+require(__dirname).test({
+  xml: '<span class=test hello=world></span>',
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'SPAN',
+        attributes: {}
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'CLASS',
+        value: 'test'
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'HELLO',
+        value: 'world'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'SPAN',
+        attributes: {
+          CLASS: 'test',
+          HELLO: 'world'
+        },
+        isSelfClosing: false
+      }
+    ],
+    [
+      'closetag',
+      'SPAN'
+    ]
+  ],
+  strict: false,
+  opt: {}
+})
diff --git a/test/utf8-split.js b/test/utf8-split.js
index e22bc10..80047e2 100644
--- a/test/utf8-split.js
+++ b/test/utf8-split.js
@@ -1,10 +1,10 @@
-var assert = require('assert')
+var tap = require('tap')
 var saxStream = require('../lib/sax').createStream()
 
 var b = new Buffer('误')
 
-saxStream.on('text', function(text) {
-  assert.equal(text, b.toString())
+saxStream.on('text', function (text) {
+  tap.equal(text, b.toString())
 })
 
 saxStream.write(new Buffer('<test><a>'))
@@ -21,12 +21,14 @@ saxStream.end(Buffer.concat([b.slice(1), new Buffer('</d></test>')]))
 
 var saxStream2 = require('../lib/sax').createStream()
 
-saxStream2.on('text', function(text) {
-  assert.equal(text, '�')
-});
+saxStream2.on('text', function (text) {
+  tap.equal(text, '�')
+})
 
-saxStream2.write(new Buffer('<e>'));
-saxStream2.write(new Buffer([0xC0]));
-saxStream2.write(new Buffer('</e>'));
-saxStream2.write(Buffer.concat([new Buffer('<f>'), b.slice(0,1)]));
-saxStream2.end();
+saxStream2.write(new Buffer('<root>'))
+saxStream2.write(new Buffer('<e>'))
+saxStream2.write(new Buffer([0xC0]))
+saxStream2.write(new Buffer('</e>'))
+saxStream2.write(Buffer.concat([new Buffer('<f>'), b.slice(0, 1)]))
+saxStream2.write(new Buffer('</root>'))
+saxStream2.end()
diff --git a/test/xml-internal-entities.js b/test/xml-internal-entities.js
new file mode 100644
index 0000000..3c49e50
--- /dev/null
+++ b/test/xml-internal-entities.js
@@ -0,0 +1,92 @@
+var iExpect = []
+var myAttributes = {}
+var ENTITIES = {}
+
+// generates xml like test0="&control;"
+var entitiesToTest = {
+  // 'ENTITY_NAME': IS_VALID || [invalidCharPos, invalidChar],
+  'control0': true, // This is a vanilla control.
+  // entityStart
+  '_uscore': true,
+  '#hash': true,
+  ':colon': true,
+  '-bad': [0, '-'],
+  '.bad': [0, '.'],
+  // general entity
+  'u_score': true,
+  'd-ash': true,
+  'd.ot': true,
+  'all:_#-.': true
+}
+
+var xmlStart = '<a test="&" '
+var xmlEnd = '/>'
+
+iExpect.push([
+  'opentagstart',
+  {
+    name: 'a',
+    attributes: {}
+  }
+])
+
+iExpect.push([
+  'attribute',
+  {
+    name: 'test',
+    value: '&'
+  }
+])
+myAttributes['test'] = '&'
+
+var entI = 0
+
+for (var entity in entitiesToTest) {
+  var attribName = 'test' + entI
+  var attribValue = 'Testing ' + entity
+
+  // add the first part to use in calculation below
+  xmlStart += attribName + '="' + '&'
+
+  if (typeof entitiesToTest[entity] === 'object') {
+    iExpect.push([
+      'error',
+      'Invalid character in entity name\nLine: 0\nColumn: ' +
+      (xmlStart.length + entitiesToTest[entity][0] + 1) +
+      '\nChar: ' + entitiesToTest[entity][1]
+    ])
+    iExpect.push([
+      'attribute',
+      { name: attribName, value: '&' + entity + ';' }
+    ])
+    myAttributes[attribName] = '&' + entity + ';'
+  } else {
+    ENTITIES[entity] = attribValue
+    iExpect.push(['attribute', { name: attribName, value: attribValue }])
+    myAttributes[attribName] = attribValue
+  }
+
+  xmlStart += entity + ';" '
+  entI++
+}
+
+iExpect.push([
+  'opentag',
+  {
+    name: 'a',
+    attributes: myAttributes,
+    isSelfClosing: true
+  }
+])
+iExpect.push([ 'closetag', 'a' ])
+
+var parser = require(__dirname).test({
+  strict: true,
+  expect: iExpect
+})
+
+for (entity in entitiesToTest) {
+  parser.ENTITIES[entity] = ENTITIES[entity]
+}
+
+parser.write(xmlStart + xmlEnd).close()
diff --git a/test/xml_entities.js b/test/xml_entities.js
new file mode 100644
index 0000000..3d739d0
--- /dev/null
+++ b/test/xml_entities.js
@@ -0,0 +1,12 @@
+require(__dirname).test({
+  opt: { strictEntities: true },
+  xml: '<r>⌋ ' +
+    '♠ © → & ' +
+    '< < <  <   < > ℜ ℘ €</r>',
+  expect: [
+    ['opentagstart', {'name': 'R', attributes: {}}],
+    ['opentag', {'name': 'R', attributes: {}, isSelfClosing: false}],
+    ['text', '⌋ ♠ © → & < < <  <   < > ℜ ℘ €'],
+    ['closetag', 'R']
+  ]
+})
diff --git a/test/xmlns-as-tag-name.js b/test/xmlns-as-tag-name.js
new file mode 100644
index 0000000..18cd44d
--- /dev/null
+++ b/test/xmlns-as-tag-name.js
@@ -0,0 +1,33 @@
+require(__dirname).test({
+  xml: '<xmlns/>',
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'xmlns',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'xmlns',
+        uri: '',
+        prefix: '',
+        local: 'xmlns',
+        attributes: {},
+        ns: {},
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'xmlns'
+    ]
+  ],
+  strict: true,
+  opt: {
+    xmlns: true
+  }
+})
diff --git a/test/xmlns-issue-41.js b/test/xmlns-issue-41.js
index 17ab45a..435b7e6 100644
--- a/test/xmlns-issue-41.js
+++ b/test/xmlns-issue-41.js
@@ -1,68 +1,93 @@
 var t = require(__dirname)
 
-  , xmls = // should be the same both ways.
-    [ "<parent xmlns:a='http://ATTRIBUTE' a:attr='value' />"
-    , "<parent a:attr='value' xmlns:a='http://ATTRIBUTE' />" ]
+// should be the same both ways.
+var xmls = [
+  '<parent xmlns:a="http://ATTRIBUTE" a:attr="value" />',
+  '<parent a:attr="value" xmlns:a="http://ATTRIBUTE" />'
+]
 
-  , ex1 =
-    [ [ "opennamespace"
-      , { prefix: "a"
-        , uri: "http://ATTRIBUTE"
+var ex1 = [
+  [ 'opentagstart', { name: 'parent', attributes: {}, ns: {} } ],
+  [
+    'opennamespace',
+    {
+      prefix: 'a',
+      uri: 'http://ATTRIBUTE'
+    }
+  ],
+  [
+    'attribute',
+    {
+      name: 'xmlns:a',
+      value: 'http://ATTRIBUTE',
+      prefix: 'xmlns',
+      local: 'a',
+      uri: 'http://www.w3.org/2000/xmlns/'
+    }
+  ],
+  [
+    'attribute',
+    {
+      name: 'a:attr',
+      local: 'attr',
+      prefix: 'a',
+      uri: 'http://ATTRIBUTE',
+      value: 'value'
+    }
+  ],
+  [
+    'opentag',
+    {
+      name: 'parent',
+      uri: '',
+      prefix: '',
+      local: 'parent',
+      attributes: {
+        'a:attr': {
+          name: 'a:attr',
+          local: 'attr',
+          prefix: 'a',
+          uri: 'http://ATTRIBUTE',
+          value: 'value'
+        },
+        'xmlns:a': {
+          name: 'xmlns:a',
+          local: 'a',
+          prefix: 'xmlns',
+          uri: 'http://www.w3.org/2000/xmlns/',
+          value: 'http://ATTRIBUTE'
         }
-      ]
-    , [ "attribute"
-      , { name: "xmlns:a"
-        , value: "http://ATTRIBUTE"
-        , prefix: "xmlns"
-        , local: "a"
-        , uri: "http://www.w3.org/2000/xmlns/"
-        }
-      ]
-    , [ "attribute"
-      , { name: "a:attr"
-        , local: "attr"
-        , prefix: "a"
-        , uri: "http://ATTRIBUTE"
-        , value: "value"
-        }
-      ]
-    , [ "opentag"
-      , { name: "parent"
-        , uri: ""
-        , prefix: ""
-        , local: "parent"
-        , attributes:
-          { "a:attr":
-            { name: "a:attr"
-            , local: "attr"
-            , prefix: "a"
-            , uri: "http://ATTRIBUTE"
-            , value: "value"
-            }
-          , "xmlns:a":
-            { name: "xmlns:a"
-            , local: "a"
-            , prefix: "xmlns"
-            , uri: "http://www.w3.org/2000/xmlns/"
-            , value: "http://ATTRIBUTE"
-            }
-          }
-        , ns: {"a": "http://ATTRIBUTE"}
-        , isSelfClosing: true
-        }
-      ]
-    , ["closetag", "parent"]
-    , ["closenamespace", { prefix: "a", uri: "http://ATTRIBUTE" }]
-    ]
+      },
+      ns: {
+        a: 'http://ATTRIBUTE'
+      },
+      isSelfClosing: true
+    }
+  ],
+  [
+    'closetag',
+    'parent'
+  ],
+  [
+    'closenamespace',
+    {
+      prefix: 'a',
+      uri: 'http://ATTRIBUTE'
+    }
+  ]
+]
 
-  // swap the order of elements 2 and 1
-  , ex2 = [ex1[0], ex1[2], ex1[1]].concat(ex1.slice(3))
-  , expected = [ex1, ex2]
+// swap the order of elements 2 and 3
+var ex2 = [ex1[0], ex1[1], ex1[3], ex1[2]].concat(ex1.slice(4))
+var expected = [ex1, ex2]
 
 xmls.forEach(function (x, i) {
-  t.test({ xml: x
-         , expect: expected[i]
-         , strict: true
-         , opt: { xmlns: true }
-         })
+  t.test({
+    xml: x,
+    expect: expected[i],
+    strict: true,
+    opt: {
+      xmlns: true
+    }
+  })
 })
diff --git a/test/xmlns-rebinding.js b/test/xmlns-rebinding.js
index 07e0425..8086b44 100644
--- a/test/xmlns-rebinding.js
+++ b/test/xmlns-rebinding.js
@@ -1,63 +1,327 @@
-
-require(__dirname).test
-  ( { xml :
-      "<root xmlns:x='x1' xmlns:y='y1' x:a='x1' y:a='y1'>"+
-        "<rebind xmlns:x='x2'>"+
-          "<check x:a='x2' y:a='y1'/>"+
-        "</rebind>"+
-        "<check x:a='x1' y:a='y1'/>"+
-      "</root>"
-
-    , expect :
-      [ [ "opennamespace", { prefix: "x", uri: "x1" } ]
-      , [ "opennamespace", { prefix: "y", uri: "y1" } ]
-      , [ "attribute", { name: "xmlns:x", value: "x1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } ]
-      , [ "attribute", { name: "xmlns:y", value: "y1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "y" } ]
-      , [ "attribute", { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" } ]
-      , [ "attribute", { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } ]
-      , [ "opentag", { name: "root", uri: "", prefix: "", local: "root",
-            attributes: { "xmlns:x": { name: "xmlns:x", value: "x1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" }
-                        , "xmlns:y": { name: "xmlns:y", value: "y1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "y" }
-                        , "x:a": { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" }
-                        , "y:a": { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } },
-            ns: { x: 'x1', y: 'y1' },
-            isSelfClosing: false } ]
-
-      , [ "opennamespace", { prefix: "x", uri: "x2" } ]
-      , [ "attribute", { name: "xmlns:x", value: "x2", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } ]
-      , [ "opentag", { name: "rebind", uri: "", prefix: "", local: "rebind",
-            attributes: { "xmlns:x": { name: "xmlns:x", value: "x2", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } },
-            ns: { x: 'x2' },
-            isSelfClosing: false } ]
-
-      , [ "attribute", { name: "x:a", value: "x2", uri: "x2", prefix: "x", local: "a" } ]
-      , [ "attribute", { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } ]
-      , [ "opentag", { name: "check", uri: "", prefix: "", local: "check",
-            attributes: { "x:a": { name: "x:a", value: "x2", uri: "x2", prefix: "x", local: "a" }
-                        , "y:a": { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } },
-            ns: { x: 'x2' },
-            isSelfClosing: true } ]
-
-      , [ "closetag", "check" ]
-
-      , [ "closetag", "rebind" ]
-      , [ "closenamespace", { prefix: "x", uri: "x2" } ]
-
-      , [ "attribute", { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" } ]
-      , [ "attribute", { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } ]
-      , [ "opentag", { name: "check", uri: "", prefix: "", local: "check",
-            attributes: { "x:a": { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" }
-                        , "y:a": { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } },
-            ns: { x: 'x1', y: 'y1' },
-            isSelfClosing: true } ]
-      , [ "closetag", "check" ]
-
-      , [ "closetag", "root" ]
-      , [ "closenamespace", { prefix: "x", uri: "x1" } ]
-      , [ "closenamespace", { prefix: "y", uri: "y1" } ]
-      ]
-    , strict : true
-    , opt : { xmlns: true }
-    }
-  )
-
+require(__dirname).test({
+  xml: '<root xmlns:x="x1" xmlns:y="y1" x:a="x1" y:a="y1">' +
+    '<rebind xmlns:x="x2">' +
+    '<check x:a="x2" y:a="y1"/>' +
+    '</rebind>' +
+    '<check x:a="x1" y:a="y1"/>' +
+    '</root>',
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'root',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'opennamespace',
+      {
+        prefix: 'x',
+        uri: 'x1'
+      }
+    ],
+    [
+      'opennamespace',
+      {
+        prefix: 'y',
+        uri: 'y1'
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'xmlns:x',
+        value: 'x1',
+        uri: 'http://www.w3.org/2000/xmlns/',
+        prefix: 'xmlns',
+        local: 'x'
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'xmlns:y',
+        value: 'y1',
+        uri: 'http://www.w3.org/2000/xmlns/',
+        prefix: 'xmlns',
+        local: 'y'
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'x:a',
+        value: 'x1',
+        uri: 'x1',
+        prefix: 'x',
+        local: 'a'
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'y:a',
+        value: 'y1',
+        uri: 'y1',
+        prefix: 'y',
+        local: 'a'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'root',
+        uri: '',
+        prefix: '',
+        local: 'root',
+        attributes: {
+          'xmlns:x': {
+            name: 'xmlns:x',
+            value: 'x1',
+            uri: 'http://www.w3.org/2000/xmlns/',
+            prefix: 'xmlns',
+            local: 'x'
+          },
+          'xmlns:y': {
+            name: 'xmlns:y',
+            value: 'y1',
+            uri: 'http://www.w3.org/2000/xmlns/',
+            prefix: 'xmlns',
+            local: 'y'
+          },
+          'x:a': {
+            name: 'x:a',
+            value: 'x1',
+            uri: 'x1',
+            prefix: 'x',
+            local: 'a'
+          },
+          'y:a': {
+            name: 'y:a',
+            value: 'y1',
+            uri: 'y1',
+            prefix: 'y',
+            local: 'a'
+          }
+        },
+        ns: {
+          x: 'x1',
+          y: 'y1'
+        },
+        isSelfClosing: false
+      }
+    ],
+    [
+      'opentagstart',
+      {
+        name: 'rebind',
+        attributes: {},
+        ns: {
+          x: 'x1',
+          y: 'y1'
+        }
+      }
+    ],
+    [
+      'opennamespace',
+      {
+        prefix: 'x',
+        uri: 'x2'
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'xmlns:x',
+        value: 'x2',
+        uri: 'http://www.w3.org/2000/xmlns/',
+        prefix: 'xmlns',
+        local: 'x'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'rebind',
+        uri: '',
+        prefix: '',
+        local: 'rebind',
+        attributes: {
+          'xmlns:x': {
+            name: 'xmlns:x',
+            value: 'x2',
+            uri: 'http://www.w3.org/2000/xmlns/',
+            prefix: 'xmlns',
+            local: 'x'
+          }
+        },
+        ns: {
+          x: 'x2'
+        },
+        isSelfClosing: false
+      }
+    ],
+    [
+      'opentagstart',
+      {
+        name: 'check',
+        attributes: {},
+        ns: {
+          x: 'x2'
+        }
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'x:a',
+        value: 'x2',
+        uri: 'x2',
+        prefix: 'x',
+        local: 'a'
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'y:a',
+        value: 'y1',
+        uri: 'y1',
+        prefix: 'y',
+        local: 'a'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'check',
+        uri: '',
+        prefix: '',
+        local: 'check',
+        attributes: {
+          'x:a': {
+            name: 'x:a',
+            value: 'x2',
+            uri: 'x2',
+            prefix: 'x',
+            local: 'a'
+          },
+          'y:a': {
+            name: 'y:a',
+            value: 'y1',
+            uri: 'y1',
+            prefix: 'y',
+            local: 'a'
+          }
+        },
+        ns: {
+          x: 'x2'
+        },
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'check'
+    ],
+    [
+      'closetag',
+      'rebind'
+    ],
+    [
+      'closenamespace',
+      {
+        prefix: 'x',
+        uri: 'x2'
+      }
+    ],
+    [
+      'opentagstart',
+      {
+        name: 'check',
+        attributes: {},
+        ns: {
+          x: 'x1',
+          y: 'y1'
+        }
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'x:a',
+        value: 'x1',
+        uri: 'x1',
+        prefix: 'x',
+        local: 'a'
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'y:a',
+        value: 'y1',
+        uri: 'y1',
+        prefix: 'y',
+        local: 'a'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'check',
+        uri: '',
+        prefix: '',
+        local: 'check',
+        attributes: {
+          'x:a': {
+            name: 'x:a',
+            value: 'x1',
+            uri: 'x1',
+            prefix: 'x',
+            local: 'a'
+          },
+          'y:a': {
+            name: 'y:a',
+            value: 'y1',
+            uri: 'y1',
+            prefix: 'y',
+            local: 'a'
+          }
+        },
+        ns: {
+          x: 'x1',
+          y: 'y1'
+        },
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'check'
+    ],
+    [
+      'closetag',
+      'root'
+    ],
+    [
+      'closenamespace',
+      {
+        prefix: 'x',
+        uri: 'x1'
+      }
+    ],
+    [
+      'closenamespace',
+      {
+        prefix: 'y',
+        uri: 'y1'
+      }
+    ]
+  ],
+  strict: true,
+  opt: {
+    xmlns: true
+  }
+})
diff --git a/test/xmlns-strict.js b/test/xmlns-strict.js
index b5e3e51..87d26c4 100644
--- a/test/xmlns-strict.js
+++ b/test/xmlns-strict.js
@@ -1,74 +1,334 @@
-
-require(__dirname).test
-  ( { xml :
-      "<root>"+
-        "<plain attr='normal'/>"+
-        "<ns1 xmlns='uri:default'>"+
-          "<plain attr='normal'/>"+
-        "</ns1>"+
-        "<ns2 xmlns:a='uri:nsa'>"+
-          "<plain attr='normal'/>"+
-          "<a:ns a:attr='namespaced'/>"+
-        "</ns2>"+
-      "</root>"
-
-    , expect :
-      [ [ "opentag", { name: "root", prefix: "", local: "root", uri: "",
-            attributes: {}, ns: {}, isSelfClosing: false } ]
-
-      , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } ]
-      , [ "opentag", { name: "plain", prefix: "", local: "plain", uri: "",
-            attributes: { "attr": { name: "attr", value: "normal", uri: "", prefix: "", local: "attr", uri: "" } },
-            ns: {}, isSelfClosing: true } ]
-      , [ "closetag", "plain" ]
-
-      , [ "opennamespace", { prefix: "", uri: "uri:default" } ]
-
-      , [ "attribute", { name: "xmlns", value: "uri:default", prefix: "xmlns", local: "", uri: "http://www.w3.org/2000/xmlns/" } ]
-      , [ "opentag", { name: "ns1", prefix: "", local: "ns1", uri: "uri:default",
-            attributes: { "xmlns": { name: "xmlns", value: "uri:default", prefix: "xmlns", local: "", uri: "http://www.w3.org/2000/xmlns/" } },
-            ns: { "": "uri:default" }, isSelfClosing: false } ]
-
-      , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } ]
-      , [ "opentag", { name: "plain", prefix: "", local: "plain", uri: "uri:default", ns: { '': 'uri:default' },
-            attributes: { "attr": { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } },
-            isSelfClosing: true } ]
-      , [ "closetag", "plain" ]
-
-      , [ "closetag", "ns1" ]
-
-      , [ "closenamespace", { prefix: "", uri: "uri:default" } ]
-
-      , [ "opennamespace", { prefix: "a", uri: "uri:nsa" } ]
-
-      , [ "attribute", { name: "xmlns:a", value: "uri:nsa", prefix: "xmlns", local: "a", uri: "http://www.w3.org/2000/xmlns/" } ]
-
-      , [ "opentag", { name: "ns2", prefix: "", local: "ns2", uri: "",
-            attributes: { "xmlns:a": { name: "xmlns:a", value: "uri:nsa", prefix: "xmlns", local: "a", uri: "http://www.w3.org/2000/xmlns/" } },
-            ns: { a: "uri:nsa" }, isSelfClosing: false } ]
-
-      , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } ]
-      , [ "opentag", { name: "plain", prefix: "", local: "plain", uri: "",
-            attributes: { "attr": { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } },
-            ns: { a: 'uri:nsa' },
-            isSelfClosing: true } ]
-      , [ "closetag", "plain" ]
-
-      , [ "attribute", { name: "a:attr", value: "namespaced", prefix: "a", local: "attr", uri: "uri:nsa" } ]
-      , [ "opentag", { name: "a:ns", prefix: "a", local: "ns", uri: "uri:nsa",
-            attributes: { "a:attr": { name: "a:attr", value: "namespaced", prefix: "a", local: "attr", uri: "uri:nsa" } },
-            ns: { a: 'uri:nsa' },
-            isSelfClosing: true } ]
-      , [ "closetag", "a:ns" ]
-
-      , [ "closetag", "ns2" ]
-
-      , [ "closenamespace", { prefix: "a", uri: "uri:nsa" } ]
-
-      , [ "closetag", "root" ]
-      ]
-    , strict : true
-    , opt : { xmlns: true }
-    }
-  )
-
+require(__dirname).test({
+  xml: '<root>' +
+    '<plain attr="normal" />' +
+    '<ns1 xmlns="uri:default">' +
+    '<plain attr="normal"/>' +
+    '</ns1>' +
+    '<ns2 xmlns:a="uri:nsa">' +
+    '<plain attr="normal"/>' +
+    '<a:ns a:attr="namespaced"/>' +
+    '</ns2>' +
+    '</root>',
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'root',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'root',
+        prefix: '',
+        local: 'root',
+        uri: '',
+        attributes: {},
+        ns: {},
+        isSelfClosing: false
+      }
+    ],
+    [
+      'opentagstart',
+      {
+        name: 'plain',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'attr',
+        value: 'normal',
+        prefix: '',
+        local: 'attr',
+        uri: ''
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'plain',
+        prefix: '',
+        local: 'plain',
+        uri: '',
+        attributes: {
+          'attr': {
+            name: 'attr',
+            value: 'normal',
+            prefix: '',
+            local: 'attr',
+            uri: ''
+          }
+        },
+        ns: {},
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'plain'
+    ],
+    [
+      'opentagstart',
+      {
+        name: 'ns1',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'opennamespace',
+      {
+        prefix: '',
+        uri: 'uri:default'
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'xmlns',
+        value: 'uri:default',
+        prefix: 'xmlns',
+        local: '',
+        uri: 'http://www.w3.org/2000/xmlns/'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'ns1',
+        prefix: '',
+        local: 'ns1',
+        uri: 'uri:default',
+        attributes: {
+          'xmlns': {
+            name: 'xmlns',
+            value: 'uri:default',
+            prefix: 'xmlns',
+            local: '',
+            uri: 'http://www.w3.org/2000/xmlns/'
+          }
+        },
+        ns: {
+          '': 'uri:default'
+        },
+        isSelfClosing: false
+      }
+    ],
+    [
+      'opentagstart',
+      {
+        name: 'plain',
+        ns: {
+          '': 'uri:default'
+        },
+        attributes: {}
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'attr',
+        value: 'normal',
+        prefix: '',
+        local: 'attr',
+        uri: ''
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'plain',
+        prefix: '',
+        local: 'plain',
+        uri: 'uri:default',
+        ns: {
+          '': 'uri:default'
+        },
+        attributes: {
+          'attr': {
+            name: 'attr',
+            value: 'normal',
+            prefix: '',
+            local: 'attr',
+            uri: ''
+          }
+        },
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'plain'
+    ],
+    [
+      'closetag',
+      'ns1'
+    ],
+    [
+      'closenamespace',
+      {
+        prefix: '',
+        uri: 'uri:default'
+      }
+    ],
+    [
+      'opentagstart',
+      {
+        name: 'ns2',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'opennamespace',
+      {
+        prefix: 'a',
+        uri: 'uri:nsa'
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'xmlns:a',
+        value: 'uri:nsa',
+        prefix: 'xmlns',
+        local: 'a',
+        uri: 'http://www.w3.org/2000/xmlns/'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'ns2',
+        prefix: '',
+        local: 'ns2',
+        uri: '',
+        attributes: {
+          'xmlns:a': {
+            name: 'xmlns:a',
+            value: 'uri:nsa',
+            prefix: 'xmlns',
+            local: 'a',
+            uri: 'http://www.w3.org/2000/xmlns/'
+          }
+        },
+        ns: {
+          a: 'uri:nsa'
+        },
+        isSelfClosing: false
+      }
+    ],
+    [
+      'opentagstart',
+      {
+        name: 'plain',
+        attributes: {},
+        ns: {
+          a: 'uri:nsa'
+        }
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'attr',
+        value: 'normal',
+        prefix: '',
+        local: 'attr',
+        uri: ''
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'plain',
+        prefix: '',
+        local: 'plain',
+        uri: '',
+        attributes: {
+          'attr': {
+            name: 'attr',
+            value: 'normal',
+            prefix: '',
+            local: 'attr',
+            uri: ''
+          }
+        },
+        ns: {
+          a: 'uri:nsa'
+        },
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'plain'
+    ],
+    [
+      'opentagstart',
+      {
+        name: 'a:ns',
+        attributes: {},
+        ns: { a: 'uri:nsa' }
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'a:attr',
+        value: 'namespaced',
+        prefix: 'a',
+        local: 'attr',
+        uri: 'uri:nsa'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'a:ns',
+        prefix: 'a',
+        local: 'ns',
+        uri: 'uri:nsa',
+        attributes: {
+          'a:attr': {
+            name: 'a:attr',
+            value: 'namespaced',
+            prefix: 'a',
+            local: 'attr',
+            uri: 'uri:nsa'
+          }
+        },
+        ns: { a: 'uri:nsa' },
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'a:ns'
+    ],
+    [
+      'closetag',
+      'ns2'
+    ],
+    [
+      'closenamespace',
+      {
+        prefix: 'a',
+        uri: 'uri:nsa'
+      }
+    ],
+    [
+      'closetag',
+      'root'
+    ]
+  ],
+  strict: true,
+  opt: {
+    xmlns: true
+  }
+})
diff --git a/test/xmlns-unbound-element.js b/test/xmlns-unbound-element.js
index 9d031a2..60759b1 100644
--- a/test/xmlns-unbound-element.js
+++ b/test/xmlns-unbound-element.js
@@ -1,33 +1,101 @@
-require(__dirname).test(
-  { strict : true
-  , opt : { xmlns: true }
-  , expect :
-    [ [ "error", "Unbound namespace prefix: \"unbound:root\"\nLine: 0\nColumn: 15\nChar: >"]
-    , [ "opentag", { name: "unbound:root", uri: "unbound", prefix: "unbound", local: "root"
-        , attributes: {}, ns: {}, isSelfClosing: true } ]
-    , [ "closetag", "unbound:root" ]
+require(__dirname).test({
+  strict: true,
+  opt: { xmlns: true },
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'unbound:root',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'error',
+      'Unbound namespace prefix: "unbound:root"\nLine: 0\nColumn: 15\nChar: >'
+    ],
+    [
+      'opentag',
+      {
+        name: 'unbound:root',
+        uri: 'unbound',
+        prefix: 'unbound',
+        local: 'root',
+        attributes: {},
+        ns: {},
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'unbound:root'
     ]
-  }
-).write("<unbound:root/>");
+  ]
+}).write('<unbound:root/>')
 
-require(__dirname).test(
-  { strict : true
-  , opt : { xmlns: true }
-  , expect :
-    [ [ "opennamespace", { prefix: "unbound", uri: "someuri" } ]
-    , [ "attribute", { name: 'xmlns:unbound', value: 'someuri'
-      , prefix: 'xmlns', local: 'unbound'
-      , uri: 'http://www.w3.org/2000/xmlns/' } ]
-    , [ "opentag", { name: "unbound:root", uri: "someuri", prefix: "unbound", local: "root"
-          , attributes: { 'xmlns:unbound': {
-              name: 'xmlns:unbound'
-            , value: 'someuri'
-            , prefix: 'xmlns'
-            , local: 'unbound'
-            , uri: 'http://www.w3.org/2000/xmlns/' } }
-      , ns: { "unbound": "someuri" }, isSelfClosing: true } ]
-    , [ "closetag", "unbound:root" ]
-    , [ "closenamespace", { prefix: 'unbound', uri: 'someuri' }]
+require(__dirname).test({
+  strict: true,
+  opt: {
+    xmlns: true
+  },
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'unbound:root',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'opennamespace',
+      {
+        prefix: 'unbound',
+        uri: 'someuri'
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'xmlns:unbound',
+        value: 'someuri',
+        prefix: 'xmlns',
+        local: 'unbound',
+        uri: 'http://www.w3.org/2000/xmlns/'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'unbound:root',
+        uri: 'someuri',
+        prefix: 'unbound',
+        local: 'root',
+        attributes: {
+          'xmlns:unbound': {
+            name: 'xmlns:unbound',
+            value: 'someuri',
+            prefix: 'xmlns',
+            local: 'unbound',
+            uri: 'http://www.w3.org/2000/xmlns/'
+          }
+        },
+        ns: {
+          'unbound': 'someuri'
+        },
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'unbound:root'
+    ],
+    [
+      'closenamespace',
+      {
+        prefix: 'unbound',
+        uri: 'someuri'
+      }
     ]
-  }
-).write("<unbound:root xmlns:unbound=\"someuri\"/>");
+  ]
+}).write('<unbound:root xmlns:unbound="someuri"/>')
diff --git a/test/xmlns-unbound.js b/test/xmlns-unbound.js
index b740e26..319d350 100644
--- a/test/xmlns-unbound.js
+++ b/test/xmlns-unbound.js
@@ -1,15 +1,52 @@
-
-require(__dirname).test(
-  { strict : true
-  , opt : { xmlns: true }
-  , expect :
-    [ ["error", "Unbound namespace prefix: \"unbound\"\nLine: 0\nColumn: 28\nChar: >"]
-
-    , [ "attribute", { name: "unbound:attr", value: "value", uri: "unbound", prefix: "unbound", local: "attr" } ]
-    , [ "opentag", { name: "root", uri: "", prefix: "", local: "root",
-          attributes: { "unbound:attr": { name: "unbound:attr", value: "value", uri: "unbound", prefix: "unbound", local: "attr" } },
-          ns: {}, isSelfClosing: true } ]
-    , [ "closetag", "root" ]
+require(__dirname).test({
+  strict: true,
+  opt: { xmlns: true },
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'root',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'error',
+      'Unbound namespace prefix: "unbound"\nLine: 0\nColumn: 28\nChar: >'
+    ],
+    [
+      'attribute',
+      {
+        name: 'unbound:attr',
+        value: 'value',
+        uri: 'unbound',
+        prefix: 'unbound',
+        local: 'attr'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'root',
+        uri: '',
+        prefix: '',
+        local: 'root',
+        attributes: {
+          'unbound:attr': {
+            name: 'unbound:attr',
+            value: 'value',
+            uri: 'unbound',
+            prefix: 'unbound',
+            local: 'attr'
+          }
+        },
+        ns: {},
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'root'
     ]
-  }
-).write("<root unbound:attr='value'/>")
+  ]
+}).write("<root unbound:attr='value'/>")
diff --git a/test/xmlns-xml-default-ns.js b/test/xmlns-xml-default-ns.js
index b1984d2..41d5572 100644
--- a/test/xmlns-xml-default-ns.js
+++ b/test/xmlns-xml-default-ns.js
@@ -1,31 +1,71 @@
-var xmlns_attr =
-{
-    name: "xmlns", value: "http://foo", prefix: "xmlns",
-    local: "", uri : "http://www.w3.org/2000/xmlns/"
-};
+var xmlnsAttr = {
+  name: 'xmlns',
+  value: 'http://foo',
+  prefix: 'xmlns',
+  local: '',
+  uri: 'http://www.w3.org/2000/xmlns/'
+}
 
-var attr_attr =
-{
-    name: "attr", value: "bar", prefix: "",
-    local : "attr",  uri : ""
-};
+var attrAttr = {
+  name: 'attr',
+  value: 'bar',
+  prefix: '',
+  local: 'attr',
+  uri: ''
+}
 
-
-require(__dirname).test
-  ( { xml :
-      "<elm xmlns='http://foo' attr='bar'/>"
-    , expect :
-      [ [ "opennamespace", { prefix: "", uri: "http://foo" } ]
-      , [ "attribute", xmlns_attr ]
-      , [ "attribute", attr_attr ]
-      , [ "opentag", { name: "elm", prefix: "", local: "elm", uri : "http://foo",
-                       ns : { "" : "http://foo" },
-                       attributes: { xmlns: xmlns_attr, attr: attr_attr },
-                       isSelfClosing: true } ]
-      , [ "closetag", "elm" ]
-      , [ "closenamespace", { prefix: "", uri: "http://foo"} ]
-      ]
-    , strict : true
-    , opt : {xmlns: true}
-    }
-  )
+require(__dirname).test({
+  xml: "<elm xmlns='http://foo' attr='bar'/>",
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'elm',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'opennamespace',
+      { prefix: '', uri: 'http://foo' }
+    ],
+    [
+      'attribute',
+      xmlnsAttr
+    ],
+    [
+      'attribute',
+      attrAttr
+    ],
+    [
+      'opentag',
+      {
+        name: 'elm',
+        prefix: '',
+        local: 'elm',
+        uri: 'http://foo',
+        ns: { '': 'http://foo' },
+        attributes: {
+          xmlns: xmlnsAttr,
+          attr: attrAttr
+        },
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'elm'
+    ],
+    [
+      'closenamespace',
+      {
+        prefix: '',
+        uri: 'http://foo'
+      }
+    ]
+  ],
+  strict: true,
+  opt: {
+    xmlns: true
+  }
+})
diff --git a/test/xmlns-xml-default-prefix-attribute.js b/test/xmlns-xml-default-prefix-attribute.js
index e41f218..51cfbb6 100644
--- a/test/xmlns-xml-default-prefix-attribute.js
+++ b/test/xmlns-xml-default-prefix-attribute.js
@@ -1,36 +1,49 @@
-require(__dirname).test(
-  { xml : "<root xml:lang='en'/>"
-  , expect :
-    [ [ "attribute"
-      , { name: "xml:lang"
-        , local: "lang"
-        , prefix: "xml"
-        , uri: "http://www.w3.org/XML/1998/namespace"
-        , value: "en"
-        }
-      ]
-    , [ "opentag"
-      , { name: "root"
-        , uri: ""
-        , prefix: ""
-        , local: "root"
-        , attributes:
-          { "xml:lang":
-            { name: "xml:lang"
-            , local: "lang"
-            , prefix: "xml"
-            , uri: "http://www.w3.org/XML/1998/namespace"
-            , value: "en"
-            }
+require(__dirname).test({
+  xml: "<root xml:lang='en'/>",
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'root',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'attribute',
+      {
+        name: 'xml:lang',
+        local: 'lang',
+        prefix: 'xml',
+        uri: 'http://www.w3.org/XML/1998/namespace',
+        value: 'en'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'root',
+        uri: '',
+        prefix: '',
+        local: 'root',
+        attributes: {
+          'xml:lang': {
+            name: 'xml:lang',
+            local: 'lang',
+            prefix: 'xml',
+            uri: 'http://www.w3.org/XML/1998/namespace',
+            value: 'en'
           }
-        , ns: {}
-        , isSelfClosing: true
-        }
-      ]
-    , ["closetag", "root"]
+        },
+        ns: {},
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'root'
     ]
-  , strict : true
-  , opt : { xmlns: true }
-  }
-)
-
+  ],
+  strict: true,
+  opt: { xmlns: true }
+})
diff --git a/test/xmlns-xml-default-prefix.js b/test/xmlns-xml-default-prefix.js
index a85b478..fd48cbd 100644
--- a/test/xmlns-xml-default-prefix.js
+++ b/test/xmlns-xml-default-prefix.js
@@ -1,21 +1,31 @@
-require(__dirname).test(
-  { xml : "<xml:root/>"
-  , expect :
+require(__dirname).test({
+  xml: '<xml:root/>',
+  expect: [
     [
-      [ "opentag"
-      , { name: "xml:root"
-        , uri: "http://www.w3.org/XML/1998/namespace"
-        , prefix: "xml"
-        , local: "root"
-        , attributes: {}
-        , ns: {}
-        , isSelfClosing: true
-        }
-      ]
-    , ["closetag", "xml:root"]
+      'opentagstart',
+      {
+        name: 'xml:root',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'xml:root',
+        uri: 'http://www.w3.org/XML/1998/namespace',
+        prefix: 'xml',
+        local: 'root',
+        attributes: {},
+        ns: {},
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'xml:root'
     ]
-  , strict : true
-  , opt : { xmlns: true }
-  }
-)
-
+  ],
+  strict: true,
+  opt: { xmlns: true }
+})
diff --git a/test/xmlns-xml-default-redefine.js b/test/xmlns-xml-default-redefine.js
index d35d5a0..2a8f705 100644
--- a/test/xmlns-xml-default-redefine.js
+++ b/test/xmlns-xml-default-redefine.js
@@ -1,41 +1,55 @@
-require(__dirname).test(
-  { xml : "<xml:root xmlns:xml='ERROR'/>"
-  , expect :
-    [ ["error"
-      , "xml: prefix must be bound to http://www.w3.org/XML/1998/namespace\n"
-                        + "Actual: ERROR\n"
-      + "Line: 0\nColumn: 27\nChar: '"
-      ]
-    , [ "attribute"
-      , { name: "xmlns:xml"
-        , local: "xml"
-        , prefix: "xmlns"
-        , uri: "http://www.w3.org/2000/xmlns/"
-        , value: "ERROR"
-        }
-      ]
-    , [ "opentag"
-      , { name: "xml:root"
-        , uri: "http://www.w3.org/XML/1998/namespace"
-        , prefix: "xml"
-        , local: "root"
-        , attributes:
-          { "xmlns:xml":
-            { name: "xmlns:xml"
-            , local: "xml"
-            , prefix: "xmlns"
-            , uri: "http://www.w3.org/2000/xmlns/"
-            , value: "ERROR"
-            }
+require(__dirname).test({
+  xml: "<xml:root xmlns:xml='ERROR'/>",
+  expect: [
+    [
+      'opentagstart',
+      {
+        name: 'xml:root',
+        attributes: {},
+        ns: {}
+      }
+    ],
+    [
+      'error',
+      'xml: prefix must be bound to http://www.w3.org/XML/1998/namespace\n' +
+      'Actual: ERROR\n' +
+      "Line: 0\nColumn: 27\nChar: '"
+    ],
+    [
+      'attribute',
+      {
+        name: 'xmlns:xml',
+        local: 'xml',
+        prefix: 'xmlns',
+        uri: 'http://www.w3.org/2000/xmlns/',
+        value: 'ERROR'
+      }
+    ],
+    [
+      'opentag',
+      {
+        name: 'xml:root',
+        uri: 'http://www.w3.org/XML/1998/namespace',
+        prefix: 'xml',
+        local: 'root',
+        attributes: {
+          'xmlns:xml': {
+            name: 'xmlns:xml',
+            local: 'xml',
+            prefix: 'xmlns',
+            uri: 'http://www.w3.org/2000/xmlns/',
+            value: 'ERROR'
           }
-        , ns: {}
-        , isSelfClosing: true
-        }
-      ]
-    , ["closetag", "xml:root"]
+        },
+        ns: {},
+        isSelfClosing: true
+      }
+    ],
+    [
+      'closetag',
+      'xml:root'
     ]
-  , strict : true
-  , opt : { xmlns: true }
-  }
-)
-
+  ],
+  strict: true,
+  opt: { xmlns: true }
+})

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/sax.js.git



More information about the Pkg-javascript-commits mailing list