Merge pull request #2311 from apache/master

Sync master to release branch for NB 12.1-beta3
diff --git a/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/ConfigBuilderProvider.java b/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/ConfigBuilderProvider.java
index d297c77..90efe45 100644
--- a/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/ConfigBuilderProvider.java
+++ b/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/ConfigBuilderProvider.java
@@ -72,7 +72,7 @@
     /** Library builder configuration since GlassFish 5.1. */
     private static final Config.Next CONFIG_V5_1
             = new Config.Next(GlassFishVersion.GF_5_1_0,
-            ConfigBuilderProvider.class.getResource("GlassFishV5_1.xml"));
+            ConfigBuilderProvider.class.getResource("GlassFishV5_1_0.xml"));
 
     /** Library builder configuration for GlassFish cloud. */
     private static final Config config
diff --git a/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/GlassFishV5_1.xml b/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/GlassFishV5_1.xml
deleted file mode 100644
index bce4c22..0000000
--- a/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/GlassFishV5_1.xml
+++ /dev/null
@@ -1,101 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you under the Apache License, Version 2.0 (the
-    "License"); you may not use this file except in compliance
-    with the License.  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing,
-    software distributed under the License is distributed on an
-    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    KIND, either express or implied.  See the License for the
-    specific language governing permissions and limitations
-    under the License.
-
--->
-<server>
-    <tools lib="lib">
-        <asadmin jar="client/appserver-cli.jar"/>
-    </tools>
-    <java version="1.8">
-        <platform version="1.7"/>
-        <platform version="1.8"/>
-    </java>
-    <javaee version="1.8">
-        <profile version="1.3" type="full"/>
-        <profile version="1.4" type="full"/>
-        <profile version="1.5" type="full"/>
-        <profile version="1.6" type="web"/>
-        <profile version="1.6" type="full" check="full"/>
-        <profile version="1.7" type="web"/>
-        <profile version="1.7" type="full" check="full"/>
-        <profile version="1.8" type="web"/>
-        <profile version="1.8" type="full" check="full"/>
-        <module type="war"/>
-        <module type="car" check="full"/>
-        <module type="ear" check="full"/>
-        <module type="ejb" check="full"/>
-        <module type="rar" check="full"/>
-        <check name="full">
-            <file path="appclient-server-core.jar"/>
-        </check>
-    </javaee>
-    <library id="Java EE">
-        <classpath>
-            <fileset dir="modules">
-                <include name="javax\..+\.jar"/>
-                <include name="bean-validator.jar"/>
-                <include name="cdi-api.jar"/>
-                <include name="jaxb-osgi.jar"/>
-                <include name="jaxr-api-osgi.jar"/>
-                <include name="jaxrpc-api-osgi.jar"/>
-                <include name="webservices-osgi.jar"/>
-                <include name="weld-osgi-bundle.jar"/>
-            </fileset>
-            <fileset dir="modules/endorsed">
-                <include name=".+\.jar"/>
-            </fileset>
-            <fileset dir="../mq/lib">
-                <include name="jaxm-api.jar"/>
-            </fileset>
-        </classpath>
-        <javadocs>
-            <lookup path="docs/javaee-doc-api.jar"/>
-        </javadocs>
-        <sources>
-        </sources>
-    </library>
-    <library id="Jersey 2">
-        <classpath>
-            <fileset dir="modules">
-                <include name="guava.+\.jar"/>
-                <include name="jackson.+\.jar"/>
-                <!-- include name="javax.ws.+\.jar"/ -->
-                <include name="jersey.+\.jar"/>
-                <include name="jettison.*\.jar"/>
-            </fileset>
-        </classpath>
-        <javadocs>
-            <link url="http://repo1.maven.org/maven2/org/glassfish/jersey/jersey-documentation/2.0-m05-2/jersey-documentation-2.0-m05-2-docbook.zip"/>
-        </javadocs>
-        <sources>
-        </sources>
-    </library>
-    <library id="JAX-RS">
-        <classpath>
-            <fileset dir="modules">
-                <include name="javax.ws.rs-api.jar"/>
-            </fileset>
-        </classpath>
-        <javadocs>
-        </javadocs>
-        <sources>
-        </sources>
-    </library>
-</server>
diff --git a/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/GlassFishV5_1_0.xml b/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/GlassFishV5_1_0.xml
index bafd707..ea62cd8 100644
--- a/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/GlassFishV5_1_0.xml
+++ b/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/GlassFishV5_1_0.xml
@@ -37,8 +37,8 @@
         <profile version="1.7" type="full" check="full"/>
         <profile version="1.8" type="web"/>
         <profile version="1.8" type="full" check="full"/>
-        <profile version="1.8.0" type="web"/>
-        <profile version="1.8.0" type="full" check="full"/>
+        <profile version="8.0.0" type="web"/>
+        <profile version="8.0.0" type="full" check="full"/>
         <module type="war"/>
         <module type="car" check="full"/>
         <module type="ear" check="full"/>
diff --git a/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/JavaEEProfile.java b/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/JavaEEProfile.java
index 7efcd2f..75efca9 100644
--- a/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/JavaEEProfile.java
+++ b/enterprise/glassfish.tooling/src/org/netbeans/modules/glassfish/tooling/server/config/JavaEEProfile.java
@@ -119,7 +119,7 @@
         v1_7("1.7"),
         /** JavaEE 1.8. */
         v1_8("1.8"),
-        /** JakartaEE 1.8.0. */
+        /** JakartaEE 8.0. */
         v8_0_0("8.0.0");
 
         /** JavaEE profile type name. */
diff --git a/ide/html.validation/external/binaries-list b/ide/html.validation/external/binaries-list
index 4ca9418..853738e 100644
--- a/ide/html.validation/external/binaries-list
+++ b/ide/html.validation/external/binaries-list
@@ -14,9 +14,11 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-0DCC973606CBD9737541AA5F3E76DED6E3F4D0D0 com.hp.hpl.jena:iri:0.5
+CC78B59E2539C78AF923C12939D8D1CDE44B5CC1 com.hp.hpl.jena:iri:0.8
 483A61B688B13C62BB201A683D98A6688B5373B6 jing-0unknown.jar
 F0A0D2E29ED910808C33135A3A5A51BBA6358F7B log4j:log4j:1.2.15
-3D5058C101AEC048A48C257F3236055BA2A0C154 validator-20200626-patched.jar
-85A67D883A879E7BF767758A8413B690DEF29735 saxon9B-9.1.0.2.jar
+2EF7FD1E7A714E04EF0881FB451CC4E85AD3D23F validator-20200626-patched.jar
 FACC6D84B0B0A650B1D44FED941E9ADD9F326862 isorelax-20041111.jar
+FF0A7D89CE99F8D9EACDDC9D5D0B154462CA9935 com.shapesecurity:salvation:2.7.2
+FCF9C70F53B9C0E7BC723F43558488BF58390B33 nu.validator:galimatias:0.1.3
+4568003757802ADD587776B1DC23133F6AD7701E nu.validator:langdetect:1.2
\ No newline at end of file
diff --git a/ide/html.validation/external/galimatias-0.1.3-license.txt b/ide/html.validation/external/galimatias-0.1.3-license.txt
new file mode 100644
index 0000000..5b961c1
--- /dev/null
+++ b/ide/html.validation/external/galimatias-0.1.3-license.txt
@@ -0,0 +1,25 @@
+Name: ISO-RELAX
+Description: Relax validation APIs
+Version: 0.1.3
+License: MIT-galimatias
+Origin: https://github.com/validator/galimatias
+
+Copyright (c) 2013-2014 Santiago M. Mola <santi@mola.io>
+
+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/ide/html.validation/external/iri-0.5-license.txt b/ide/html.validation/external/iri-0.8-license.txt
similarity index 99%
rename from ide/html.validation/external/iri-0.5-license.txt
rename to ide/html.validation/external/iri-0.8-license.txt
index c8c8ed8..79affeb 100644
--- a/ide/html.validation/external/iri-0.5-license.txt
+++ b/ide/html.validation/external/iri-0.8-license.txt
@@ -1,6 +1,6 @@
 Name: JENA-IRI
 Description: The Jena IRI Library is an implementation of RFC 3987 (IRI) and RFC 3986 (URI), and a partial implementation of other related standards.
-Version: 0.5
+Version: 0.8
 Origin: SourceForge
 License: BSD-iri
 URL: http://jena.sourceforge.net/iri/index.html
diff --git a/ide/html.validation/external/langdetect-1.2-license.txt b/ide/html.validation/external/langdetect-1.2-license.txt
new file mode 100644
index 0000000..34e11e7
--- /dev/null
+++ b/ide/html.validation/external/langdetect-1.2-license.txt
@@ -0,0 +1,209 @@
+Name: langdetect
+Description: Fork of the com.cybozu.labs.langdetect language-detection library
+Version: 1.2
+Origin: Apache Software Foundation
+License: Apache-2.0
+URL: https://github.com/validator/language-detection/
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/ide/html.validation/external/salvation-2.7.2-license.txt b/ide/html.validation/external/salvation-2.7.2-license.txt
new file mode 100644
index 0000000..ea1cc62
--- /dev/null
+++ b/ide/html.validation/external/salvation-2.7.2-license.txt
@@ -0,0 +1,209 @@
+Name: salvation
+Description: This is a general purpose library for working with Content Security Policy policies.
+Version: 2.7.2
+Origin: Apache Software Foundation
+License: Apache-2.0
+URL: https://github.com/shapesecurity/salvation
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/ide/html.validation/external/saxon9B-9.1.0.2-license.txt b/ide/html.validation/external/saxon9B-9.1.0.2-license.txt
deleted file mode 100644
index 9e3f661..0000000
--- a/ide/html.validation/external/saxon9B-9.1.0.2-license.txt
+++ /dev/null
@@ -1,367 +0,0 @@
-Name: Saxon
-Description: Complete and conformant implementation of the XSLT 2.0, XQuery 1.0, and XPath 2.0 Recommendations published on 23 January 2007 by W3C.
-Version: 9.1.0.2
-License: MPL-1.0
-Origin: SourceForge
-URL: http://saxon.sourceforge.net/
-
-                           MOZILLA PUBLIC LICENSE
-                                Version 1.0
-
-                              ----------------
-
-1. Definitions.
-
-     1.1. ``Contributor'' means each entity that creates or contributes to
-     the creation of Modifications.
-
-     1.2. ``Contributor Version'' means the combination of the Original
-     Code, prior Modifications used by a Contributor, and the Modifications
-     made by that particular Contributor.
-
-     1.3. ``Covered Code'' means the Original Code or Modifications or the
-     combination of the Original Code and Modifications, in each case
-     including portions thereof.
-
-     1.4. ``Electronic Distribution Mechanism'' means a mechanism generally
-     accepted in the software development community for the electronic
-     transfer of data.
-
-     1.5. ``Executable'' means Covered Code in any form other than Source
-     Code.
-
-     1.6. ``Initial Developer'' means the individual or entity identified as
-     the Initial Developer in the Source Code notice required by Exhibit A.
-
-     1.7. ``Larger Work'' means a work which combines Covered Code or
-     portions thereof with code not governed by the terms of this License.
-
-     1.8. ``License'' means this document.
-
-     1.9. ``Modifications'' means any addition to or deletion from the
-     substance or structure of either the Original Code or any previous
-     Modifications. When Covered Code is released as a series of files, a
-     Modification is:
-
-          A. Any addition to or deletion from the contents of a file
-          containing Original Code or previous Modifications.
-
-          B. Any new file that contains any part of the Original Code or
-          previous Modifications.
-
-     1.10. ``Original Code'' means Source Code of computer software code
-     which is described in the Source Code notice required by Exhibit A as
-     Original Code, and which, at the time of its release under this License
-     is not already Covered Code governed by this License.
-
-     1.11. ``Source Code'' means the preferred form of the Covered Code for
-     making modifications to it, including all modules it contains, plus any
-     associated interface definition files, scripts used to control
-     compilation and installation of an Executable, or a list of source code
-     differential comparisons against either the Original Code or another
-     well known, available Covered Code of the Contributor's choice. The
-     Source Code can be in a compressed or archival form, provided the
-     appropriate decompression or de-archiving software is widely available
-     for no charge.
-
-     1.12. ``You'' means an individual or a legal entity exercising rights
-     under, and complying with all of the terms of, this License or a future
-     version of this License issued under Section 6.1. For legal entities,
-     ``You'' includes any entity which controls, is controlled by, or is
-     under common control with You. For purposes of this definition,
-     ``control'' means (a) the power, direct or indirect, to cause the
-     direction or management of such entity, whether by contract or
-     otherwise, or (b) ownership of fifty percent (50%) or more of the
-     outstanding shares or beneficial ownership of such entity.
-
-2. Source Code License.
-
-     2.1. The Initial Developer Grant.
-     The Initial Developer hereby grants You a world-wide, royalty-free,
-     non-exclusive license, subject to third party intellectual property
-     claims:
-
-          (a) to use, reproduce, modify, display, perform, sublicense and
-          distribute the Original Code (or portions thereof) with or without
-          Modifications, or as part of a Larger Work; and
-
-          (b) under patents now or hereafter owned or controlled by Initial
-          Developer, to make, have made, use and sell (``Utilize'') the
-          Original Code (or portions thereof), but solely to the extent that
-          any such patent is reasonably necessary to enable You to Utilize
-          the Original Code (or portions thereof) and not to any greater
-          extent that may be necessary to Utilize further Modifications or
-          combinations.
-
-     2.2. Contributor Grant.
-     Each Contributor hereby grants You a world-wide, royalty-free,
-     non-exclusive license, subject to third party intellectual property
-     claims:
-
-          (a) to use, reproduce, modify, display, perform, sublicense and
-          distribute the Modifications created by such Contributor (or
-          portions thereof) either on an unmodified basis, with other
-          Modifications, as Covered Code or as part of a Larger Work; and
-
-          (b) under patents now or hereafter owned or controlled by
-          Contributor, to Utilize the Contributor Version (or portions
-          thereof), but solely to the extent that any such patent is
-          reasonably necessary to enable You to Utilize the Contributor
-          Version (or portions thereof), and not to any greater extent that
-          may be necessary to Utilize further Modifications or combinations.
-
-3. Distribution Obligations.
-
-     3.1. Application of License.
-     The Modifications which You create or to which You contribute are
-     governed by the terms of this License, including without limitation
-     Section 2.2. The Source Code version of Covered Code may be distributed
-     only under the terms of this License or a future version of this
-     License released under Section 6.1, and You must include a copy of this
-     License with every copy of the Source Code You distribute. You may not
-     offer or impose any terms on any Source Code version that alters or
-     restricts the applicable version of this License or the recipients'
-     rights hereunder. However, You may include an additional document
-     offering the additional rights described in Section 3.5.
-
-     3.2. Availability of Source Code.
-     Any Modification which You create or to which You contribute must be
-     made available in Source Code form under the terms of this License
-     either on the same media as an Executable version or via an accepted
-     Electronic Distribution Mechanism to anyone to whom you made an
-     Executable version available; and if made available via Electronic
-     Distribution Mechanism, must remain available for at least twelve (12)
-     months after the date it initially became available, or at least six
-     (6) months after a subsequent version of that particular Modification
-     has been made available to such recipients. You are responsible for
-     ensuring that the Source Code version remains available even if the
-     Electronic Distribution Mechanism is maintained by a third party.
-
-     3.3. Description of Modifications.
-     You must cause all Covered Code to which you contribute to contain a
-     file documenting the changes You made to create that Covered Code and
-     the date of any change. You must include a prominent statement that the
-     Modification is derived, directly or indirectly, from Original Code
-     provided by the Initial Developer and including the name of the Initial
-     Developer in (a) the Source Code, and (b) in any notice in an
-     Executable version or related documentation in which You describe the
-     origin or ownership of the Covered Code.
-
-     3.4. Intellectual Property Matters
-
-          (a) Third Party Claims.
-          If You have knowledge that a party claims an intellectual property
-          right in particular functionality or code (or its utilization
-          under this License), you must include a text file with the source
-          code distribution titled ``LEGAL'' which describes the claim and
-          the party making the claim in sufficient detail that a recipient
-          will know whom to contact. If you obtain such knowledge after You
-          make Your Modification available as described in Section 3.2, You
-          shall promptly modify the LEGAL file in all copies You make
-          available thereafter and shall take other steps (such as notifying
-          appropriate mailing lists or newsgroups) reasonably calculated to
-          inform those who received the Covered Code that new knowledge has
-          been obtained.
-
-          (b) Contributor APIs.
-          If Your Modification is an application programming interface and
-          You own or control patents which are reasonably necessary to
-          implement that API, you must also include this information in the
-          LEGAL file.
-
-     3.5. Required Notices.
-     You must duplicate the notice in Exhibit A in each file of the Source
-     Code, and this License in any documentation for the Source Code, where
-     You describe recipients' rights relating to Covered Code. If You
-     created one or more Modification(s), You may add your name as a
-     Contributor to the notice described in Exhibit A. If it is not possible
-     to put such notice in a particular Source Code file due to its
-     structure, then you must include such notice in a location (such as a
-     relevant directory file) where a user would be likely to look for such
-     a notice. You may choose to offer, and to charge a fee for, warranty,
-     support, indemnity or liability obligations to one or more recipients
-     of Covered Code. However, You may do so only on Your own behalf, and
-     not on behalf of the Initial Developer or any Contributor. You must
-     make it absolutely clear than any such warranty, support, indemnity or
-     liability obligation is offered by You alone, and You hereby agree to
-     indemnify the Initial Developer and every Contributor for any liability
-     incurred by the Initial Developer or such Contributor as a result of
-     warranty, support, indemnity or liability terms You offer.
-
-     3.6. Distribution of Executable Versions.
-     You may distribute Covered Code in Executable form only if the
-     requirements of Section 3.1-3.5 have been met for that Covered Code,
-     and if You include a notice stating that the Source Code version of the
-     Covered Code is available under the terms of this License, including a
-     description of how and where You have fulfilled the obligations of
-     Section 3.2. The notice must be conspicuously included in any notice in
-     an Executable version, related documentation or collateral in which You
-     describe recipients' rights relating to the Covered Code. You may
-     distribute the Executable version of Covered Code under a license of
-     Your choice, which may contain terms different from this License,
-     provided that You are in compliance with the terms of this License and
-     that the license for the Executable version does not attempt to limit
-     or alter the recipient's rights in the Source Code version from the
-     rights set forth in this License. If You distribute the Executable
-     version under a different license You must make it absolutely clear
-     that any terms which differ from this License are offered by You alone,
-     not by the Initial Developer or any Contributor. You hereby agree to
-     indemnify the Initial Developer and every Contributor for any liability
-     incurred by the Initial Developer or such Contributor as a result of
-     any such terms You offer.
-
-     3.7. Larger Works.
-     You may create a Larger Work by combining Covered Code with other code
-     not governed by the terms of this License and distribute the Larger
-     Work as a single product. In such a case, You must make sure the
-     requirements of this License are fulfilled for the Covered Code.
-
-4. Inability to Comply Due to Statute or Regulation.
-
-     If it is impossible for You to comply with any of the terms of this
-     License with respect to some or all of the Covered Code due to statute
-     or regulation then You must: (a) comply with the terms of this License
-     to the maximum extent possible; and (b) describe the limitations and
-     the code they affect. Such description must be included in the LEGAL
-     file described in Section 3.4 and must be included with all
-     distributions of the Source Code. Except to the extent prohibited by
-     statute or regulation, such description must be sufficiently detailed
-     for a recipient of ordinary skill to be able to understand it.
-
-5. Application of this License.
-
-     This License applies to code to which the Initial Developer has
-     attached the notice in Exhibit A, and to related Covered Code.
-
-6. Versions of the License.
-
-     6.1. New Versions.
-     Netscape Communications Corporation (``Netscape'') may publish revised
-     and/or new versions of the License from time to time. Each version will
-     be given a distinguishing version number.
-
-     6.2. Effect of New Versions.
-     Once Covered Code has been published under a particular version of the
-     License, You may always continue to use it under the terms of that
-     version. You may also choose to use such Covered Code under the terms
-     of any subsequent version of the License published by Netscape. No one
-     other than Netscape has the right to modify the terms applicable to
-     Covered Code created under this License.
-
-     6.3. Derivative Works.
-     If you create or use a modified version of this License (which you may
-     only do in order to apply it to code which is not already Covered Code
-     governed by this License), you must (a) rename Your license so that the
-     phrases ``Mozilla'', ``MOZILLAPL'', ``MOZPL'', ``Netscape'', ``NPL'' or
-     any confusingly similar phrase do not appear anywhere in your license
-     and (b) otherwise make it clear that your version of the license
-     contains terms which differ from the Mozilla Public License and
-     Netscape Public License. (Filling in the name of the Initial Developer,
-     Original Code or Contributor in the notice described in Exhibit A shall
-     not of themselves be deemed to be modifications of this License.)
-
-7. DISCLAIMER OF WARRANTY.
-
-     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN ``AS IS'' BASIS,
-     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
-     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
-     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
-     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
-     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
-     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
-     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
-     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
-     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-8. TERMINATION.
-
-     This License and the rights granted hereunder will terminate
-     automatically if You fail to comply with terms herein and fail to cure
-     such breach within 30 days of becoming aware of the breach. All
-     sublicenses to the Covered Code which are properly granted shall
-     survive any termination of this License. Provisions which, by their
-     nature, must remain in effect beyond the termination of this License
-     shall survive.
-
-9. LIMITATION OF LIABILITY.
-
-     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
-     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE INITIAL
-     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
-     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO YOU OR ANY OTHER
-     PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
-     OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF
-     GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND
-     ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE
-     BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
-     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
-     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
-     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
-     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THAT
-     EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
-
-10. U.S. GOVERNMENT END USERS.
-
-     The Covered Code is a ``commercial item,'' as that term is defined in
-     48 C.F.R. 2.101 (Oct. 1995), consisting of ``commercial computer
-     software'' and ``commercial computer software documentation,'' as such
-     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
-     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
-     all U.S. Government End Users acquire Covered Code with only those
-     rights set forth herein.
-
-11. MISCELLANEOUS.
-
-     This License represents the complete agreement concerning subject
-     matter hereof. If any provision of this License is held to be
-     unenforceable, such provision shall be reformed only to the extent
-     necessary to make it enforceable. This License shall be governed by
-     California law provisions (except to the extent applicable law, if any,
-     provides otherwise), excluding its conflict-of-law provisions. With
-     respect to disputes in which at least one party is a citizen of, or an
-     entity chartered or registered to do business in, the United States of
-     America: (a) unless otherwise agreed in writing, all disputes relating
-     to this License (excepting any dispute relating to intellectual
-     property rights) shall be subject to final and binding arbitration,
-     with the losing party paying all costs of arbitration; (b) any
-     arbitration relating to this Agreement shall be held in Santa Clara
-     County, California, under the auspices of JAMS/EndDispute; and (c) any
-     litigation relating to this Agreement shall be subject to the
-     jurisdiction of the Federal Courts of the Northern District of
-     California, with venue lying in Santa Clara County, California, with
-     the losing party responsible for costs, including without limitation,
-     court costs and reasonable attorneys fees and expenses. The application
-     of the United Nations Convention on Contracts for the International
-     Sale of Goods is expressly excluded. Any law or regulation which
-     provides that the language of a contract shall be construed against the
-     drafter shall not apply to this License.
-
-12. RESPONSIBILITY FOR CLAIMS.
-
-     Except in cases where another Contributor has failed to comply with
-     Section 3.4, You are responsible for damages arising, directly or
-     indirectly, out of Your utilization of rights under this License, based
-     on the number of copies of Covered Code you made available, the
-     revenues you received from utilizing such rights, and other relevant
-     factors. You agree to work with affected parties to distribute
-     responsibility on an equitable basis.
-
-EXHIBIT A.
-
-     ``The contents of this file are subject to the Mozilla Public License
-     Version 1.0 (the "License"); you may not use this file except in
-     compliance with the License. You may obtain a copy of the License at
-     http://www.mozilla.org/MPL/
-
-     Software distributed under the License is distributed on an "AS IS"
-     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
-     License for the specific language governing rights and limitations
-     under the License.
-
-     The Original Code is ______________________________________.
-
-     The Initial Developer of the Original Code is ________________________.
-     Portions created by ______________________ are Copyright (C) ______
-     _______________________. All Rights Reserved.
-
-     Contributor(s): ______________________________________.''
diff --git a/ide/html.validation/external/validator-20200626.patch b/ide/html.validation/external/validator-20200626.patch
index 2d496e7..d504cde 100644
--- a/ide/html.validation/external/validator-20200626.patch
+++ b/ide/html.validation/external/validator-20200626.patch
@@ -30,6 +30,183 @@
  ]
  
  moduleDependencyPackages = [
+diff --git a/src/nu/validator/checker/schematronequiv/Assertions.java b/src/nu/validator/checker/schematronequiv/Assertions.java
+index 917182f3..6aba4301 100644
+--- a/src/nu/validator/checker/schematronequiv/Assertions.java
++++ b/src/nu/validator/checker/schematronequiv/Assertions.java
+@@ -65,12 +65,6 @@ import nu.validator.messages.MessageEmitterAdapter;
+ 
+ import org.relaxng.datatype.DatatypeException;
+ 
+-import org.w3c.css.css.StyleSheetParser;
+-import org.w3c.css.parser.CssError;
+-import org.w3c.css.parser.CssParseException;
+-import org.w3c.css.parser.Errors;
+-import org.w3c.css.util.ApplContext;
+-
+ import org.xml.sax.Attributes;
+ import org.xml.sax.Locator;
+ import org.xml.sax.SAXException;
+@@ -1506,93 +1500,6 @@ public class Assertions extends Checker {
+             } else if ("option" == localName
+                     && !stack[currentPtr].hasOption()) {
+                 stack[currentPtr].setOptionFound();
+-            } else if ("style" == localName) {
+-                String styleContents = node.getTextContent().toString();
+-                int lineOffset = 0;
+-                if (styleContents.startsWith("\n")) {
+-                    lineOffset = 1;
+-                }
+-                ApplContext ac = new ApplContext("en");
+-                ac.setCssVersionAndProfile("css3svg");
+-                ac.setMedium("all");
+-                ac.setSuggestPropertyName(false);
+-                ac.setTreatVendorExtensionsAsWarnings(true);
+-                ac.setTreatCssHacksAsWarnings(true);
+-                ac.setWarningLevel(-1);
+-                ac.setFakeURL("file://localhost/StyleElement");
+-                StyleSheetParser styleSheetParser = new StyleSheetParser();
+-                styleSheetParser.parseStyleSheet(ac,
+-                        new StringReader(styleContents.substring(lineOffset)),
+-                        null);
+-                styleSheetParser.getStyleSheet().findConflicts(ac);
+-                Errors errors = styleSheetParser.getStyleSheet().getErrors();
+-                if (errors.getErrorCount() > 0) {
+-                    incrementUseCounter("style-element-errors-found");
+-                }
+-                for (int i = 0; i < errors.getErrorCount(); i++) {
+-                    String message = "";
+-                    String cssProperty = "";
+-                    String cssMessage = "";
+-                    CssError error = errors.getErrorAt(i);
+-                    int beginLine = error.getBeginLine() + lineOffset;
+-                    int beginColumn = error.getBeginColumn();
+-                    int endLine = error.getEndLine() + lineOffset;
+-                    int endColumn = error.getEndColumn();
+-                    if (beginLine == 0) {
+-                        continue;
+-                    }
+-                    Throwable ex = error.getException();
+-                    if (ex instanceof CssParseException) {
+-                        CssParseException cpe = (CssParseException) ex;
+-                        if ("generator.unrecognize" //
+-                                .equals(cpe.getErrorType())) {
+-                            cssMessage = "Parse Error";
+-                        }
+-                        if (cpe.getProperty() != null) {
+-                            cssProperty = String.format("\u201c%s\u201D: ",
+-                                    cpe.getProperty());
+-                        }
+-                        if (cpe.getMessage() != null) {
+-                            cssMessage = cpe.getMessage();
+-                        }
+-                        if (!"".equals(cssMessage)) {
+-                            message = cssProperty + cssMessage.trim();
+-                            if (!".".equals(
+-                                    message.substring(message.length() - 1))) {
+-                                message = message + ".";
+-                            }
+-                        }
+-                    } else {
+-                        message = ex.getMessage();
+-                    }
+-                    if (!"".equals(message)) {
+-                        int lastLine = node.locator.getLineNumber() //
+-                                + endLine - 1;
+-                        int lastColumn = endColumn;
+-                        int columnOffset = node.locator.getColumnNumber();
+-                        if (error.getBeginLine() == 1) {
+-                            if (lineOffset != 0) {
+-                                columnOffset = 0;
+-                            }
+-                        } else {
+-                            columnOffset = 0;
+-                        }
+-                        String prefix = sourceIsCss ? "" : "CSS: ";
+-                        SAXParseException spe = new SAXParseException( //
+-                                prefix + message, publicId, systemId, //
+-                                lastLine, lastColumn);
+-                        int[] start = {
+-                                node.locator.getLineNumber() + beginLine - 1,
+-                                beginColumn, columnOffset };
+-                        if ((getErrorHandler() instanceof MessageEmitterAdapter)
+-                                && !(getErrorHandler() instanceof TestRunner)) {
+-                            ((MessageEmitterAdapter) getErrorHandler()) //
+-                                    .errorWithStart(spe, start);
+-                        } else {
+-                            getErrorHandler().error(spe);
+-                        }
+-                    }
+-                }
+             }
+             if ("article" == localName || "aside" == localName
+                     || "nav" == localName || "section" == localName) {
+@@ -1743,64 +1650,7 @@ public class Assertions extends Checker {
+                                     + " XML-compatible.");
+                         }
+                     }
+-                    if ("style" == attLocal) {
+-                        String styleContents = atts.getValue(i);
+-                        ApplContext ac = new ApplContext("en");
+-                        ac.setCssVersionAndProfile("css3svg");
+-                        ac.setMedium("all");
+-                        ac.setSuggestPropertyName(false);
+-                        ac.setTreatVendorExtensionsAsWarnings(true);
+-                        ac.setTreatCssHacksAsWarnings(true);
+-                        ac.setWarningLevel(-1);
+-                        ac.setFakeURL("file://localhost/StyleAttribute");
+-                        StyleSheetParser styleSheetParser = //
+-                                new StyleSheetParser();
+-                        styleSheetParser.parseStyleAttribute(ac,
+-                                new ByteArrayInputStream(
+-                                        styleContents.getBytes()),
+-                                "", ac.getFakeURL(),
+-                                getDocumentLocator().getLineNumber());
+-                        styleSheetParser.getStyleSheet().findConflicts(ac);
+-                        Errors errors = //
+-                                styleSheetParser.getStyleSheet().getErrors();
+-                        if (errors.getErrorCount() > 0) {
+-                            incrementUseCounter("style-attribute-errors-found");
+-                        }
+-                        for (int j = 0; j < errors.getErrorCount(); j++) {
+-                            String message = "";
+-                            String cssProperty = "";
+-                            String cssMessage = "";
+-                            CssError error = errors.getErrorAt(j);
+-                            Throwable ex = error.getException();
+-                            if (ex instanceof CssParseException) {
+-                                CssParseException cpe = (CssParseException) ex;
+-                                if ("generator.unrecognize" //
+-                                        .equals(cpe.getErrorType())) {
+-                                    cssMessage = "Parse Error";
+-                                }
+-                                if (cpe.getProperty() != null) {
+-                                    cssProperty = String.format(
+-                                            "\u201c%s\u201D: ",
+-                                            cpe.getProperty());
+-                                }
+-                                if (cpe.getMessage() != null) {
+-                                    cssMessage = cpe.getMessage();
+-                                }
+-                                if (!"".equals(cssMessage)) {
+-                                    message = cssProperty + cssMessage.trim();
+-                                    if (!".".equals(message.substring(
+-                                            message.length() - 1))) {
+-                                        message = message + ".";
+-                                    }
+-                                }
+-                            } else {
+-                                message = ex.getMessage();
+-                            }
+-                            if (!"".equals(message)) {
+-                                err("CSS: " + message);
+-                            }
+-                        }
+-                    } else if ("tabindex" == attLocal) {
++                    if ("tabindex" == attLocal) {
+                         tabindex = true;
+                     } else if ("href" == attLocal) {
+                         href = true;
 diff --git a/src/nu/validator/datatype/IriRef.java b/src/nu/validator/datatype/IriRef.java
 index 8fb8de35..461c753c 100644
 --- a/src/nu/validator/datatype/IriRef.java
@@ -154,6 +331,80 @@
              if (!isScript(subtag)) {
                  throw newDatatypeException("Bad script subtag.");
              }
+diff --git a/src/nu/validator/datatype/MediaQuery.java b/src/nu/validator/datatype/MediaQuery.java
+index dff51c58..1a2c86cd 100644
+--- a/src/nu/validator/datatype/MediaQuery.java
++++ b/src/nu/validator/datatype/MediaQuery.java
+@@ -22,14 +22,7 @@
+ 
+ package nu.validator.datatype;
+ 
+-import java.io.StringReader;
+-
+ import org.relaxng.datatype.DatatypeException;
+-import org.w3c.css.css.StyleSheetParser;
+-import org.w3c.css.parser.CssError;
+-import org.w3c.css.parser.CssParseException;
+-import org.w3c.css.parser.Errors;
+-import org.w3c.css.util.ApplContext;
+ 
+ public class MediaQuery extends AbstractDatatype {
+ 
+@@ -44,54 +37,6 @@ public class MediaQuery extends AbstractDatatype {
+ 
+     @Override
+     public void checkValid(CharSequence literal) throws DatatypeException {
+-        ApplContext ac = new ApplContext("en");
+-        ac.setCssVersionAndProfile("css3svg");
+-        ac.setMedium("all");
+-        ac.setSuggestPropertyName(false);
+-        ac.setTreatVendorExtensionsAsWarnings(true);
+-        ac.setTreatCssHacksAsWarnings(true);
+-        ac.setWarningLevel(-1);
+-        ac.setFakeURL("file://localhost/StyleElement");
+-        String literalString = literal.toString();
+-        String style;
+-        if (isMediaCondition()) {
+-            style = String.format("@media all and %s %s", literalString, "{}");
+-        } else {
+-            style = String.format("@media %s %s", literalString, "{}");
+-        }
+-        StyleSheetParser styleSheetParser = new StyleSheetParser();
+-        styleSheetParser.parseStyleSheet(ac, new StringReader(style), null);
+-        styleSheetParser.getStyleSheet().findConflicts(ac);
+-        Errors errors = styleSheetParser.getStyleSheet().getErrors();
+-        for (int i = 0; i < errors.getErrorCount(); i++) {
+-            String message = "";
+-            String cssProperty = "";
+-            String cssMessage = "";
+-            CssError error = errors.getErrorAt(i);
+-            Throwable ex = error.getException();
+-            if (ex instanceof CssParseException) {
+-                CssParseException cpe = (CssParseException) ex;
+-                if ("generator.unrecognize" //
+-                        .equals(cpe.getErrorType())) {
+-                    cssMessage = "Parse Error";
+-                }
+-                if (cpe.getProperty() != null) {
+-                    cssProperty = String.format("\u201c%s\u201D: ",
+-                            cpe.getProperty());
+-                }
+-                if (cpe.getMessage() != null) {
+-                    cssMessage = cpe.getMessage();
+-                }
+-                if (!"".equals(cssMessage)) {
+-                    message = cssProperty + cssMessage + ".";
+-                }
+-            } else {
+-                message = ex.getMessage();
+-            }
+-            if (!"".equals(message)) {
+-                throw newDatatypeException(message);
+-            }
+-        }
+     }
+ 
+     protected boolean isMediaCondition() {
 diff --git a/src/nu/validator/io/DataUri.java b/src/nu/validator/io/DataUri.java
 index eb6fba26..d68f74a5 100644
 --- a/src/nu/validator/io/DataUri.java
diff --git a/ide/html.validation/external/validator-howto-build.txt b/ide/html.validation/external/validator-howto-build.txt
new file mode 100644
index 0000000..49708f9
--- /dev/null
+++ b/ide/html.validation/external/validator-howto-build.txt
@@ -0,0 +1,15 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more contributor
+# license agreements; and to You under the Apache License, Version 2.0.
+#
+# This way the validator-20200626-patched.jar was build:
+git clone https://github.com/validator/validator.git
+cd validator
+git checkout 787a7a7e972719edf7a79009d768f5111e1d93bc
+git apply ../validator-20200626.patch
+python3 checker.py all
+# ignore the error messages
+cd jars
+mv validator.jar validator-20200626-patched.jar
+sha1sum validator-20200626-patched.jar | awk '{print "mv "$2" "toupper($1)"-"$2}' | sh
+# At this point the directory cotains a build of the validator in the format
+# needed for the upload to the netbeans.osuosl.org
\ No newline at end of file
diff --git a/ide/html.validation/external/validator.patch b/ide/html.validation/external/validator.patch
deleted file mode 100644
index 33a23da..0000000
--- a/ide/html.validation/external/validator.patch
+++ /dev/null
@@ -1,8898 +0,0 @@
-diff --git a/build/build.py b/build/build.py
-index 1a03b4c..7a99cf4 100755
---- a/build/build.py
-+++ b/build/build.py
-@@ -168,6 +168,7 @@ runDependencyJars = [
-   "jetty-util-ajax-9.2.9.v20150224.jar",
-   "log4j-1.2.17.jar",
-   "rhino-1.7R5.jar",
-+  "iri.jar"
- ]
- 
- buildOnlyDependencyJars = [
-@@ -641,6 +642,7 @@ def buildEmitters():
-     '-d "%s"' % classDir,
-     '-encoding UTF-8',
-   ]
-+  return
-   if javaVersion != "":
-     args.append('-target ' + javaVersion)
-     args.append('-source ' + javaVersion)
-diff --git a/htmlparser b/htmlparser
-deleted file mode 160000
-index 543cc3e..0000000
---- a/htmlparser
-+++ /dev/null
-@@ -1 +0,0 @@
--Subproject commit 543cc3e7d442874c10ed40e114317115bcff1ca5
-diff --git a/jing-trang b/jing-trang
-deleted file mode 160000
-index 35eb11b..0000000
---- a/jing-trang
-+++ /dev/null
-@@ -1 +0,0 @@
--Subproject commit 35eb11b84a230ee4d7168f12f98a28bf40e940aa
-diff --git a/src/nu/validator/client/TestRunner.java b/src/nu/validator/client/TestRunner.java
-deleted file mode 100644
-index 551df39..0000000
---- a/src/nu/validator/client/TestRunner.java
-+++ /dev/null
-@@ -1,611 +0,0 @@
--/*
-- * Copyright (c) 2013-2015 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.client;
--
--import java.io.BufferedWriter;
--import java.io.File;
--import java.io.FileInputStream;
--import java.io.FileOutputStream;
--import java.io.InputStreamReader;
--import java.io.IOException;
--import java.io.OutputStreamWriter;
--import java.io.PrintWriter;
--import java.net.MalformedURLException;
--import java.util.ArrayList;
--import java.util.HashMap;
--import java.util.LinkedHashMap;
--import java.util.List;
--import java.util.Map;
--import java.util.regex.Pattern;
--
--import org.xml.sax.ErrorHandler;
--import org.xml.sax.SAXException;
--import org.xml.sax.SAXParseException;
--
--import org.eclipse.jetty.util.ajax.JSON;
--
--import org.relaxng.datatype.DatatypeException;
--import com.thaiopensource.relaxng.exceptions.BadAttributeValueException;
--
--import nu.validator.datatype.Html5DatatypeException;
--
--import nu.validator.validation.SimpleDocumentValidator;
--
--public class TestRunner implements ErrorHandler {
--
--    private boolean inError = false;
--
--    private boolean emitMessages = false;
--
--    private boolean exceptionIsWarning = false;
--
--    private boolean expectingError = false;
--
--    private Exception exception = null;
--
--    private SimpleDocumentValidator validator;
--
--    private PrintWriter err;
--
--    private PrintWriter out;
--
--    private String schema = "http://s.validator.nu/html5-all.rnc";
--
--    private boolean failed = false;
--
--    private static File messagesFile;
--
--    private static String[] ignoreList = null;
--
--    private static boolean writeMessages;
--
--    private static boolean verbose;
--
--    private String baseDir = null;
--
--    private Map<String, String> expectedMessages;
--
--    private Map<String, String> reportedMessages;
--
--    public TestRunner() throws IOException {
--        reportedMessages = new LinkedHashMap<String, String>();
--        validator = new SimpleDocumentValidator();
--        try {
--            this.err = new PrintWriter(new OutputStreamWriter(System.err,
--                    "UTF-8"));
--            this.out = new PrintWriter(new OutputStreamWriter(System.out,
--                    "UTF-8"));
--        } catch (Exception e) {
--            // If this happens, the JDK is too broken anyway
--            throw new RuntimeException(e);
--        }
--    }
--
--    private void checkHtmlFile(File file) throws IOException, SAXException {
--        if (!file.exists()) {
--            if (verbose) {
--                out.println(String.format("\"%s\": warning: File not found.",
--                        file.toURI().toURL().toString()));
--                out.flush();
--            }
--            return;
--        }
--        if (verbose) {
--            out.println(file);
--            out.flush();
--        }
--        if (isHtml(file)) {
--            validator.checkHtmlFile(file, true);
--        } else if (isXhtml(file)) {
--            validator.checkXmlFile(file);
--        } else {
--            if (verbose) {
--                out.println(String.format(
--                        "\"%s\": warning: File was not checked."
--                                + " Files must have a .html, .xhtml, .htm,"
--                                + " or .xht extension.",
--                        file.toURI().toURL().toString()));
--                out.flush();
--            }
--        }
--    }
--
--    private boolean isXhtml(File file) {
--        String name = file.getName();
--        return name.endsWith(".xhtml") || name.endsWith(".xht");
--    }
--
--    private boolean isHtml(File file) {
--        String name = file.getName();
--        return name.endsWith(".html") || name.endsWith(".htm");
--    }
--
--    private boolean isCheckableFile(File file) {
--        return file.isFile() && (isHtml(file) || isXhtml(file));
--    }
--
--    private void recurseDirectory(File directory) throws SAXException,
--            IOException {
--        File[] files = directory.listFiles();
--        for (int i = 0; i < files.length; i++) {
--            File file = files[i];
--            if (file.isDirectory()) {
--                recurseDirectory(file);
--            } else {
--                checkHtmlFile(file);
--            }
--        }
--    }
--
--    private boolean isIgnorable(File file) throws IOException {
--        String testPathname = file.getAbsolutePath().substring(
--                baseDir.length() + 1);
--        if (ignoreList != null) {
--            for (String substring : ignoreList) {
--                if (testPathname.contains(substring)) {
--                    if (verbose) {
--                        out.println(String.format(
--                                "\"%s\": warning: File ignored.",
--                                file.toURI().toURL().toString()));
--                        out.flush();
--                    }
--                    return true;
--                }
--            }
--        }
--        return false;
--    }
--
--    private void checkFiles(List<File> files) throws IOException {
--        for (File file : files) {
--            if (isIgnorable(file)) {
--                continue;
--            }
--            reset();
--            emitMessages = true;
--            try {
--                if (file.isDirectory()) {
--                    recurseDirectory(file);
--                } else {
--                    checkHtmlFile(file);
--                }
--            } catch (IOException e) {
--            } catch (SAXException e) {
--            }
--            if (inError) {
--                failed = true;
--            }
--        }
--    }
--
--    private boolean messageMatches(String testFilename) {
--        // p{C} = Other = Control+Format+Private_Use+Surrogate+Unassigned
--        // http://www.regular-expressions.info/unicode.html#category
--        // http://www.unicode.org/reports/tr18/#General_Category_Property
--        String messageReported = exception.getMessage().replaceAll("\\p{C}",
--                "?");
--        String messageExpected = expectedMessages.get(testFilename).replaceAll(
--                "\\p{C}", "?");
--        // FIXME: The string replacements below are a hack to "normalize"
--        // error messages reported for bad values of the ins/del datetime
--        // attribute, to work around the fact that in Java 8, parts of
--        // those error messages don't always get emitted in the same order
--        // that they do in Java 7 and earlier.
--        Pattern p;
--        p = Pattern.compile("(Bad datetime with timezone: .+) (Bad date: .+)");
--        messageExpected = p.matcher(messageExpected).replaceAll("$2 $1");
--        messageReported = p.matcher(messageReported).replaceAll("$2 $1");
--        return messageReported.equals(messageExpected);
--    }
--
--    private void checkInvalidFiles(List<File> files) throws IOException {
--        String testFilename;
--        expectingError = true;
--        for (File file : files) {
--            if (isIgnorable(file)) {
--                continue;
--            }
--            reset();
--            try {
--                if (file.isDirectory()) {
--                    recurseDirectory(file);
--                } else {
--                    checkHtmlFile(file);
--                }
--            } catch (IOException e) {
--            } catch (SAXException e) {
--            }
--            if (exception != null) {
--                testFilename = file.getAbsolutePath().substring(
--                        baseDir.length() + 1);
--                if (writeMessages) {
--                    reportedMessages.put(testFilename, exception.getMessage());
--                } else if (expectedMessages != null
--                        && expectedMessages.get(testFilename) == null) {
--                    try {
--                        err.println(String.format(
--                                "\"%s\": warning: No expected message in"
--                                        + " messages file.",
--                                file.toURI().toURL().toString()));
--                        err.flush();
--                    } catch (MalformedURLException e) {
--                        throw new RuntimeException(e);
--                    }
--                } else if (expectedMessages != null
--                        && !messageMatches(testFilename)) {
--                    failed = true;
--                    try {
--                        err.println(String.format(
--                                "\"%s\": error: Expected \"%s\""
--                                        + " but instead encountered \"%s\".",
--                                file.toURI().toURL().toString(),
--                                expectedMessages.get(testFilename),
--                                exception.getMessage()));
--                        err.flush();
--                    } catch (MalformedURLException e) {
--                        throw new RuntimeException(e);
--                    }
--                }
--            }
--            if (!inError) {
--                failed = true;
--                try {
--                    err.println(String.format(
--                            "\"%s\": error: Expected an error but did not"
--                                    + " encounter any.",
--                            file.toURI().toURL().toString()));
--                    err.flush();
--                } catch (MalformedURLException e) {
--                    throw new RuntimeException(e);
--                }
--            }
--        }
--    }
--
--    private void checkHasWarningFiles(List<File> files) throws IOException {
--        String testFilename;
--        expectingError = false;
--        for (File file : files) {
--            if (isIgnorable(file)) {
--                continue;
--            }
--            reset();
--            try {
--                if (file.isDirectory()) {
--                    recurseDirectory(file);
--                } else {
--                    checkHtmlFile(file);
--                }
--            } catch (IOException e) {
--            } catch (SAXException e) {
--            }
--            if (exception != null) {
--                testFilename = file.getAbsolutePath().substring(
--                        baseDir.length() + 1);
--                if (writeMessages) {
--                    reportedMessages.put(testFilename, exception.getMessage());
--                } else if (expectedMessages != null
--                        && expectedMessages.get(testFilename) == null) {
--                    try {
--                        err.println(String.format(
--                                "\"%s\": warning: No expected message in"
--                                        + " messages file.",
--                                file.toURI().toURL().toString()));
--                        err.flush();
--                    } catch (MalformedURLException e) {
--                        throw new RuntimeException(e);
--                    }
--                } else if (expectedMessages != null
--                        && !messageMatches(testFilename)) {
--                    try {
--                        err.println(String.format(
--                                "\"%s\": error: Expected \"%s\""
--                                        + " but instead encountered \"%s\".",
--                                file.toURI().toURL().toString(),
--                                expectedMessages.get(testFilename),
--                                exception.getMessage()));
--                        err.flush();
--                    } catch (MalformedURLException e) {
--                        throw new RuntimeException(e);
--                    }
--                }
--            }
--            if (inError) {
--                failed = true;
--                try {
--                    err.println(String.format(
--                            "\"%s\": error: Expected a warning but encountered"
--                                    + " an error first.",
--                            file.toURI().toURL().toString()));
--                    err.flush();
--                } catch (MalformedURLException e) {
--                    throw new RuntimeException(e);
--                }
--            } else if (!exceptionIsWarning) {
--                try {
--                    err.println(String.format(
--                            "\"%s\": error: Expected a warning but did not"
--                                    + " encounter any.",
--                            file.toURI().toURL().toString()));
--                    err.flush();
--                } catch (MalformedURLException e) {
--                    throw new RuntimeException(e);
--                }
--            }
--            if (inError) {
--                failed = true;
--                try {
--                    err.println(String.format(
--                            "\"%s\": error: Expected a warning only but"
--                                    + " encountered at least one error.",
--                            file.toURI().toURL().toString()));
--                    err.flush();
--                } catch (MalformedURLException e) {
--                    throw new RuntimeException(e);
--                }
--            }
--        }
--    }
--
--    private enum State {
--        EXPECTING_INVALID_FILES, EXPECTING_VALID_FILES, EXPECTING_ANYTHING
--    }
--
--    private void checkTestDirectoryAgainstSchema(File directory,
--            String schemaUrl) throws SAXException, Exception {
--        validator.setUpMainSchema(schemaUrl, this);
--        checkTestFiles(directory, State.EXPECTING_ANYTHING);
--    }
--
--    private void checkTestFiles(File directory, State state)
--            throws SAXException, IOException {
--        File[] files = directory.listFiles();
--        List<File> validFiles = new ArrayList<File>();
--        List<File> invalidFiles = new ArrayList<File>();
--        List<File> hasWarningFiles = new ArrayList<File>();
--        if (files == null) {
--            if (verbose) {
--                try {
--                    out.println(String.format(
--                            "\"%s\": warning: No files found in directory.",
--                            directory.toURI().toURL().toString()));
--                    out.flush();
--                } catch (MalformedURLException mue) {
--                    throw new RuntimeException(mue);
--                }
--            }
--            return;
--        }
--        for (int i = 0; i < files.length; i++) {
--            File file = files[i];
--            if (file.isDirectory()) {
--                if (state != State.EXPECTING_ANYTHING) {
--                    checkTestFiles(file, state);
--                } else if ("invalid".equals(file.getName())) {
--                    checkTestFiles(file, State.EXPECTING_INVALID_FILES);
--                } else if ("valid".equals(file.getName())) {
--                    checkTestFiles(file, State.EXPECTING_VALID_FILES);
--                } else {
--                    checkTestFiles(file, State.EXPECTING_ANYTHING);
--                }
--            } else if (isCheckableFile(file)) {
--                if (state == State.EXPECTING_INVALID_FILES) {
--                    invalidFiles.add(file);
--                } else if (state == State.EXPECTING_VALID_FILES) {
--                    validFiles.add(file);
--                } else if (file.getPath().indexOf("novalid") > 0) {
--                    invalidFiles.add(file);
--                } else if (file.getPath().indexOf("haswarn") > 0) {
--                    hasWarningFiles.add(file);
--                } else {
--                    validFiles.add(file);
--                }
--            }
--        }
--        if (validFiles.size() > 0) {
--            validator.setUpValidatorAndParsers(this, false, false);
--            checkFiles(validFiles);
--        }
--        if (invalidFiles.size() > 0) {
--            validator.setUpValidatorAndParsers(this, false, false);
--            checkInvalidFiles(invalidFiles);
--        }
--        if (hasWarningFiles.size() > 0) {
--            validator.setUpValidatorAndParsers(this, false, false);
--            checkHasWarningFiles(hasWarningFiles);
--        }
--        if (writeMessages) {
--            OutputStreamWriter out = new OutputStreamWriter(
--                    new FileOutputStream(messagesFile), "utf-8");
--            BufferedWriter bw = new BufferedWriter(out);
--            bw.write(JSON.toString(reportedMessages));
--            bw.close();
--        }
--    }
--
--    public boolean runTestSuite() throws SAXException, Exception {
--        if (messagesFile != null) {
--            baseDir = messagesFile.getAbsoluteFile().getParent();
--            FileInputStream fis = new FileInputStream(messagesFile);
--            InputStreamReader reader = new InputStreamReader(fis, "UTF-8");
--            expectedMessages = (HashMap<String, String>) JSON.parse(reader);
--        } else {
--            baseDir = System.getProperty("user.dir");
--        }
--        for (File directory : new File(baseDir).listFiles()) {
--            if (directory.isDirectory()) {
--                if (directory.getName().contains("rdfalite")) {
--                    checkTestDirectoryAgainstSchema(directory,
--                            "http://s.validator.nu/html5-rdfalite.rnc");
--                } else if (directory.getName().contains("xhtml")) {
--                    checkTestDirectoryAgainstSchema(directory,
--                            "http://s.validator.nu/xhtml5-all.rnc");
--                } else {
--                    checkTestDirectoryAgainstSchema(directory, schema);
--                }
--            }
--        }
--        if (verbose) {
--            if (failed) {
--                out.println("Failure!");
--                out.flush();
--            } else {
--                out.println("Success!");
--                out.flush();
--            }
--        }
--        return !failed;
--    }
--
--    private void emitMessage(SAXParseException e, String messageType) {
--        String systemId = e.getSystemId();
--        err.write((systemId == null) ? "" : '\"' + systemId + '\"');
--        err.write(":");
--        err.write(Integer.toString(e.getLineNumber()));
--        err.write(":");
--        err.write(Integer.toString(e.getColumnNumber()));
--        err.write(": ");
--        err.write(messageType);
--        err.write(": ");
--        err.write(e.getMessage());
--        err.write("\n");
--        err.flush();
--    }
--
--    public void warning(SAXParseException e) throws SAXException {
--        if (emitMessages) {
--            emitMessage(e, "warning");
--        } else if (exception == null && !expectingError) {
--            exception = e;
--            exceptionIsWarning = true;
--        }
--    }
--
--    public void error(SAXParseException e) throws SAXException {
--        if (emitMessages) {
--            emitMessage(e, "error");
--        } else if (exception == null) {
--            exception = e;
--            if (e instanceof BadAttributeValueException) {
--                BadAttributeValueException ex = (BadAttributeValueException) e;
--                Map<String, DatatypeException> datatypeErrors = ex.getExceptions();
--                for (Map.Entry<String, DatatypeException> entry : datatypeErrors.entrySet()) {
--                    DatatypeException dex = entry.getValue();
--                    if (dex instanceof Html5DatatypeException) {
--                        Html5DatatypeException ex5 = (Html5DatatypeException) dex;
--                        if (ex5.isWarning()) {
--                            exceptionIsWarning = true;
--                            return;
--                        }
--                    }
--                }
--            }
--        }
--        inError = true;
--    }
--
--    public void fatalError(SAXParseException e) throws SAXException {
--        inError = true;
--        if (emitMessages) {
--            emitMessage(e, "fatal error");
--            return;
--        } else if (exception == null) {
--            exception = e;
--        }
--    }
--
--    public void reset() {
--        exception = null;
--        inError = false;
--        emitMessages = false;
--        exceptionIsWarning = false;
--    }
--
--    public static void main(String[] args) throws SAXException, Exception {
--        if (args.length < 1) {
--            usage();
--            System.exit(0);
--        }
--        verbose = false;
--        String messagesFilename = null;
--        System.setProperty("nu.validator.datatype.warn", "true");
--        for (int i = 0; i < args.length; i++) {
--            if ("--verbose".equals(args[i])) {
--                verbose = true;
--            } else if ("--errors-only".equals(args[i])) {
--                System.setProperty("nu.validator.datatype.warn", "false");
--            } else if ("--write-messages".equals(args[i])) {
--                writeMessages = true;
--            } else if (args[i].startsWith("--ignore=")) {
--                ignoreList = args[i].substring(9, args[i].length()).split(",");
--            } else if (args[i].startsWith("--")) {
--                System.out.println(String.format(
--                        "\nError: There is no option \"%s\".", args[i]));
--                usage();
--                System.exit(1);
--            } else {
--                if (args[i].endsWith(".json")) {
--                    messagesFilename = args[i];
--                } else {
--                    System.out.println("\nError: Expected the name of a messages"
--                            + " file with a .json extension.");
--                    usage();
--                    System.exit(1);
--                }
--            }
--        }
--        if (messagesFilename != null) {
--            messagesFile = new File(messagesFilename);
--            if (!messagesFile.exists()) {
--                System.out.println("\nError: \"" + messagesFilename
--                        + "\" file not found.");
--                System.exit(1);
--            } else if (!messagesFile.isFile()) {
--                System.out.println("\nError: \"" + messagesFilename
--                        + "\" is not a file.");
--                System.exit(1);
--            }
--        } else if (writeMessages) {
--            System.out.println("\nError: Expected the name of a messages"
--                    + " file with a .json extension.");
--            usage();
--            System.exit(1);
--        }
--        TestRunner tr = new TestRunner();
--        if (tr.runTestSuite()) {
--            System.exit(0);
--        } else {
--            System.exit(1);
--        }
--    }
--
--    private static void usage() {
--        System.out.println("\nUsage:");
--        System.out.println("\n    java nu.validator.client.TestRunner [--errors-only] [--write-messages]");
--        System.out.println("          [--verbose] [MESSAGES.json]");
--        System.out.println("\n...where the MESSAGES.json file contains name/value pairs in which the name is");
--        System.out.println("a pathname of a document to check and the value is the first error message or");
--        System.out.println("warning message the validator is expected to report when checking that document.");
--        System.out.println("Use the --write-messages option to create the file.");
--    }
--}
-diff --git a/src/nu/validator/datatype/FunctionBody.java b/src/nu/validator/datatype/FunctionBody.java
-index 5e8bd69..35642ef 100644
---- a/src/nu/validator/datatype/FunctionBody.java
-+++ b/src/nu/validator/datatype/FunctionBody.java
-@@ -27,9 +27,9 @@ import java.io.IOException;
- import java.io.Reader;
- import java.io.StringReader;
- 
--import org.mozilla.javascript.Context;
--import org.mozilla.javascript.ContextFactory;
--import org.mozilla.javascript.RhinoException;
-+//import org.mozilla.javascript.Context;
-+//import org.mozilla.javascript.ContextFactory;
-+//import org.mozilla.javascript.RhinoException;
- import org.relaxng.datatype.DatatypeException;
- 
- public class FunctionBody extends AbstractDatatype {
-@@ -44,25 +44,25 @@ public class FunctionBody extends AbstractDatatype {
-     }
- 
-     public void checkValid(CharSequence literal) throws DatatypeException {
--        try {
--            Reader reader = new BufferedReader((new StringReader(
--                    "function(event){" + literal.toString() + "}")));
--            reader.mark(1);
--            try {
--                Context context = ContextFactory.getGlobal().enterContext();
--                context.setOptimizationLevel(0);
--                context.setLanguageVersion(Context.VERSION_1_6);
--                // -1 for lineno arg prevents Rhino from appending
--                // "(unnamed script#1)" to all error messages
--                context.compileReader(reader, null, -1, null);
--            } finally {
--                Context.exit();
--            }
--        } catch (IOException e) {
--            throw newDatatypeException(e.getMessage());
--        } catch (RhinoException e) {
--            throw newDatatypeException(e.getMessage());
--        }
-+//        try {
-+//            Reader reader = new BufferedReader((new StringReader(
-+//                    "function(event){" + literal.toString() + "}")));
-+//            reader.mark(1);
-+//            try {
-+//                Context context = ContextFactory.getGlobal().enterContext();
-+//                context.setOptimizationLevel(0);
-+//                context.setLanguageVersion(Context.VERSION_1_6);
-+//                // -1 for lineno arg prevents Rhino from appending
-+//                // "(unnamed script#1)" to all error messages
-+//                context.compileReader(reader, null, -1, null);
-+//            } finally {
-+//                Context.exit();
-+//            }
-+//        } catch (IOException e) {
-+//            throw newDatatypeException(e.getMessage());
-+//        } catch (RhinoException e) {
-+//            throw newDatatypeException(e.getMessage());
-+//        }
-     }
- 
-     @Override public String getName() {
-diff --git a/src/nu/validator/datatype/IriRef.java b/src/nu/validator/datatype/IriRef.java
-index e9d6fff..2b42415 100644
---- a/src/nu/validator/datatype/IriRef.java
-+++ b/src/nu/validator/datatype/IriRef.java
-@@ -29,18 +29,18 @@ import java.io.InputStream;
- import java.io.Reader;
- import java.io.StringReader;
- 
--import org.mozilla.javascript.Context;
--import org.mozilla.javascript.ContextFactory;
--import org.mozilla.javascript.RhinoException;
-+//import org.mozilla.javascript.Context;
-+//import org.mozilla.javascript.ContextFactory;
-+//import org.mozilla.javascript.RhinoException;
- import org.relaxng.datatype.DatatypeException;
- import nu.validator.io.DataUri;
- import nu.validator.io.DataUriException;
- import nu.validator.io.Utf8PercentDecodingReader;
- 
--import io.mola.galimatias.URL;
--import io.mola.galimatias.URLParsingSettings;
--import io.mola.galimatias.GalimatiasParseException;
--import io.mola.galimatias.StrictErrorHandler;
-+//import io.mola.galimatias.URL;
-+//import io.mola.galimatias.URLParsingSettings;
-+//import io.mola.galimatias.GalimatiasParseException;
-+//import io.mola.galimatias.StrictErrorHandler;
- 
- public class IriRef extends AbstractDatatype {
- 
-@@ -93,112 +93,112 @@ public class IriRef extends AbstractDatatype {
-     }
- 
-     public void checkValid(CharSequence literal) throws DatatypeException {
--        String messagePrologue = "";
--        int length = literal.length();
--        if (reportValue()) {
--            if (length < ELIDE_LIMIT) {
--                messagePrologue = "\u201c" + literal + "\u201d: ";
--            } else {
--                StringBuilder sb = new StringBuilder(ELIDE_LIMIT + 1);
--                sb.append(literal, 0, ELIDE_LIMIT / 2);
--                sb.append('\u2026');
--                sb.append(literal, length - ELIDE_LIMIT / 2, length);
--                messagePrologue = "\u201c" + sb.toString() + "\u201d: ";
--            }
--        }
--        if ("".equals(trimHtmlSpaces(literal.toString()))) {
--            throw newDatatypeException("Must be non-empty.");
--        }
--        URL url = null;
--        URLParsingSettings settings = URLParsingSettings.create().withErrorHandler(
--                StrictErrorHandler.getInstance());
--        boolean data = false;
--        try {
--            CharSequencePair pair = splitScheme(literal);
--            if (pair == null) {
--                // no scheme or scheme is private
--                if (isAbsolute()) {
--                    throw newDatatypeException("The string \u201c" + literal
--                            + "\u201d is not an absolute URL.");
--                } else {
--                    // in this case, doc's actual base URL isn't relevant,
--                    // so just use http://example.org/foo/bar as base
--                    url = URL.parse(settings,
--                            URL.parse("http://example.org/foo/bar"),
--                            literal.toString());
--                }
--            } else {
--                CharSequence scheme = pair.getHead();
--                CharSequence tail = pair.getTail();
--                if (isWellKnown(scheme)) {
--                    url = URL.parse(settings, literal.toString());
--                } else if ("javascript".contentEquals(scheme)) {
--                    // StringBuilder sb = new StringBuilder(2 +
--                    // literal.length());
--                    // sb.append("x-").append(literal);
--                    // iri = fac.construct(sb.toString());
--                    url = null; // Don't bother user with generic IRI syntax
--                    Reader reader = new BufferedReader(
--                            new Utf8PercentDecodingReader(new StringReader(
--                                    "function(event){" + tail.toString() + "}")));
--                    // XXX CharSequenceReader
--                    reader.mark(1);
--                    int c = reader.read();
--                    if (c != 0xFEFF) {
--                        reader.reset();
--                    }
--                    try {
--                        Context context = ContextFactory.getGlobal().enterContext();
--                        context.setOptimizationLevel(0);
--                        context.setLanguageVersion(Context.VERSION_1_6);
--                        // -1 for lineno arg prevents Rhino from appending
--                        // "(unnamed script#1)" to all error messages
--                        context.compileReader(reader, null, -1, null);
--                    } finally {
--                        Context.exit();
--                    }
--                } else if ("data".contentEquals(scheme)) {
--                    data = true;
--                    url = URL.parse(settings, literal.toString());
--                } else if (isHttpAlias(scheme)) {
--                    StringBuilder sb = new StringBuilder(5 + tail.length());
--                    sb.append("http:").append(tail);
--                    url = URL.parse(settings, sb.toString());
--                } else {
--                    StringBuilder sb = new StringBuilder(2 + literal.length());
--                    sb.append("x-").append(literal);
--                    url = URL.parse(settings, sb.toString());
--                }
--            }
--        } catch (GalimatiasParseException e) {
--            throw newDatatypeException(messagePrologue + e.getMessage() + ".");
--        } catch (IOException e) {
--            throw newDatatypeException(messagePrologue + e.getMessage());
--        } catch (RhinoException e) {
--            throw newDatatypeException(messagePrologue + e.getMessage());
--        }
--        if (url != null) {
--            if (data) {
--                try {
--                    DataUri dataUri = new DataUri(url);
--                    InputStream is = dataUri.getInputStream();
--                    while (is.read() >= 0) {
--                        // spin
--                    }
--                } catch (DataUriException e) {
--                    throw newDatatypeException(e.getIndex(), e.getHead(),
--                            e.getLiteral(), e.getTail());
--                } catch (IOException e) {
--                    String msg = e.getMessage();
--                    if (WARN
--                            && "Fragment is not allowed for data: URIs according to RFC 2397.".equals(msg)) {
--                        throw newDatatypeException(messagePrologue + msg, WARN);
--                    } else {
--                        throw newDatatypeException(messagePrologue + msg);
--                    }
--                }
--            }
--        }
-+//        String messagePrologue = "";
-+//        int length = literal.length();
-+//        if (reportValue()) {
-+//            if (length < ELIDE_LIMIT) {
-+//                messagePrologue = "\u201c" + literal + "\u201d: ";
-+//            } else {
-+//                StringBuilder sb = new StringBuilder(ELIDE_LIMIT + 1);
-+//                sb.append(literal, 0, ELIDE_LIMIT / 2);
-+//                sb.append('\u2026');
-+//                sb.append(literal, length - ELIDE_LIMIT / 2, length);
-+//                messagePrologue = "\u201c" + sb.toString() + "\u201d: ";
-+//            }
-+//        }
-+//        if ("".equals(trimHtmlSpaces(literal.toString()))) {
-+//            throw newDatatypeException("Must be non-empty.");
-+//        }
-+//        URL url = null;
-+//        URLParsingSettings settings = URLParsingSettings.create().withErrorHandler(
-+//                StrictErrorHandler.getInstance());
-+//        boolean data = false;
-+//        try {
-+//            CharSequencePair pair = splitScheme(literal);
-+//            if (pair == null) {
-+//                // no scheme or scheme is private
-+//                if (isAbsolute()) {
-+//                    throw newDatatypeException("The string \u201c" + literal
-+//                            + "\u201d is not an absolute URL.");
-+//                } else {
-+//                    // in this case, doc's actual base URL isn't relevant,
-+//                    // so just use http://example.org/foo/bar as base
-+//                    url = URL.parse(settings,
-+//                            URL.parse("http://example.org/foo/bar"),
-+//                            literal.toString());
-+//                }
-+//            } else {
-+//                CharSequence scheme = pair.getHead();
-+//                CharSequence tail = pair.getTail();
-+//                if (isWellKnown(scheme)) {
-+//                    url = URL.parse(settings, literal.toString());
-+//                } else if ("javascript".contentEquals(scheme)) {
-+//                    // StringBuilder sb = new StringBuilder(2 +
-+//                    // literal.length());
-+//                    // sb.append("x-").append(literal);
-+//                    // iri = fac.construct(sb.toString());
-+//                    url = null; // Don't bother user with generic IRI syntax
-+//                    Reader reader = new BufferedReader(
-+//                            new Utf8PercentDecodingReader(new StringReader(
-+//                                    "function(event){" + tail.toString() + "}")));
-+//                    // XXX CharSequenceReader
-+//                    reader.mark(1);
-+//                    int c = reader.read();
-+//                    if (c != 0xFEFF) {
-+//                        reader.reset();
-+//                    }
-+//                    try {
-+//                        Context context = ContextFactory.getGlobal().enterContext();
-+//                        context.setOptimizationLevel(0);
-+//                        context.setLanguageVersion(Context.VERSION_1_6);
-+//                        // -1 for lineno arg prevents Rhino from appending
-+//                        // "(unnamed script#1)" to all error messages
-+//                        context.compileReader(reader, null, -1, null);
-+//                    } finally {
-+//                        Context.exit();
-+//                    }
-+//                } else if ("data".contentEquals(scheme)) {
-+//                    data = true;
-+//                    url = URL.parse(settings, literal.toString());
-+//                } else if (isHttpAlias(scheme)) {
-+//                    StringBuilder sb = new StringBuilder(5 + tail.length());
-+//                    sb.append("http:").append(tail);
-+//                    url = URL.parse(settings, sb.toString());
-+//                } else {
-+//                    StringBuilder sb = new StringBuilder(2 + literal.length());
-+//                    sb.append("x-").append(literal);
-+//                    url = URL.parse(settings, sb.toString());
-+//                }
-+//            }
-+//        } catch (GalimatiasParseException e) {
-+//            throw newDatatypeException(messagePrologue + e.getMessage() + ".");
-+//        } catch (IOException e) {
-+//            throw newDatatypeException(messagePrologue + e.getMessage());
-+//        } catch (RhinoException e) {
-+//            throw newDatatypeException(messagePrologue + e.getMessage());
-+//        }
-+//        if (url != null) {
-+//            if (data) {
-+//                try {
-+//                    DataUri dataUri = new DataUri(url);
-+//                    InputStream is = dataUri.getInputStream();
-+//                    while (is.read() >= 0) {
-+//                        // spin
-+//                    }
-+//                } catch (DataUriException e) {
-+//                    throw newDatatypeException(e.getIndex(), e.getHead(),
-+//                            e.getLiteral(), e.getTail());
-+//                } catch (IOException e) {
-+//                    String msg = e.getMessage();
-+//                    if (WARN
-+//                            && "Fragment is not allowed for data: URIs according to RFC 2397.".equals(msg)) {
-+//                        throw newDatatypeException(messagePrologue + msg, WARN);
-+//                    } else {
-+//                        throw newDatatypeException(messagePrologue + msg);
-+//                    }
-+//                }
-+//            }
-+//        }
-     }
- 
-     private final boolean isHttpAlias(CharSequence scheme) {
-diff --git a/src/nu/validator/datatype/Language.java b/src/nu/validator/datatype/Language.java
-index b61913d..24fb4a4 100644
---- a/src/nu/validator/datatype/Language.java
-+++ b/src/nu/validator/datatype/Language.java
-@@ -227,7 +227,7 @@ public final class Language extends AbstractDatatype {
-             checkPrivateUse(i, subtags);
-             return;
-         }
--        if (subtag.length() == 4 & isLowerCaseAlpha(subtag)) {
-+        if (subtag.length() == 4 && isLowerCaseAlpha(subtag)) {
-             if (!isScript(subtag)) {
-                 throw newDatatypeException("Bad script subtag.");
-             }
-diff --git a/src/nu/validator/datatype/Pattern.java b/src/nu/validator/datatype/Pattern.java
-index aa10750..67766c7 100644
---- a/src/nu/validator/datatype/Pattern.java
-+++ b/src/nu/validator/datatype/Pattern.java
-@@ -22,10 +22,10 @@
- 
- package nu.validator.datatype;
- 
--import org.mozilla.javascript.Context;
--import org.mozilla.javascript.ContextFactory;
--import org.mozilla.javascript.EcmaError;
--import org.mozilla.javascript.regexp.RegExpImpl;
-+//import org.mozilla.javascript.Context;
-+//import org.mozilla.javascript.ContextFactory;
-+//import org.mozilla.javascript.EcmaError;
-+//import org.mozilla.javascript.regexp.RegExpImpl;
- import org.relaxng.datatype.DatatypeException;
- 
- /**
-@@ -58,18 +58,18 @@ public final class Pattern extends AbstractDatatype {
-     public void checkValid(CharSequence literal)
-             throws DatatypeException {
-         // TODO find out what kind of thread concurrency guarantees are made
--        ContextFactory cf = new ContextFactory();
--        Context cx = cf.enterContext();
--        cx.setOptimizationLevel(0);
--        RegExpImpl rei = new RegExpImpl();
--        String anchoredRegex = "^(?:" + literal + ")$";
--        try {
--            rei.compileRegExp(cx, anchoredRegex, "");
--        } catch (EcmaError ee) {
--            throw newDatatypeException(ee.getErrorMessage());
--        } finally {
--            Context.exit();
--        }
-+//        ContextFactory cf = new ContextFactory();
-+//        Context cx = cf.enterContext();
-+//        cx.setOptimizationLevel(0);
-+//        RegExpImpl rei = new RegExpImpl();
-+//        String anchoredRegex = "^(?:" + literal + ")$";
-+//        try {
-+//            rei.compileRegExp(cx, anchoredRegex, "");
-+//        } catch (EcmaError ee) {
-+//            throw newDatatypeException(ee.getErrorMessage());
-+//        } finally {
-+//            Context.exit();
-+//        }
-     }
- 
-     @Override
-diff --git a/src/nu/validator/datatype/SourceSizeList.java b/src/nu/validator/datatype/SourceSizeList.java
-index 1c61f81..e3bd20a 100644
---- a/src/nu/validator/datatype/SourceSizeList.java
-+++ b/src/nu/validator/datatype/SourceSizeList.java
-@@ -26,7 +26,6 @@ import java.text.ParseException;
- import java.util.LinkedHashSet;
- import java.util.Set;
- 
--import nu.validator.datatype.tools.CssParser;
- import org.relaxng.datatype.DatatypeException;
- 
- public class SourceSizeList extends AbstractDatatype {
-@@ -41,8 +40,6 @@ public class SourceSizeList extends AbstractDatatype {
- 
-     private static final StringBuilder VALID_UNITS = new StringBuilder();
- 
--    private static CssParser cssParser = new CssParser();
--
-     static {
-         /* font-relative lengths */
-         LENGTH_UNITS.add("em");
-@@ -119,18 +116,6 @@ public class SourceSizeList extends AbstractDatatype {
-             errEmpty(isFirst, isLast, extract);
-             return;
-         }
--        try {
--            cssParser.tokenize(unparsedSize.toString());
--            if ('(' == unparsedSize.codePointAt(0)) {
--                cssParser.parseARule("@media " + unparsedSize.toString()
--                        + " {}");
--            } else {
--                cssParser.parseARule(".foo { width: " + unparsedSize.toString()
--                        + " }");
--            }
--        } catch (ParseException e) {
--            errCssParseError(e.getMessage(), unparsedSize, extract);
--        }
-         if (')' == unparsedSize.charAt(unparsedSize.length() - 1)) {
-             checkCalc(unparsedSize, extract, isLast);
-             return;
-diff --git a/src/nu/validator/datatype/tools/CssParser.java b/src/nu/validator/datatype/tools/CssParser.java
-deleted file mode 100644
-index 9daa67f..0000000
---- a/src/nu/validator/datatype/tools/CssParser.java
-+++ /dev/null
-@@ -1,88 +0,0 @@
--/*
-- * Copyright (c) 2015 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.datatype.tools;
--
--import java.io.BufferedReader;
--import java.io.IOException;
--import java.io.InputStreamReader;
--import java.text.ParseException;
--
--import org.mozilla.javascript.Context;
--import org.mozilla.javascript.ContextFactory;
--import org.mozilla.javascript.Function;
--import org.mozilla.javascript.JavaScriptException;
--import org.mozilla.javascript.ScriptableObject;
--
--public class CssParser {
--
--    private static ScriptableObject scope;
--
--    private static Function tokenizer;
--
--    private static Function ruleParser;
--
--    static {
--        try {
--            BufferedReader br = new BufferedReader(
--                    new InputStreamReader(
--                            CssParser.class.getClassLoader().getResourceAsStream(
--                                    "nu/validator/localentities/files/parse-css-js")));
--            br.mark(1);
--            Context context = ContextFactory.getGlobal().enterContext();
--            context.setOptimizationLevel(1);
--            context.setLanguageVersion(Context.VERSION_1_6);
--            scope = context.initStandardObjects();
--            context.evaluateReader(scope, br, null, -1, null);
--            tokenizer = (Function) scope.get("tokenize", scope);
--            ruleParser = (Function) scope.get("parseARule", scope);
--        } catch (IOException e) {
--        }
--    }
--
--    public String[] tokenize(CharSequence cs) throws ParseException {
--        try {
--            Context context = ContextFactory.getGlobal().enterContext();
--            context.setOptimizationLevel(0);
--            context.setLanguageVersion(Context.VERSION_1_6);
--            return (String[]) Context.jsToJava(
--                    tokenizer.call(context, scope, scope, new Object[] { cs }),
--                    String[].class);
--        } catch (JavaScriptException e) {
--            throw new ParseException(e.details(), -1);
--        }
--    }
--
--    public String parseARule(CharSequence cs) throws ParseException {
--        try {
--            Context context = ContextFactory.getGlobal().enterContext();
--            context.setOptimizationLevel(0);
--            context.setLanguageVersion(Context.VERSION_1_6);
--            return (String) Context.jsToJava(ruleParser.call(context, scope, scope,
--                    new Object[] { tokenizer.call(context, scope, scope,
--                            new Object[] { cs }) }), String.class);
--        } catch (JavaScriptException e) {
--            throw new ParseException(e.details(), -1);
--        }
--    }
--
--}
-diff --git a/src/nu/validator/io/DataUri.java b/src/nu/validator/io/DataUri.java
-index 74811a9..9677758 100644
---- a/src/nu/validator/io/DataUri.java
-+++ b/src/nu/validator/io/DataUri.java
-@@ -22,13 +22,14 @@
- 
- package nu.validator.io;
- 
-+import com.hp.hpl.jena.iri.IRIFactory;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.StringReader;
- import java.net.MalformedURLException;
- 
--import io.mola.galimatias.URL;
--import io.mola.galimatias.GalimatiasParseException;
-+//import io.mola.galimatias.URL;
-+//import io.mola.galimatias.GalimatiasParseException;
- 
- public class DataUri {
- 
-@@ -54,17 +55,17 @@ public class DataUri {
-      * @throws MalformedURLException
-      * @throws IOException
-      */
--    protected void init(URL url) throws IOException, MalformedURLException {
--        if (!url.scheme().equals("data")) {
-+    protected void init(com.hp.hpl.jena.iri.IRI url) throws IOException, MalformedURLException {
-+        if (!url.getScheme().equals("data")) {
-             throw new IllegalArgumentException("The input did not start with data:.");
-         }
- 
--        if (url.fragment() != null) {
-+        if (url.getRawFragment() != null) {
-             throw new MalformedURLException(
-                     "Fragment is not allowed for data: URIs according to RFC 2397.");
-         }
- 
--        InputStream is = new PercentDecodingReaderInputStream(new StringReader(url.schemeData()));
-+        InputStream is = new PercentDecodingReaderInputStream(new StringReader(url.getRawPath()));
-         StringBuilder sb = new StringBuilder();
-         State state = State.AT_START;
-         int i = 0; // string counter
-@@ -254,11 +255,15 @@ public class DataUri {
-     }
- 
-     public DataUri(String url) throws IOException {
--        try {
--            init(URL.parse(url));
--        } catch (GalimatiasParseException e) {
--            throw new MalformedURLException(e.getMessage());
--        }
-+        
-+        IRIFactory fac = new IRIFactory();
-+        fac.shouldViolation(true, false);
-+        fac.securityViolation(true, false);
-+        fac.dnsViolation(true, false);
-+        fac.mintingViolation(false, false);
-+        fac.useSpecificationIRI(true);
-+        init(fac.construct(url));
-+        
-     }
- 
-     /**
-@@ -266,7 +271,7 @@ public class DataUri {
-      * @throws MalformedURLException
-      * @throws IOException
-      */
--    public DataUri(URL url) throws IOException, MalformedURLException {
-+    public DataUri(com.hp.hpl.jena.iri.IRI url) throws IOException, MalformedURLException {
-         init(url);
-     }
- 
-diff --git a/src/nu/validator/localentities/LocalCacheEntityResolver.java b/src/nu/validator/localentities/LocalCacheEntityResolver.java
-index 8b6ac69..18de3b8 100644
---- a/src/nu/validator/localentities/LocalCacheEntityResolver.java
-+++ b/src/nu/validator/localentities/LocalCacheEntityResolver.java
-@@ -4,6 +4,7 @@ import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
-+import java.net.URL;
- import java.util.HashMap;
- import java.util.Map;
- 
-@@ -41,7 +42,7 @@ public class LocalCacheEntityResolver implements EntityResolver {
-     }
- 
-     public static InputStream getPresetsAsStream() {
--        return LOADER.getResourceAsStream("nu/validator/localentities/files/presets");
-+        return LOADER.getResourceAsStream("nu/validator/localentities/presets");
-     }
- 
-     public static InputStream getHtml5SpecAsStream() {
-@@ -53,18 +54,27 @@ public class LocalCacheEntityResolver implements EntityResolver {
-     private boolean allowRnc = false;
- 
-     /**
-+     * The map must be safe for concurrent reads.
-+     * 
-+     * @param pathMap
-      * @param delegate
-      */
-     public LocalCacheEntityResolver(EntityResolver delegate) {
-         this.delegate = delegate;
-     }
- 
-+    public static URL getResource(String systemId) {
-+        String path = PATH_MAP.get(systemId);
-+        return path != null ? LOADER.getResource(path) : null;
-+    }
-+
-     /**
-      * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String,
-      *      java.lang.String)
-      */
-     public InputSource resolveEntity(String publicId, String systemId)
-             throws SAXException, IOException {
-+        long a = System.currentTimeMillis();
-         String path = PATH_MAP.get(systemId);
-         if (path != null) {
-             InputStream stream = LOADER.getResourceAsStream(path);
-@@ -89,6 +99,7 @@ public class LocalCacheEntityResolver implements EntityResolver {
-                 return is;
-             }
-         }
-+        System.out.println("resolve :" + publicId +" " + systemId); 
-         return delegate.resolveEntity(publicId, systemId);
-     }
- 
-@@ -106,4 +117,4 @@ public class LocalCacheEntityResolver implements EntityResolver {
-     public void setAllowRnc(boolean allowRnc) {
-         this.allowRnc = allowRnc;
-     }
--}
-+}
-\ No newline at end of file
-diff --git a/src/nu/validator/localentities/presets b/src/nu/validator/localentities/presets
-new file mode 100644
-index 0000000..7966803
---- /dev/null
-+++ b/src/nu/validator/localentities/presets
-@@ -0,0 +1,10 @@
-+-1	-	HTML5 + SVG 1.1 + MathML 3.0	http://s.validator.nu/html5.rnc http://s.validator.nu/html5/assertions.sch http://c.validator.nu/all/
-+-1	-	HTML5 + SVG 1.1 + MathML 3.0 + ITS 2.0	http://s.validator.nu/html5-its.rnc http://s.validator.nu/html5/assertions.sch http://c.validator.nu/all/
-+3	-	HTML5 + SVG 1.1 + MathML 3.0 + RDFa Lite 1.1	http://s.validator.nu/html5-rdfalite.rnc http://s.validator.nu/html5/assertions.sch http://c.validator.nu/all/
-+2	-	HTML 4.01 Strict + IRI / XHTML 1.0 Strict + IRI	http://s.validator.nu/xhtml10/xhtml-strict.rnc http://s.validator.nu/html5/assertions.sch http://c.validator.nu/all-html4/
-+1	-	HTML 4.01 Transitional + IRI / XHTML 1.0 Transitional + IRI	http://s.validator.nu/xhtml10/xhtml-transitional.rnc http://s.validator.nu/html5/assertions.sch http://c.validator.nu/all-html4/
-+-1	-	HTML 4.01 Frameset + IRI / XHTML 1.0 Frameset + IRI	http://s.validator.nu/xhtml10/xhtml-frameset.rnc http://s.validator.nu/html5/assertions.sch http://c.validator.nu/all-html4/
-+-1	-	XHTML5 + SVG 1.1 + MathML 3.0	http://s.validator.nu/xhtml5.rnc http://s.validator.nu/html5/assertions.sch http://c.validator.nu/all/
-+7	http://www.w3.org/1999/xhtml	XHTML5 + SVG 1.1 + MathML 3.0 + RDFa Lite 1.1	http://s.validator.nu/xhtml5-rdfalite.rnc http://s.validator.nu/html5/assertions.sch http://c.validator.nu/all/
-+-1	-	XHTML 1.0 Strict + IRI + Ruby + SVG 1.1 + MathML 3.0	http://s.validator.nu/xhtml1-ruby-rdf-svg-mathml.rnc http://s.validator.nu/html5/assertions.sch http://c.validator.nu/all-html4/
-+-1	http://www.w3.org/2000/svg	SVG 1.1 + IRI + XHTML5 + MathML 3.0	http://s.validator.nu/svg-xhtml5-rdf-mathml.rnc http://s.validator.nu/html5/assertions.sch http://c.validator.nu/all/
-\ No newline at end of file
-diff --git a/src/nu/validator/messages/BufferingRootNamespaceSniffer.java b/src/nu/validator/messages/BufferingRootNamespaceSniffer.java
-new file mode 100644
-index 0000000..13e5b07
---- /dev/null
-+++ b/src/nu/validator/messages/BufferingRootNamespaceSniffer.java
-@@ -0,0 +1,172 @@
-+/*
-+ * Copyright (c) 2006 Henri Sivonen
-+ *
-+ * 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.
-+ */
-+
-+package nu.validator.messages;
-+
-+import java.util.Iterator;
-+import java.util.LinkedList;
-+import java.util.List;
-+import org.xml.sax.Attributes;
-+import org.xml.sax.ContentHandler;
-+import org.xml.sax.Locator;
-+import org.xml.sax.SAXException;
-+
-+public class BufferingRootNamespaceSniffer implements ContentHandler {
-+
-+    private ContentHandler ch = null;
-+
-+    private Locator locator = null;
-+    
-+    private List<String[]> namespaces = new LinkedList<String[]>();
-+    
-+    private ValidationTransaction vst;
-+    
-+    public BufferingRootNamespaceSniffer(ValidationTransaction vst) {
-+        super();
-+        this.vst = vst;
-+    }
-+
-+    public void setContentHandler(ContentHandler contentHandler) throws SAXException {
-+        this.ch = contentHandler;
-+        if (locator != null) {
-+            ch.setDocumentLocator(locator);
-+        }
-+        ch.startDocument();
-+        for (Iterator<String[]> iter = namespaces.iterator(); iter.hasNext();) {
-+            String[] element = iter.next();
-+            ch.startPrefixMapping(element[0], element[1]);
-+        }
-+    }
-+    
-+    /**
-+     * @see org.xml.sax.ContentHandler#characters(char[], int, int)
-+     */
-+    public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
-+        if (ch != null) {
-+            ch.characters(arg0, arg1, arg2);
-+        }
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#endDocument()
-+     */
-+    public void endDocument() throws SAXException {
-+        if (ch != null) {
-+            ch.endDocument();
-+        }
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#endElement(java.lang.String,
-+     *      java.lang.String, java.lang.String)
-+     */
-+    public void endElement(String arg0, String arg1, String arg2)
-+            throws SAXException {
-+        if (ch != null) {
-+            ch.endElement(arg0, arg1, arg2);
-+        }
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
-+     */
-+    public void endPrefixMapping(String arg0) throws SAXException {
-+        if (ch != null) {
-+            ch.endPrefixMapping(arg0);
-+        }
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
-+     */
-+    public void ignorableWhitespace(char[] arg0, int arg1, int arg2)
-+            throws SAXException {
-+        if (ch != null) {
-+            ch.ignorableWhitespace(arg0, arg1, arg2);
-+        }
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String,
-+     *      java.lang.String)
-+     */
-+    public void processingInstruction(String arg0, String arg1)
-+            throws SAXException {
-+        if (ch != null) {
-+            ch.processingInstruction(arg0, arg1);
-+        }
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
-+     */
-+    public void setDocumentLocator(Locator arg0) {
-+        locator = arg0;
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
-+     */
-+    public void skippedEntity(String arg0) throws SAXException {
-+        if (ch != null) {
-+            ch.skippedEntity(arg0);
-+        }
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#startDocument()
-+     */
-+    public void startDocument() throws SAXException {
-+
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#startElement(java.lang.String,
-+     *      java.lang.String, java.lang.String, org.xml.sax.Attributes)
-+     */
-+    public void startElement(String arg0, String arg1, String arg2,
-+            Attributes arg3) throws SAXException {
-+        if (ch != null) {
-+            ch.startElement(arg0, arg1, arg2, arg3);
-+        } else {
-+            vst.rootNamespace(arg0, locator);
-+            ch.startElement(arg0, arg1, arg2, arg3);
-+        }
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String,
-+     *      java.lang.String)
-+     */
-+    public void startPrefixMapping(String arg0, String arg1)
-+            throws SAXException {
-+        if (ch != null) {
-+            ch.startPrefixMapping(arg0, arg1);
-+        } else {
-+            String[] arr = new String[2];
-+            arr[0] = arg0;
-+            arr[1] = arg1;
-+            namespaces.add(arr);
-+        }
-+    }
-+
-+}
-diff --git a/src/nu/validator/messages/RootNamespaceSniffer.java b/src/nu/validator/messages/RootNamespaceSniffer.java
-new file mode 100644
-index 0000000..1981475
---- /dev/null
-+++ b/src/nu/validator/messages/RootNamespaceSniffer.java
-@@ -0,0 +1,121 @@
-+/*
-+ * Copyright (c) 2006 Henri Sivonen
-+ *
-+ * 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.
-+ */
-+
-+package nu.validator.messages;
-+
-+import org.xml.sax.Attributes;
-+import org.xml.sax.ContentHandler;
-+import org.xml.sax.Locator;
-+import org.xml.sax.SAXException;
-+
-+public class RootNamespaceSniffer implements ContentHandler {
-+
-+    private ValidationTransaction vst;
-+    private ContentHandler ch;
-+    private Locator locator;
-+
-+    public RootNamespaceSniffer(ValidationTransaction vst, ContentHandler ch) {
-+        super();
-+        this.vst = vst;
-+        this.ch = ch;
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#characters(char[], int, int)
-+     */
-+    public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
-+        ch.characters(arg0, arg1, arg2);
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#endDocument()
-+     */
-+    public void endDocument() throws SAXException {
-+        ch.endDocument();
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
-+     */
-+    public void endElement(String arg0, String arg1, String arg2) throws SAXException {
-+        ch.endElement(arg0, arg1, arg2);
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
-+     */
-+    public void endPrefixMapping(String arg0) throws SAXException {
-+        ch.endPrefixMapping(arg0);
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
-+     */
-+    public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
-+        ch.ignorableWhitespace(arg0, arg1, arg2);
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
-+     */
-+    public void processingInstruction(String arg0, String arg1) throws SAXException {
-+        ch.processingInstruction(arg0, arg1);
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
-+     */
-+    public void setDocumentLocator(Locator arg0) {
-+        this.locator = arg0;
-+        ch.setDocumentLocator(arg0);
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
-+     */
-+    public void skippedEntity(String arg0) throws SAXException {
-+        ch.skippedEntity(arg0);
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#startDocument()
-+     */
-+    public void startDocument() throws SAXException {
-+        ch.startDocument();
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
-+     */
-+    public void startElement(String arg0, String arg1, String arg2, Attributes arg3) throws SAXException {
-+        vst.rootNamespace(arg0, locator);
-+        ch.startElement(arg0, arg1, arg2, arg3);
-+    }
-+
-+    /**
-+     * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
-+     */
-+    public void startPrefixMapping(String arg0, String arg1) throws SAXException {
-+        ch.startPrefixMapping(arg0, arg1);
-+    }
-+
-+}
-diff --git a/src/nu/validator/messages/ValidationTransaction.java b/src/nu/validator/messages/ValidationTransaction.java
-new file mode 100644
-index 0000000..9b60092
---- /dev/null
-+++ b/src/nu/validator/messages/ValidationTransaction.java
-@@ -0,0 +1,466 @@
-+package nu.validator.messages;
-+
-+import com.thaiopensource.relaxng.impl.CombineValidator;
-+import com.thaiopensource.util.PropertyMap;
-+import com.thaiopensource.validate.IncorrectSchemaException;
-+import com.thaiopensource.validate.Schema;
-+import com.thaiopensource.validate.SchemaReader;
-+import com.thaiopensource.validate.SchemaResolver;
-+import com.thaiopensource.validate.Validator;
-+import com.thaiopensource.validate.auto.AutoSchemaReader;
-+import com.thaiopensource.validate.prop.wrap.WrapProperty;
-+import com.thaiopensource.validate.rng.CompactSchemaReader;
-+import java.io.IOException;
-+import java.lang.ref.SoftReference;
-+import java.util.Arrays;
-+import java.util.HashMap;
-+import java.util.Map;
-+import java.util.logging.Level;
-+import java.util.logging.Logger;
-+import java.util.regex.Pattern;
-+import nu.validator.checker.XmlPiChecker;
-+import nu.validator.checker.jing.CheckerSchema;
-+import nu.validator.htmlparser.common.DocumentMode;
-+import nu.validator.htmlparser.common.DocumentModeHandler;
-+import nu.validator.htmlparser.sax.HtmlParser;
-+import nu.validator.localentities.LocalCacheEntityResolver;
-+import nu.validator.spec.Spec;
-+import nu.validator.xml.TypedInputSource;
-+import org.xml.sax.ContentHandler;
-+import org.xml.sax.EntityResolver;
-+import org.xml.sax.Locator;
-+import org.xml.sax.SAXException;
-+import org.xml.sax.SAXParseException;
-+import org.xml.sax.XMLReader;
-+import org.xml.sax.ext.LexicalHandler;
-+
-+/**
-+ * This class code was mainly extracted from the original class {@link VerifierServletTransaction}.
-+ *
-+ * @author hsivonen, mfukala@netbeans.org
-+ */
-+public class ValidationTransaction implements DocumentModeHandler, SchemaResolver {
-+    private static final Logger LOGGER = Logger.getLogger(ValidationTransaction.class.getCanonicalName());
-+
-+    // XXX SVG!!!
-+    private static final String[] KNOWN_CONTENT_TYPES = {
-+        "application/atom+xml", "application/docbook+xml",
-+        "application/xhtml+xml", "application/xv+xml", "image/svg+xml"};
-+    private static final String[] NAMESPACES_FOR_KNOWN_CONTENT_TYPES = {
-+        "http://www.w3.org/2005/Atom", "http://docbook.org/ns/docbook",
-+        "http://www.w3.org/1999/xhtml", "http://www.w3.org/1999/xhtml",
-+        "http://www.w3.org/2000/svg"};
-+    protected static final String[] ALL_CHECKERS = {
-+        "http://c.validator.nu/table/", "http://c.validator.nu/nfc/",
-+        "http://c.validator.nu/text-content/",
-+        "http://c.validator.nu/unchecked/",
-+        "http://c.validator.nu/usemap/", "http://c.validator.nu/obsolete/",
-+        "http://c.validator.nu/xml-pi/"};
-+    private static final String[] ALL_CHECKERS_HTML4 = {
-+        "http://c.validator.nu/table/", "http://c.validator.nu/nfc/",
-+        "http://c.validator.nu/unchecked/", "http://c.validator.nu/usemap/"};
-+    
-+    protected BufferingRootNamespaceSniffer bufferingRootNamespaceSniffer = null;
-+    protected boolean rootNamespaceSeen = false;
-+    protected String contentType = null;
-+    
-+    protected static int[] presetDoctypes;
-+    protected static String[] presetLabels;
-+    protected static String[] presetUrls;
-+    protected static String[] presetNamespaces;
-+    
-+    protected MessageEmitterAdapter errorHandler;
-+    protected static String[] preloadedSchemaUrls;
-+    protected static Schema[] preloadedSchemas;
-+    
-+    private Map<String, Validator> loadedValidatorUrls = new HashMap<String, Validator>();
-+    
-+    protected Validator validator = null;
-+    protected LocalCacheEntityResolver entityResolver;
-+    
-+    private static final Pattern SPACE = Pattern.compile("\\s+");
-+    protected static final int HTML5_SCHEMA = 3;
-+    protected static final int XHTML1STRICT_SCHEMA = 2;
-+    protected static final int XHTML1FRAMESET_SCHEMA = 4;
-+    protected static final int XHTML1TRANSITIONAL_SCHEMA = 1;
-+    protected static final int XHTML5_SCHEMA = 7;
-+    
-+    public HtmlParser htmlParser = null;
-+    protected PropertyMap jingPropertyMap;
-+    protected static Spec html5spec;
-+    
-+    protected XMLReader reader;
-+    protected LexicalHandler lexicalHandler;
-+    
-+    public void rootNamespace(String namespace, Locator locator) throws SAXException {
-+        if (validator == null) {
-+            int index = -1;
-+            for (int i = 0; i < presetNamespaces.length; i++) {
-+                if (namespace.equals(presetNamespaces[i])) {
-+                    index = i;
-+                    break;
-+                }
-+            }
-+            if (index == -1) {
-+                String message = "Cannot find preset schema for namespace: \u201C"
-+                        + namespace + "\u201D.";
-+                SAXException se = new SAXException(message);
-+                errorHandler.schemaError(se);
-+                throw se;
-+            }
-+            String label = presetLabels[index];
-+            String urls = presetUrls[index];
-+            errorHandler.info("Using the preset for " + label
-+                    + " based on the root namespace " + namespace);
-+            try {
-+                validator = validatorByUrls(urls);
-+            } catch (IOException ioe) {
-+                // At this point the schema comes from memory.
-+                throw new RuntimeException(ioe);
-+            } catch (IncorrectSchemaException e) {
-+                // At this point the schema comes from memory.
-+                throw new RuntimeException(e);
-+            }
-+            if (bufferingRootNamespaceSniffer == null) {
-+                throw new RuntimeException(
-+                        "Bug! bufferingRootNamespaceSniffer was null.");
-+            }
-+            bufferingRootNamespaceSniffer.setContentHandler(validator.getContentHandler());
-+        }
-+
-+        if (!rootNamespaceSeen) {
-+            rootNamespaceSeen = true;
-+            if (contentType != null) {
-+                int i;
-+                if ((i = Arrays.binarySearch(KNOWN_CONTENT_TYPES, contentType)) > -1) {
-+                    if (!NAMESPACES_FOR_KNOWN_CONTENT_TYPES[i].equals(namespace)) {
-+                        String message = "".equals(namespace) ? "\u201C"
-+                                + contentType
-+                                + "\u201D is not an appropriate Content-Type for a document whose root element is not in a namespace."
-+                                : "\u201C"
-+                                + contentType
-+                                + "\u201D is not an appropriate Content-Type for a document whose root namespace is \u201C"
-+                                + namespace + "\u201D.";
-+                        SAXParseException spe = new SAXParseException(message,
-+                                locator);
-+                        errorHandler.warning(spe);
-+                    }
-+                }
-+            }
-+        }
-+    }
-+    
-+    @Override
-+    public void documentMode(DocumentMode mode, String publicIdentifier,
-+            String systemIdentifier, boolean html4SpecificAdditionalErrorChecks)
-+            throws SAXException {
-+        if (validator == null) {
-+            try {
-+                if ("-//W3C//DTD XHTML 1.0 Transitional//EN".equals(publicIdentifier)) {
-+                    errorHandler.info("XHTML 1.0 Transitional doctype seen. Appendix C is not supported. Proceeding anyway for your convenience. The parser is still an HTML parser, so namespace processing is not performed and \u201Cxml:*\u201D attributes are not supported. Using the schema for "
-+                            + getPresetLabel(XHTML1TRANSITIONAL_SCHEMA)
-+                            + "."
-+                            + (html4SpecificAdditionalErrorChecks ? " HTML4-specific tokenization errors are enabled."
-+                            : ""));
-+                    validator = validatorByDoctype(XHTML1TRANSITIONAL_SCHEMA);
-+                } else if ("-//W3C//DTD XHTML 1.0 Strict//EN".equals(publicIdentifier)) {
-+                    errorHandler.info("XHTML 1.0 Strict doctype seen. Appendix C is not supported. Proceeding anyway for your convenience. The parser is still an HTML parser, so namespace processing is not performed and \u201Cxml:*\u201D attributes are not supported. Using the schema for "
-+                            + getPresetLabel(XHTML1STRICT_SCHEMA)
-+                            + "."
-+                            + (html4SpecificAdditionalErrorChecks ? " HTML4-specific tokenization errors are enabled."
-+                            : ""));
-+                    validator = validatorByDoctype(XHTML1STRICT_SCHEMA);
-+                } else if ("-//W3C//DTD HTML 4.01 Transitional//EN".equals(publicIdentifier)) {
-+                    errorHandler.info("HTML 4.01 Transitional doctype seen. Using the schema for "
-+                            + getPresetLabel(XHTML1TRANSITIONAL_SCHEMA)
-+                            + "."
-+                            + (html4SpecificAdditionalErrorChecks ? ""
-+                            : " HTML4-specific tokenization errors are not enabled."));
-+                    validator = validatorByDoctype(XHTML1TRANSITIONAL_SCHEMA);
-+                } else if ("-//W3C//DTD HTML 4.01//EN".equals(publicIdentifier)) {
-+                    errorHandler.info("HTML 4.01 Strict doctype seen. Using the schema for "
-+                            + getPresetLabel(XHTML1STRICT_SCHEMA)
-+                            + "."
-+                            + (html4SpecificAdditionalErrorChecks ? ""
-+                            : " HTML4-specific tokenization errors are not enabled."));
-+                    validator = validatorByDoctype(XHTML1STRICT_SCHEMA);
-+                } else if ("-//W3C//DTD HTML 4.0 Transitional//EN".equals(publicIdentifier)) {
-+                    errorHandler.info("Legacy HTML 4.0 Transitional doctype seen.  Please consider using HTML 4.01 Transitional instead. Proceeding anyway for your convenience with the schema for "
-+                            + getPresetLabel(XHTML1TRANSITIONAL_SCHEMA)
-+                            + "."
-+                            + (html4SpecificAdditionalErrorChecks ? ""
-+                            : " HTML4-specific tokenization errors are not enabled."));
-+                    validator = validatorByDoctype(XHTML1TRANSITIONAL_SCHEMA);
-+                } else if ("-//W3C//DTD HTML 4.0//EN".equals(publicIdentifier)) {
-+                    errorHandler.info("Legacy HTML 4.0 Strict doctype seen. Please consider using HTML 4.01 instead. Proceeding anyway for your convenience with the schema for "
-+                            + getPresetLabel(XHTML1STRICT_SCHEMA)
-+                            + "."
-+                            + (html4SpecificAdditionalErrorChecks ? ""
-+                            : " HTML4-specific tokenization errors are not enabled."));
-+                    validator = validatorByDoctype(XHTML1STRICT_SCHEMA);
-+                } else {
-+                    errorHandler.info("Using the schema for "
-+                            + getPresetLabel(HTML5_SCHEMA)
-+                            + "."
-+                            + (html4SpecificAdditionalErrorChecks ? " HTML4-specific tokenization errors are enabled."
-+                            : ""));
-+                    validator = validatorByDoctype(HTML5_SCHEMA);
-+                }
-+            } catch (IOException ioe) {
-+                // At this point the schema comes from memory.
-+                throw new RuntimeException(ioe);
-+            } catch (IncorrectSchemaException e) {
-+                // At this point the schema comes from memory.
-+                throw new RuntimeException(e);
-+            }
-+            ContentHandler ch = validator.getContentHandler();
-+            ch.setDocumentLocator(htmlParser.getDocumentLocator());
-+            ch.startDocument();
-+            reader.setContentHandler(ch);
-+        } else {
-+            if (html4SpecificAdditionalErrorChecks) {
-+                errorHandler.info("HTML4-specific tokenization errors are enabled.");
-+            }
-+        }
-+    }
-+
-+    public Schema resolveSchema(String url, PropertyMap options)
-+            throws SAXException, IOException, IncorrectSchemaException {
-+        int i = Arrays.binarySearch(preloadedSchemaUrls, url);
-+        if (i > -1) {
-+            Schema rv = preloadedSchemas[i];
-+            if (options.contains(WrapProperty.ATTRIBUTE_OWNER)) {
-+                if(rv instanceof ValidationTransaction.ProxySchema && ((ValidationTransaction.ProxySchema)rv).getWrappedSchema() instanceof CheckerSchema) {
-+                    errorHandler.error(new SAXParseException(
-+                            "A non-schema checker cannot be used as an attribute schema.",
-+                            null, url, -1, -1));
-+                    throw new IncorrectSchemaException();
-+                } else {
-+                    // ugly fall through
-+                }
-+            } else {
-+                return rv;
-+            }
-+        }
-+
-+        //this code line should not normally be encountered since the necessary
-+        //schemas have been preloaded
-+        LOGGER.log(Level.INFO, "Going to create a non preloaded Schema for {0}", url); //NOI18N
-+        
-+        TypedInputSource schemaInput = (TypedInputSource) entityResolver.resolveEntity(
-+                null, url);
-+        SchemaReader sr = null;
-+        if ("application/relax-ng-compact-syntax".equals(schemaInput.getType())) {
-+            sr = CompactSchemaReader.getInstance();
-+        } else {
-+            sr = new AutoSchemaReader();
-+        }
-+        Schema sch = sr.createSchema(schemaInput, options);
-+        return sch;
-+    }
-+    
-+    /**
-+     * @param validator
-+     * @return
-+     * @throws SAXException
-+     * @throws IOException
-+     * @throws IncorrectSchemaException
-+     */
-+    protected Validator validatorByUrls(String schemaList) throws SAXException,
-+            IOException, IncorrectSchemaException {
-+        Validator v = null;
-+        String[] schemas = SPACE.split(schemaList);
-+        for (int i = schemas.length - 1; i > -1; i--) {
-+            String url = schemas[i];
-+            if ("http://c.validator.nu/all/".equals(url)
-+                    || "http://hsivonen.iki.fi/checkers/all/".equals(url)) {
-+                for (int j = 0; j < ALL_CHECKERS.length; j++) {
-+                    v = combineValidatorByUrl(v, ALL_CHECKERS[j]);
-+                }
-+            } else if ("http://c.validator.nu/all-html4/".equals(url)
-+                    || "http://hsivonen.iki.fi/checkers/all-html4/".equals(url)) {
-+                for (int j = 0; j < ALL_CHECKERS_HTML4.length; j++) {
-+                    v = combineValidatorByUrl(v, ALL_CHECKERS_HTML4[j]);
-+                }
-+            } else {
-+                v = combineValidatorByUrl(v, url);
-+            }
-+        }
-+        return v;
-+    }
-+    
-+    /**
-+     * @param val
-+     * @param url
-+     * @return
-+     * @throws SAXException
-+     * @throws IOException
-+     * @throws IncorrectSchemaException
-+     */
-+    private Validator combineValidatorByUrl(Validator val, String url)
-+            throws SAXException, IOException, IncorrectSchemaException {
-+        if (!"".equals(url)) {
-+            Validator v = validatorByUrl(url);
-+            if (val == null) {
-+                val = v;
-+            } else {
-+                val = new CombineValidator(v, val);
-+            }
-+        }
-+        return val;
-+    }
-+    
-+    /**
-+     * @param url
-+     * @return
-+     * @throws SAXException
-+     * @throws IOException
-+     * @throws IncorrectSchemaException
-+     */
-+    private Validator validatorByUrl(String url) throws SAXException,
-+            IOException, IncorrectSchemaException {
-+        Validator v = loadedValidatorUrls.get(url);
-+        if (v != null) {
-+            return v;
-+        }
-+
-+
-+        if ("http://s.validator.nu/html5/html5full-aria.rnc".equals(url)
-+                || "http://s.validator.nu/xhtml5-aria-rdf-svg-mathml.rnc".equals(url)
-+                || "http://s.validator.nu/html5/html5full.rnc".equals(url)
-+                || "http://s.validator.nu/html5/xhtml5full-xhtml.rnc".equals(url)
-+                || "http://s.validator.nu/html5-aria-svg-mathml.rnc".equals(url)) {
-+            errorHandler.setSpec(html5spec);
-+        }
-+        Schema sch = resolveSchema(url, jingPropertyMap);
-+        Validator validatorInstance = sch.createValidator(jingPropertyMap);
-+        if (validatorInstance.getContentHandler() instanceof XmlPiChecker) {
-+            lexicalHandler = (LexicalHandler) validatorInstance.getContentHandler();
-+        }
-+
-+        loadedValidatorUrls.put(url, v);
-+        return validatorInstance;
-+    }
-+    
-+    private String getPresetLabel(int schemaId) {
-+        for (int i = 0; i < presetDoctypes.length; i++) {
-+            if (presetDoctypes[i] == schemaId) {
-+                return presetLabels[i];
-+            }
-+        }
-+        return "unknown";
-+    }
-+    
-+    protected Validator validatorByDoctype(int schemaId) throws SAXException,
-+            IOException, IncorrectSchemaException {
-+        if (schemaId == 0) {
-+            return null;
-+        }
-+        for (int i = 0; i < presetDoctypes.length; i++) {
-+            if (presetDoctypes[i] == schemaId) {
-+                return validatorByUrls(presetUrls[i]);
-+            }
-+        }
-+        throw new RuntimeException("Doctype mappings not initialized properly.");
-+    }
-+    
-+    
-+    /**
-+     * @param url
-+     * @return
-+     * @throws SAXException
-+     * @throws IOException
-+     * @throws IncorrectSchemaException
-+     */
-+    private static Schema schemaByUrl(String url, EntityResolver resolver,
-+            PropertyMap pMap) throws SAXException, IOException,
-+            IncorrectSchemaException {
-+        LOGGER.fine(String.format("Will load schema: %s", url));
-+        long a = System.currentTimeMillis();
-+        TypedInputSource schemaInput;
-+        try {
-+            schemaInput = (TypedInputSource) resolver.resolveEntity(
-+                    null, url);
-+        } catch (ClassCastException e) {
-+            LOGGER.log(Level.SEVERE, url, e);
-+            throw e;
-+        }
-+
-+        SchemaReader sr = null;
-+        if ("application/relax-ng-compact-syntax".equals(schemaInput.getType())) {
-+            sr = CompactSchemaReader.getInstance();
-+            LOGGER.log(Level.FINE, "Used CompactSchemaReader");
-+        } else {
-+            sr = new AutoSchemaReader();
-+            LOGGER.log(Level.FINE, "Used AutoSchemaReader");
-+        }
-+        long c = System.currentTimeMillis();
-+
-+        Schema sch = sr.createSchema(schemaInput, pMap);
-+        LOGGER.log(Level.FINE, String.format("Schema created in %s ms.", (System.currentTimeMillis() - c)));
-+        return sch;
-+    }
-+    
-+    protected static Schema proxySchemaByUrl(String uri, EntityResolver resolver, PropertyMap pMap) {
-+        return new ProxySchema(uri, resolver, pMap);
-+    }
-+    
-+    /**
-+     * A Schema instance delegate, the delegated instance if softly reachable so it should 
-+     * not be GCed so often. If the delegate is GCed a new instance is recreated.
-+     */
-+    private static class ProxySchema implements Schema {
-+    
-+        private String uri;
-+        private EntityResolver resolver;
-+        private PropertyMap pMap;
-+        
-+        private SoftReference<Schema> delegateWeakRef;
-+        
-+        private ProxySchema(String uri, EntityResolver resolver, PropertyMap pMap) {
-+            this.uri = uri;
-+            this.resolver = resolver;
-+            this.pMap = pMap;
-+        }
-+
-+        //exposing just because of some instanceof test used in the code
-+        private Schema getWrappedSchema() throws SAXException, IOException, IncorrectSchemaException {
-+            return getSchemaDelegate();
-+        }
-+        
-+        public Validator createValidator(PropertyMap pm) {
-+            try {
-+                return getSchemaDelegate().createValidator(pm);
-+            } catch (Exception ex) { //SAXException, IOException, IncorrectSchemaException
-+                LOGGER.log(Level.INFO, "Cannot create schema delegate", ex); //NOI18N
-+            }
-+            return null;
-+        }
-+
-+        public PropertyMap getProperties() {
-+            try {
-+                return getSchemaDelegate().getProperties();
-+            } catch (Exception ex) { //SAXException, IOException, IncorrectSchemaException
-+                LOGGER.log(Level.INFO, "Cannot create schema delegate", ex); //NOI18N
-+            }
-+            return null;
-+        }
-+        
-+        private synchronized Schema getSchemaDelegate() throws SAXException, IOException, IncorrectSchemaException {
-+            Schema delegate = delegateWeakRef != null ? delegateWeakRef.get() : null;
-+            if(delegate == null) {
-+                long a = System.currentTimeMillis();
-+                delegate = schemaByUrl(uri, resolver, pMap);
-+                long b = System.currentTimeMillis();
-+                delegateWeakRef = new SoftReference<Schema>(delegate);
-+                LOGGER.log(Level.FINE, "Created new Schema instance for {0} in {1}ms.", new Object[]{uri, (b-a)});
-+            } else {
-+                LOGGER.log(Level.FINE, "Using cached Schema instance for {0}", uri);
-+            }
-+            return delegate;
-+        }
-+        
-+        
-+    }
-+    
-+}
-diff --git a/src/nu/validator/servlet/BufferingRootNamespaceSniffer.java b/src/nu/validator/servlet/BufferingRootNamespaceSniffer.java
-deleted file mode 100644
-index f339667..0000000
---- a/src/nu/validator/servlet/BufferingRootNamespaceSniffer.java
-+++ /dev/null
-@@ -1,173 +0,0 @@
--/*
-- * Copyright (c) 2006 Henri Sivonen
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.util.Iterator;
--import java.util.LinkedList;
--import java.util.List;
--
--import org.xml.sax.Attributes;
--import org.xml.sax.ContentHandler;
--import org.xml.sax.Locator;
--import org.xml.sax.SAXException;
--
--public class BufferingRootNamespaceSniffer implements ContentHandler {
--
--    private ContentHandler ch = null;
--
--    private Locator locator = null;
--    
--    private List<String[]> namespaces = new LinkedList<String[]>();
--    
--    private VerifierServletTransaction vst;
--    
--    public BufferingRootNamespaceSniffer(VerifierServletTransaction vst) {
--        super();
--        this.vst = vst;
--    }
--
--    public void setContentHandler(ContentHandler contentHandler) throws SAXException {
--        this.ch = contentHandler;
--        if (locator != null) {
--            ch.setDocumentLocator(locator);
--        }
--        ch.startDocument();
--        for (Iterator<String[]> iter = namespaces.iterator(); iter.hasNext();) {
--            String[] element = iter.next();
--            ch.startPrefixMapping(element[0], element[1]);
--        }
--    }
--    
--    /**
--     * @see org.xml.sax.ContentHandler#characters(char[], int, int)
--     */
--    public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
--        if (ch != null) {
--            ch.characters(arg0, arg1, arg2);
--        }
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#endDocument()
--     */
--    public void endDocument() throws SAXException {
--        if (ch != null) {
--            ch.endDocument();
--        }
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#endElement(java.lang.String,
--     *      java.lang.String, java.lang.String)
--     */
--    public void endElement(String arg0, String arg1, String arg2)
--            throws SAXException {
--        if (ch != null) {
--            ch.endElement(arg0, arg1, arg2);
--        }
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
--     */
--    public void endPrefixMapping(String arg0) throws SAXException {
--        if (ch != null) {
--            ch.endPrefixMapping(arg0);
--        }
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
--     */
--    public void ignorableWhitespace(char[] arg0, int arg1, int arg2)
--            throws SAXException {
--        if (ch != null) {
--            ch.ignorableWhitespace(arg0, arg1, arg2);
--        }
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String,
--     *      java.lang.String)
--     */
--    public void processingInstruction(String arg0, String arg1)
--            throws SAXException {
--        if (ch != null) {
--            ch.processingInstruction(arg0, arg1);
--        }
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
--     */
--    public void setDocumentLocator(Locator arg0) {
--        locator = arg0;
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
--     */
--    public void skippedEntity(String arg0) throws SAXException {
--        if (ch != null) {
--            ch.skippedEntity(arg0);
--        }
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#startDocument()
--     */
--    public void startDocument() throws SAXException {
--
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#startElement(java.lang.String,
--     *      java.lang.String, java.lang.String, org.xml.sax.Attributes)
--     */
--    public void startElement(String arg0, String arg1, String arg2,
--            Attributes arg3) throws SAXException {
--        if (ch != null) {
--            ch.startElement(arg0, arg1, arg2, arg3);
--        } else {
--            vst.rootNamespace(arg0, locator);
--            ch.startElement(arg0, arg1, arg2, arg3);
--        }
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String,
--     *      java.lang.String)
--     */
--    public void startPrefixMapping(String arg0, String arg1)
--            throws SAXException {
--        if (ch != null) {
--            ch.startPrefixMapping(arg0, arg1);
--        } else {
--            String[] arr = new String[2];
--            arr[0] = arg0;
--            arr[1] = arg1;
--            namespaces.add(arr);
--        }
--    }
--
--}
-diff --git a/src/nu/validator/servlet/CharsetEmitter.java b/src/nu/validator/servlet/CharsetEmitter.java
-deleted file mode 100644
-index 6b795b8..0000000
---- a/src/nu/validator/servlet/CharsetEmitter.java
-+++ /dev/null
-@@ -1,38 +0,0 @@
--/* This code was generated by nu.validator.tools.SaxCompiler. Please regenerate instead of editing. */
--package nu.validator.servlet;
--public final class CharsetEmitter {
--private CharsetEmitter() {}
--public static void emit(org.xml.sax.ContentHandler contentHandler, nu.validator.servlet.VerifierServletTransaction t) throws org.xml.sax.SAXException {
--org.xml.sax.helpers.AttributesImpl __attrs__ = new org.xml.sax.helpers.AttributesImpl();
--contentHandler.startPrefixMapping("", "http://www.w3.org/1999/xhtml");
--__attrs__.clear();
--__attrs__.addAttribute("", "title", "title", "CDATA", "Override for transfer protocol character encoding declaration.");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "tr", "tr", __attrs__);
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "th", "th", __attrs__);
--__attrs__.clear();
--__attrs__.addAttribute("", "for", "for", "CDATA", "charset");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "label", "label", __attrs__);
--contentHandler.characters(__chars__, 0, 8);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "label", "label");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "th", "th");
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "td", "td", __attrs__);
--__attrs__.clear();
--__attrs__.addAttribute("", "id", "id", "CDATA", "charset");
--__attrs__.addAttribute("", "name", "name", "CDATA", "charset");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "select", "select", __attrs__);
--__attrs__.clear();
--__attrs__.addAttribute("", "value", "value", "CDATA", "");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "option", "option", __attrs__);
--contentHandler.characters(__chars__, 8, 25);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "option", "option");
--t.emitCharsetOptions(); 
--		
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "select", "select");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "td", "td");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "tr", "tr");
--contentHandler.endPrefixMapping("");
--}
--private static final char[] __chars__ = { 'E', 'n', 'c', 'o', 'd', 'i', 'n', 'g', 'A', 's', ' ', 's', 'e', 't', ' ', 'b', 'y', ' ', 't', 'h', 'e', ' ', 's', 'e', 'r', 'v', 'e', 'r', '/', 'p', 'a', 'g', 'e' };
--}
-diff --git a/src/nu/validator/servlet/CssDetector.java b/src/nu/validator/servlet/CssDetector.java
-deleted file mode 100644
-index e9308d7..0000000
---- a/src/nu/validator/servlet/CssDetector.java
-+++ /dev/null
-@@ -1,160 +0,0 @@
--/*
-- * Copyright (c) 2008 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.util.regex.Matcher;
--import java.util.regex.Pattern;
--
--import nu.validator.checker.AttributeUtil;
--import org.xml.sax.Attributes;
--import org.xml.sax.ContentHandler;
--import org.xml.sax.DTDHandler;
--import org.xml.sax.Locator;
--import org.xml.sax.SAXException;
--
--import com.thaiopensource.validate.Validator;
--
--public class CssDetector implements Validator, ContentHandler {
--
--    public static boolean lowerCaseLiteralEqualsIgnoreAsciiCase(String lowerCaseLiteral,
--            String string) {
--        if (string == null) {
--            return false;
--        }
--        if (lowerCaseLiteral.length() != string.length()) {
--            return false;
--        }
--        for (int i = 0; i < lowerCaseLiteral.length(); i++) {
--            char c0 = lowerCaseLiteral.charAt(i);
--            char c1 = string.charAt(i);
--            if (c1 >= 'A' && c1 <= 'Z') {
--                c1 += 0x20;
--            }
--            if (c0 != c1) {
--                return false;
--            }
--        }
--        return true;
--    }
--    
--    private static final Pattern TEXT_CSS = Pattern.compile("^[tT][eE][xX][tT]/[cC][sS][sS]\\s*(?:;.*)?$");
--    
--    private boolean sawCss = false;
--    
--    public ContentHandler getContentHandler() {
--        return this;
--    }
--
--    public DTDHandler getDTDHandler() {
--        return null;
--    }
--
--    public void reset() {
--        sawCss = false;
--    }
--
--    public void characters(char[] ch, int start, int length)
--            throws SAXException {
--        
--    }
--
--    public void endDocument() throws SAXException {
--        
--    }
--
--    public void endElement(String uri, String localName, String name)
--            throws SAXException {
--        
--    }
--
--    public void endPrefixMapping(String prefix) throws SAXException {
--        // TODO Auto-generated method stub
--        
--    }
--
--    public void ignorableWhitespace(char[] ch, int start, int length)
--            throws SAXException {
--        
--    }
--
--    public void processingInstruction(String target, String data)
--            throws SAXException {
--        
--    }
--
--    public void setDocumentLocator(Locator locator) {
--        
--    }
--
--    public void skippedEntity(String name) throws SAXException {
--        
--    }
--
--    public void startDocument() throws SAXException {
--        reset();
--    }
--
--    public void startElement(String uri, String localName, String name,
--            Attributes atts) throws SAXException {
--        if ("http://www.w3.org/1999/xhtml" == uri) {
--            if ("style" == localName) {
--                checkType(atts);
--                return;
--            } else if ("link" == localName) {
--                String rel = atts.getValue("", "rel");
--                if (rel != null) {
--                    String[] tokens = AttributeUtil.split(rel);
--                    for (int i = 0; i < tokens.length; i++) {
--                        String token = tokens[i];
--                        if (lowerCaseLiteralEqualsIgnoreAsciiCase("stylesheet", token)) {
--                            checkType(atts);
--                            return;
--                        }
--                    }
--                }
--            } else {
--                if (atts.getIndex("", "style") > -1) {
--                    sawCss = true;
--                }
--            }
--        }
--    }
--
--    private void checkType(Attributes atts) {
--        String type = atts.getValue("", "type");
--        if (type == null) {
--            sawCss = true;
--        } else {
--            Matcher m = TEXT_CSS.matcher(type);
--            if (m.matches()) {
--                sawCss = true;                
--            }
--        }
--    }
--
--    public void startPrefixMapping(String prefix, String uri)
--            throws SAXException {
--        
--    }
--
--}
-diff --git a/src/nu/validator/servlet/DelegatingServletInputStream.java b/src/nu/validator/servlet/DelegatingServletInputStream.java
-deleted file mode 100644
-index db669fa..0000000
---- a/src/nu/validator/servlet/DelegatingServletInputStream.java
-+++ /dev/null
-@@ -1,166 +0,0 @@
--/*
-- * Copyright (c) 2007-2015 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.io.IOException;
--import java.io.InputStream;
--
--import javax.servlet.ReadListener;
--import javax.servlet.ServletInputStream;
--
--public final class DelegatingServletInputStream extends ServletInputStream {
--
--    private final InputStream delegate;
--
--    public DelegatingServletInputStream(InputStream delegate) {
--        this.delegate = delegate;
--    }
--
--    /**
--     * @return
--     * @throws IOException
--     * @see java.io.InputStream#available()
--     */
--    public int available() throws IOException {
--        return delegate.available();
--    }
--
--    /**
--     * @throws IOException
--     * @see java.io.InputStream#close()
--     */
--    public void close() throws IOException {
--        delegate.close();
--    }
--
--    /**
--     * @param obj
--     * @return
--     * @see java.lang.Object#equals(java.lang.Object)
--     */
--    public boolean equals(Object obj) {
--        return delegate.equals(obj);
--    }
--
--    /**
--     * @return
--     * @see java.lang.Object#hashCode()
--     */
--    public int hashCode() {
--        return delegate.hashCode();
--    }
--
--    /**
--     * @param readlimit
--     * @see java.io.InputStream#mark(int)
--     */
--    public void mark(int readlimit) {
--        delegate.mark(readlimit);
--    }
--
--    /**
--     * @return
--     * @see java.io.InputStream#markSupported()
--     */
--    public boolean markSupported() {
--        return delegate.markSupported();
--    }
--
--    /**
--     * @return
--     * @throws IOException
--     * @see java.io.InputStream#read()
--     */
--    public int read() throws IOException {
--        return delegate.read();
--    }
--
--    /**
--     * @param b
--     * @param off
--     * @param len
--     * @return
--     * @throws IOException
--     * @see java.io.InputStream#read(byte[], int, int)
--     */
--    public int read(byte[] b, int off, int len) throws IOException {
--        return delegate.read(b, off, len);
--    }
--
--    /**
--     * @param b
--     * @return
--     * @throws IOException
--     * @see java.io.InputStream#read(byte[])
--     */
--    public int read(byte[] b) throws IOException {
--        return delegate.read(b);
--    }
--
--    /**
--     * @throws IOException
--     * @see java.io.InputStream#reset()
--     */
--    public void reset() throws IOException {
--        delegate.reset();
--    }
--
--    /**
--     * @param n
--     * @return
--     * @throws IOException
--     * @see java.io.InputStream#skip(long)
--     */
--    public long skip(long n) throws IOException {
--        return delegate.skip(n);
--    }
--
--    /**
--     * @return
--     * @see java.lang.Object#toString()
--     */
--    public String toString() {
--        return delegate.toString();
--    }
--
--    /**
--     * @return
--     */
--    @Override public boolean isFinished() {
--        return false;
--    }
--
--    /**
--     * @return
--     */
--    @Override public boolean isReady() {
--        return false;
--    }
--
--    /**
--     * @param arg0
--     */
--    @Override public void setReadListener(ReadListener arg0) {
--    }
--
--}
-diff --git a/src/nu/validator/servlet/Html5ConformanceCheckerTransaction.java b/src/nu/validator/servlet/Html5ConformanceCheckerTransaction.java
-deleted file mode 100644
-index f9837f8..0000000
---- a/src/nu/validator/servlet/Html5ConformanceCheckerTransaction.java
-+++ /dev/null
-@@ -1,194 +0,0 @@
--/*
-- * Copyright (c) 2005, 2006 Henri Sivonen
-- * Copyright (c) 2007-2010 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.io.IOException;
--
--import javax.servlet.ServletException;
--import javax.servlet.http.HttpServletRequest;
--import javax.servlet.http.HttpServletResponse;
--
--import nu.validator.htmlparser.common.DoctypeExpectation;
--
--import org.xml.sax.SAXException;
--import org.xml.sax.SAXNotRecognizedException;
--import org.xml.sax.SAXNotSupportedException;
--import org.xml.sax.SAXParseException;
--
--import com.thaiopensource.validate.IncorrectSchemaException;
--
--
--public class Html5ConformanceCheckerTransaction extends
--        VerifierServletTransaction {
--
--    /**
--     * @see nu.validator.servlet.VerifierServletTransaction#isSimple()
--     */
--    @Override
--    protected boolean isSimple() {
--        return true;
--    }
--    
--    private final static String GENERIC_FACET = (VerifierServlet.GENERIC_HOST.isEmpty() ? "" : ("//" + VerifierServlet.GENERIC_HOST)) + VerifierServlet.GENERIC_PATH;
--
--    private static final char[] GENERIC_UI = "More options".toCharArray();    
--    
--    private static final char[] SERVICE_TITLE = (System.getProperty(
--            "nu.validator.servlet.service-name", "Validator.nu") + " (X)HTML5 Validator ").toCharArray();
--
--    private static final char[] TECHNOLOGY_PREVIEW = "(Living Validator)".toCharArray();
--
--    private static final char[] RESULTS_TITLE = "(X)HTML5 validation results".toCharArray();
--
--    private static final char[] FOR = " for ".toCharArray();
--    
--    private static final String SUCCESS_HTML = "The document is valid HTML5 + ARIA + SVG 1.1 + MathML 2.0 (subject to the utter previewness of this service).";
--
--    private static final String SUCCESS_XHTML = "The document is valid XHTML5 + ARIA + SVG 1.1 + MathML 2.0 (subject to the utter previewness of this service).";
--
--    private static final String FAILURE_HTML = "There were errors. (Tried in the text/html mode.)";
--
--    private static final String FAILURE_XHTML = "There were errors. (Tried in the XHTML mode.)";
--
--    private boolean usingHtml = false;
--    
--    public Html5ConformanceCheckerTransaction(HttpServletRequest request,
--            HttpServletResponse response) {
--        super(request, response);
--    }
--
--    /**
--     * @see nu.validator.servlet.VerifierServletTransaction#successMessage()
--     */
--    protected String successMessage() throws SAXException {
--        if (usingHtml) {
--            return SUCCESS_HTML;
--        } else {
--            return SUCCESS_XHTML;
--        }
--    }
--
--    /**
--     * @see nu.validator.servlet.VerifierServletTransaction#loadDocAndSetupParser()
--     */
--    protected void loadDocAndSetupParser() throws SAXException, IOException, IncorrectSchemaException, SAXNotRecognizedException, SAXNotSupportedException {
--        setAllowGenericXml(false);
--        setAcceptAllKnownXmlTypes(false);
--        setAllowHtml(true);
--        setAllowXhtml(true);
--        loadDocumentInput();
--        String type = documentInput.getType();
--        if ("text/html".equals(type) || "text/html-sandboxed".equals(type)) {
--            validator = validatorByDoctype(HTML5_SCHEMA);
--            usingHtml = true;
--            newHtmlParser();
--            htmlParser.setDoctypeExpectation(DoctypeExpectation.HTML);
--            htmlParser.setDocumentModeHandler(this);
--            htmlParser.setContentHandler(validator.getContentHandler());
--            reader = htmlParser;
--        } else {
--            validator = validatorByDoctype(XHTML5_SCHEMA);
--            setupXmlParser();
--            if (!("application/xhtml+xml".equals(type) || "application/xml".equals(type))) {
--                String message = "The preferred Content-Type for XHTML5 is application/xhtml+xml. The Content-Type was " + type + ".";
--                SAXParseException spe = new SAXParseException(message, null, documentInput.getSystemId(), -1, -1);
--                errorHandler.warning(spe);
--            }
--        }
--
--    }
--
--    /**
--     * @see nu.validator.servlet.VerifierServletTransaction#setup()
--     */
--    protected void setup() throws ServletException {
--        // No-op
--    }
--
--    /**
--     * @see nu.validator.servlet.VerifierServletTransaction#emitTitle()
--     */
--    void emitTitle(boolean markupAllowed) throws SAXException {
--        if (willValidate()) {
--            emitter.characters(RESULTS_TITLE);
--            if (document != null && document.length() > 0) {
--                emitter.characters(FOR);                
--                emitter.characters(scrub(shortenDataUri(document)));                
--            }
--        } else {
--            emitter.characters(SERVICE_TITLE);
--            if (markupAllowed && System.getProperty("nu.validator.servlet.service-name", "Validator.nu").equals("Validator.nu")) {
--                emitter.startElement("span");
--                emitter.characters(TECHNOLOGY_PREVIEW);
--                emitter.endElement("span");
--            }
--        }
--    }
--
--    /**
--     * @see nu.validator.servlet.VerifierServletTransaction#tryToSetupValidator()
--     */
--    protected void tryToSetupValidator() throws SAXException, IOException, IncorrectSchemaException {
--        // No-op
--    }
--
--    /**
--     * @see nu.validator.servlet.VerifierServletTransaction#failureMessage()
--     */
--    protected String failureMessage() throws SAXException {
--        if (usingHtml) {
--            return FAILURE_HTML;
--        } else {
--            return FAILURE_XHTML;
--        }
--    }
--
--    /**
--     * @see nu.validator.servlet.VerifierServletTransaction#emitFormContent()
--     */
--    protected void emitFormContent() throws SAXException {
--        Html5FormEmitter.emit(contentHandler, this);
--    }
--
--    void maybeEmitNsfilterField() throws SAXException {
--        if (request.getParameter("nsfilter") != null) {
--            NsFilterEmitter.emit(contentHandler, this);
--        }
--    }
--
--    void maybeEmitCharsetField() throws SAXException {
--        if (request.getParameter("charset") != null) {
--            CharsetEmitter.emit(contentHandler, this);
--        }
--    }
--    
--    void emitOtherFacetLink() throws SAXException {
--        attrs.clear();
--        attrs.addAttribute("href", GENERIC_FACET);
--        emitter.startElement("a", attrs);
--        emitter.characters(GENERIC_UI);
--        emitter.endElement("a");   
--    }
--
--}
-diff --git a/src/nu/validator/servlet/Html5FormEmitter.java b/src/nu/validator/servlet/Html5FormEmitter.java
-deleted file mode 100644
-index a2901ba..0000000
---- a/src/nu/validator/servlet/Html5FormEmitter.java
-+++ /dev/null
-@@ -1,90 +0,0 @@
--/* This code was generated by nu.validator.tools.SaxCompiler. Please regenerate instead of editing. */
--package nu.validator.servlet;
--public final class Html5FormEmitter {
--private Html5FormEmitter() {}
--public static void emit(org.xml.sax.ContentHandler contentHandler, nu.validator.servlet.VerifierServletTransaction t) throws org.xml.sax.SAXException {
--org.xml.sax.helpers.AttributesImpl __attrs__ = new org.xml.sax.helpers.AttributesImpl();
--contentHandler.startPrefixMapping("", "http://www.w3.org/1999/xhtml");
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "fieldset", "fieldset", __attrs__);
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "legend", "legend", __attrs__);
--contentHandler.characters(__chars__, 0, 15);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "legend", "legend");
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "table", "table", __attrs__);
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "tbody", "tbody", __attrs__);
--__attrs__.clear();
--__attrs__.addAttribute("", "title", "title", "CDATA", "The document to validate.");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "tr", "tr", __attrs__);
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "th", "th", __attrs__);
--__attrs__.clear();
--__attrs__.addAttribute("", "for", "for", "CDATA", "doc");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "label", "label", __attrs__);
--contentHandler.characters(__chars__, 15, 8);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "label", "label");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "th", "th");
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "td", "td", __attrs__);
--t.emitDocField(); 
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "td", "td");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "tr", "tr");
--t.maybeEmitCharsetField(); t.maybeEmitNsfilterField(); 
--__attrs__.clear();
--__attrs__.addAttribute("", "title", "title", "CDATA", "Display a report about the textual alternatives for images.");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "tr", "tr", __attrs__);
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "th", "th", __attrs__);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "th", "th");
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "td", "td", __attrs__);
--__attrs__.clear();
--__attrs__.addAttribute("", "for", "for", "CDATA", "showimagereport");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "label", "label", __attrs__);
--t.emitShowImageReportField(); 
--						
--contentHandler.characters(__chars__, 23, 18);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "label", "label");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "td", "td");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "tr", "tr");
--__attrs__.clear();
--__attrs__.addAttribute("", "title", "title", "CDATA", "Display the markup source of the input document.");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "tr", "tr", __attrs__);
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "th", "th", __attrs__);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "th", "th");
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "td", "td", __attrs__);
--__attrs__.clear();
--__attrs__.addAttribute("", "for", "for", "CDATA", "showsource");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "label", "label", __attrs__);
--t.emitShowSourceField(); 
--						
--contentHandler.characters(__chars__, 41, 12);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "label", "label");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "td", "td");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "tr", "tr");
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "tr", "tr", __attrs__);
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "th", "th", __attrs__);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "th", "th");
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "td", "td", __attrs__);
--__attrs__.clear();
--__attrs__.addAttribute("", "value", "value", "CDATA", "Validate");
--__attrs__.addAttribute("", "type", "type", "CDATA", "submit");
--__attrs__.addAttribute("", "id", "id", "CDATA", "submit");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "input", "input", __attrs__);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "input", "input");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "td", "td");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "tr", "tr");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "tbody", "tbody");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "table", "table");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "fieldset", "fieldset");
--contentHandler.endPrefixMapping("");
--}
--private static final char[] __chars__ = { 'V', 'a', 'l', 'i', 'd', 'a', 't', 'o', 'r', ' ', 'I', 'n', 'p', 'u', 't', 'D', 'o', 'c', 'u', 'm', 'e', 'n', 't', ' ', 'S', 'h', 'o', 'w', ' ', 'I', 'm', 'a', 'g', 'e', ' ', 'R', 'e', 'p', 'o', 'r', 't', ' ', 'S', 'h', 'o', 'w', ' ', 'S', 'o', 'u', 'r', 'c', 'e' };
--}
-diff --git a/src/nu/validator/servlet/InboundGzipFilter.java b/src/nu/validator/servlet/InboundGzipFilter.java
-deleted file mode 100644
-index e5c13a9..0000000
---- a/src/nu/validator/servlet/InboundGzipFilter.java
-+++ /dev/null
-@@ -1,180 +0,0 @@
--/*
-- * Copyright (c) 2007-2008 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.io.IOException;
--import java.util.ArrayList;
--import java.util.Collections;
--import java.util.Enumeration;
--import java.util.List;
--import java.util.zip.GZIPInputStream;
--
--import javax.servlet.Filter;
--import javax.servlet.FilterChain;
--import javax.servlet.FilterConfig;
--import javax.servlet.ServletException;
--import javax.servlet.ServletInputStream;
--import javax.servlet.ServletRequest;
--import javax.servlet.ServletResponse;
--import javax.servlet.http.HttpServletRequest;
--import javax.servlet.http.HttpServletRequestWrapper;
--import javax.servlet.http.HttpServletResponse;
--
--public final class InboundGzipFilter implements Filter {
--
--    public void destroy() {
--    }
--
--    public void doFilter(ServletRequest req, ServletResponse res,
--            FilterChain chain) throws IOException, ServletException {
--        HttpServletRequest request = (HttpServletRequest) req;
--        HttpServletResponse response = (HttpServletResponse) res;
--        response.setHeader("Accept-Encoding", "gzip");
--        String ce = request.getHeader("Content-Encoding");
--        if (ce != null && "gzip".equalsIgnoreCase(ce.trim())) {
--            chain.doFilter(new RequestWrapper(request), res);
--        } else {
--            chain.doFilter(req, res);
--        }
--    }
--
--    public void init(FilterConfig config) throws ServletException {
--    }
--
--    private final class RequestWrapper extends HttpServletRequestWrapper {
--
--        private ServletInputStream stream = null;
--
--        public RequestWrapper(HttpServletRequest req) throws IOException {
--            super(req);
--        }
--
--        /**
--         * @see javax.servlet.http.HttpServletRequestWrapper#getDateHeader(java.lang.String)
--         */
--        @Override
--        public long getDateHeader(String name) {
--            if ("Content-Length".equalsIgnoreCase(name)) {
--                return -1;
--            } else if ("Content-MD5".equalsIgnoreCase(name)) {
--                return -1;
--            } else if ("Content-Encoding".equalsIgnoreCase(name)) {
--                return -1;
--            } else {
--                return super.getDateHeader(name);
--            }
--        }
--
--        /**
--         * @see javax.servlet.http.HttpServletRequestWrapper#getHeader(java.lang.String)
--         */
--        @Override
--        public String getHeader(String name) {
--            if ("Content-Length".equalsIgnoreCase(name)) {
--                return null;
--            } else if ("Content-MD5".equalsIgnoreCase(name)) {
--                return null;
--            } else if ("Content-Encoding".equalsIgnoreCase(name)) {
--                return null;
--            } else {
--                return super.getHeader(name);
--            }
--        }
--
--        /**
--         * @see javax.servlet.http.HttpServletRequestWrapper#getHeaderNames()
--         */
--        @Override
--        public Enumeration getHeaderNames() {
--            Enumeration e = super.getHeaderNames();
--            List<String> list = new ArrayList<String>();
--            while (e.hasMoreElements()) {
--                String name = (String) e.nextElement();
--                if ("Content-Length".equalsIgnoreCase(name)) {
--                    continue;
--                } else if ("Content-MD5".equalsIgnoreCase(name)) {
--                    continue;
--                } else if ("Content-Encoding".equalsIgnoreCase(name)) {
--                    continue;
--                } else {
--                    list.add(name);
--                }
--            }
--            return Collections.enumeration(list);
--        }
--
--        /**
--         * @see javax.servlet.http.HttpServletRequestWrapper#getHeaders(java.lang.String)
--         */
--        @SuppressWarnings("unchecked")
--        @Override
--        public Enumeration getHeaders(String name) {
--            if ("Content-Length".equalsIgnoreCase(name)) {
--                return Collections.enumeration(Collections.EMPTY_SET);
--            } else if ("Content-MD5".equalsIgnoreCase(name)) {
--                return Collections.enumeration(Collections.EMPTY_SET);
--            } else if ("Content-Encoding".equalsIgnoreCase(name)) {
--                return Collections.enumeration(Collections.EMPTY_SET);
--            } else {
--                return super.getHeaders(name);
--            }
--        }
--
--        /**
--         * @see javax.servlet.http.HttpServletRequestWrapper#getIntHeader(java.lang.String)
--         */
--        @Override
--        public int getIntHeader(String name) {
--            if ("Content-Length".equalsIgnoreCase(name)) {
--                return -1;
--            } else if ("Content-MD5".equalsIgnoreCase(name)) {
--                return -1;
--            } else if ("Content-Encoding".equalsIgnoreCase(name)) {
--                return -1;
--            } else {
--                return super.getIntHeader(name);
--            }
--        }
--
--        /**
--         * @see javax.servlet.ServletRequestWrapper#getContentLength()
--         */
--        @Override
--        public int getContentLength() {
--            return -1;
--        }
--
--        /**
--         * @see javax.servlet.ServletRequestWrapper#getInputStream()
--         */
--        @Override
--        public ServletInputStream getInputStream() throws IOException {
--            if (stream == null) {
--                stream = new DelegatingServletInputStream(new GZIPInputStream(super.getInputStream()));
--            }
--            return stream;
--        }
--
--    }
--
--}
-diff --git a/src/nu/validator/servlet/InboundSizeLimitFilter.java b/src/nu/validator/servlet/InboundSizeLimitFilter.java
-deleted file mode 100644
-index dc8b6ee..0000000
---- a/src/nu/validator/servlet/InboundSizeLimitFilter.java
-+++ /dev/null
-@@ -1,91 +0,0 @@
--/*
-- * Copyright (c) 2007-2008 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.io.IOException;
--
--import javax.servlet.Filter;
--import javax.servlet.FilterChain;
--import javax.servlet.FilterConfig;
--import javax.servlet.ServletException;
--import javax.servlet.ServletInputStream;
--import javax.servlet.ServletRequest;
--import javax.servlet.ServletResponse;
--import javax.servlet.http.HttpServletRequest;
--import javax.servlet.http.HttpServletRequestWrapper;
--
--import nu.validator.io.BoundedInputStream;
--import nu.validator.io.StreamBoundException;
--
--public final class InboundSizeLimitFilter implements Filter {
--
--    private long sizeLimit;
--    
--    /**
--     * @param sizeLimit
--     */
--    public InboundSizeLimitFilter(final long sizeLimit) {
--        this.sizeLimit = sizeLimit;
--    }
--    
--    public InboundSizeLimitFilter() {
--        this(Long.MAX_VALUE);
--    }
--    
--    public void destroy() {
--    }
--
--    public void doFilter(ServletRequest req, ServletResponse res,
--            FilterChain chain) throws IOException, ServletException {
--        HttpServletRequest request = (HttpServletRequest) req;
--        chain.doFilter(new RequestWrapper(request), res);
--    }
--
--    public void init(FilterConfig config) throws ServletException {
--        // XXX add configurability
--    }
--
--    private final class RequestWrapper extends HttpServletRequestWrapper {
--
--        private ServletInputStream stream = null;
--
--        public RequestWrapper(HttpServletRequest req) throws IOException {
--            super(req);
--        }
--
--        /**
--         * @see javax.servlet.ServletRequestWrapper#getInputStream()
--         */
--        @Override
--        public ServletInputStream getInputStream() throws IOException {
--            if (stream == null) {
--                if (super.getContentLength() > sizeLimit) {
--                    throw new StreamBoundException("Resource size exceeds limit.");
--                }
--                stream = new DelegatingServletInputStream(new BoundedInputStream(super.getInputStream(), sizeLimit, super.getHeader("Content-Location")));
--            }
--            return stream;
--        }
--    }
--
--}
-diff --git a/src/nu/validator/servlet/ListErrorHandler.java b/src/nu/validator/servlet/ListErrorHandler.java
-deleted file mode 100644
-index 90bb994..0000000
---- a/src/nu/validator/servlet/ListErrorHandler.java
-+++ /dev/null
-@@ -1,66 +0,0 @@
--/*
-- * Copyright (c) 2007 Henri Sivonen
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.util.LinkedList;
--
--import org.xml.sax.ErrorHandler;
--import org.xml.sax.SAXException;
--import org.xml.sax.SAXParseException;
--
--public class ListErrorHandler implements ErrorHandler {
--
--    private boolean fatal = false;
--    
--    private LinkedList<String> errors = new LinkedList<String>();
--    
--    public void error(SAXParseException spe) throws SAXException {
--        errors.add(Integer.toString(spe.getColumnNumber()) + ": " + spe.getMessage());
--    }
--
--    public void fatalError(SAXParseException arg0) throws SAXException {
--        fatal = true;
--    }
--
--    public void warning(SAXParseException arg0) throws SAXException {
--    }
--
--    /**
--     * Returns the errors.
--     * 
--     * @return the errors
--     */
--    public LinkedList<String> getErrors() {
--        return errors;
--    }
--
--    /**
--     * Returns the fatal.
--     * 
--     * @return the fatal
--     */
--    public boolean isFatal() {
--        return fatal;
--    }
--
--}
-diff --git a/src/nu/validator/servlet/Main.java b/src/nu/validator/servlet/Main.java
-deleted file mode 100644
-index 631e57b..0000000
---- a/src/nu/validator/servlet/Main.java
-+++ /dev/null
-@@ -1,121 +0,0 @@
--/*
-- * Copyright (c) 2005 Henri Sivonen
-- * Copyright (c) 2007-2015 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.io.InputStream;
--import java.io.OutputStream;
--import java.net.ConnectException;
--import java.net.InetAddress;
--import java.net.ServerSocket;
--import java.net.Socket;
--import java.util.EnumSet;
--
--import javax.servlet.DispatcherType;
--
--import org.apache.log4j.PropertyConfigurator;
--import org.eclipse.jetty.server.Connector;
--import org.eclipse.jetty.server.HttpConfiguration;
--import org.eclipse.jetty.server.HttpConnectionFactory;
--import org.eclipse.jetty.server.Server;
--import org.eclipse.jetty.server.ServerConnector;
--import org.eclipse.jetty.servlet.ServletContextHandler;
--import org.eclipse.jetty.servlet.FilterHolder;
--import org.eclipse.jetty.servlet.ServletHolder;
--import org.eclipse.jetty.servlets.GzipFilter;
--import org.eclipse.jetty.util.thread.QueuedThreadPool;
--
--/**
-- * @version $Id$
-- * @author hsivonen
-- */
--public class Main {
--
--    private static final long SIZE_LIMIT = Integer.parseInt(System.getProperty(
--            "nu.validator.servlet.max-file-size", "2097152"));
--
--    public static void main(String[] args) throws Exception {
--        if (!"1".equals(System.getProperty("nu.validator.servlet.read-local-log4j-properties"))) {
--            PropertyConfigurator.configure(Main.class.getClassLoader().getResource(
--                    "nu/validator/localentities/files/log4j.properties"));
--        } else {
--            PropertyConfigurator.configure(System.getProperty(
--                    "nu.validator.servlet.log4j-properties", "log4j.properties"));
--        }
--
--        ServletContextHandler contextHandler = new ServletContextHandler();
--        contextHandler.setContextPath("/");
--        contextHandler.addFilter(new FilterHolder(new GzipFilter()), "/*",
--                EnumSet.of(DispatcherType.REQUEST));
--        contextHandler.addFilter(new FilterHolder(new InboundSizeLimitFilter(
--                SIZE_LIMIT)), "/*", EnumSet.of(DispatcherType.REQUEST));
--        contextHandler.addFilter(new FilterHolder(new InboundGzipFilter()),
--                "/*", EnumSet.of(DispatcherType.REQUEST));
--        contextHandler.addFilter(
--                new FilterHolder(new MultipartFormDataFilter()), "/*",
--                EnumSet.of(DispatcherType.REQUEST));
--        contextHandler.addServlet(new ServletHolder(new VerifierServlet()),
--                "/*");
--
--        Server server = new Server(new QueuedThreadPool(100));
--        server.setHandler(contextHandler);
--
--        ServerConnector serverConnector = new ServerConnector(server,
--                new HttpConnectionFactory(new HttpConfiguration()));
--        int port = args.length > 0 ? Integer.parseInt(args[0]) : 8888;
--        serverConnector.setPort(port);
--        server.setConnectors(new Connector[] { serverConnector });
--
--        int stopPort = -1;
--        if (args.length > 1) {
--            stopPort = Integer.parseInt(args[1]);
--        }
--        if (stopPort != -1) {
--            try {
--                Socket clientSocket = new Socket(
--                        InetAddress.getByName("127.0.0.1"), stopPort);
--                InputStream in = clientSocket.getInputStream();
--                in.read();
--                in.close();
--                clientSocket.close();
--            } catch (ConnectException e) {
--
--            }
--
--            server.start();
--
--            ServerSocket serverSocket = new ServerSocket(stopPort, 0,
--                    InetAddress.getByName("127.0.0.1"));
--            Socket s = serverSocket.accept();
--
--            server.stop();
--
--            OutputStream out = s.getOutputStream();
--            out.close();
--            s.close();
--            serverSocket.close();
--        } else {
--            server.start();
--        }
--    }
--}
-diff --git a/src/nu/validator/servlet/MultipartFormDataFilter.java b/src/nu/validator/servlet/MultipartFormDataFilter.java
-deleted file mode 100644
-index 4c976ab..0000000
---- a/src/nu/validator/servlet/MultipartFormDataFilter.java
-+++ /dev/null
-@@ -1,400 +0,0 @@
--/*
-- * Copyright (c) 2007-2015 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.io.BufferedReader;
--import java.io.ByteArrayInputStream;
--import java.io.IOException;
--import java.io.InputStream;
--import java.io.InputStreamReader;
--import java.io.Reader;
--import java.nio.charset.CharacterCodingException;
--import java.nio.charset.Charset;
--import java.nio.charset.CharsetDecoder;
--import java.nio.charset.CodingErrorAction;
--import java.util.ArrayList;
--import java.util.Collections;
--import java.util.Enumeration;
--import java.util.HashMap;
--import java.util.List;
--import java.util.Map;
--import java.util.regex.Matcher;
--import java.util.regex.Pattern;
--
--import javax.servlet.Filter;
--import javax.servlet.FilterChain;
--import javax.servlet.FilterConfig;
--import javax.servlet.ServletException;
--import javax.servlet.ServletInputStream;
--import javax.servlet.ServletRequest;
--import javax.servlet.ServletResponse;
--import javax.servlet.http.HttpServletRequest;
--import javax.servlet.http.HttpServletRequestWrapper;
--import javax.servlet.http.HttpServletResponse;
--
--import org.apache.commons.fileupload.FileItemIterator;
--import org.apache.commons.fileupload.FileItemStream;
--import org.apache.commons.fileupload.FileUploadException;
--import org.apache.commons.fileupload.servlet.ServletFileUpload;
--
--public final class MultipartFormDataFilter implements Filter {
--
--    private static Pattern EXTENSION = Pattern.compile("^.*\\.(.+)$");
--
--    private final static Map<String, String> EXTENSION_TO_TYPE = new HashMap<String, String>();
--
--    static {
--        EXTENSION_TO_TYPE.put("html", "text/html");
--        EXTENSION_TO_TYPE.put("htm", "text/html");
--        EXTENSION_TO_TYPE.put("xhtml", "application/xhtml+xml");
--        EXTENSION_TO_TYPE.put("xht", "application/xhtml+xml");
--        EXTENSION_TO_TYPE.put("atom", "application/atom+xml");
--        EXTENSION_TO_TYPE.put("rng", "application/xml");
--        EXTENSION_TO_TYPE.put("xsl", "application/xml");
--        EXTENSION_TO_TYPE.put("xml", "application/xml");
--        EXTENSION_TO_TYPE.put("dbk", "application/xml");
--        EXTENSION_TO_TYPE.put("csl", "application/xml");
--    }
--
--    private static String utf8ByteStreamToString(InputStream stream)
--            throws IOException {
--        CharsetDecoder dec = Charset.forName("UTF-8").newDecoder();
--        dec.onMalformedInput(CodingErrorAction.REPORT);
--        dec.onUnmappableCharacter(CodingErrorAction.REPORT);
--        Reader reader = new InputStreamReader(stream, dec);
--        StringBuilder builder = new StringBuilder();
--        int c;
--        int i = 0;
--        while ((c = reader.read()) != -1) {
--            if (i > 2048) {
--                throw new IOException("Form field value too large.");
--            }
--            builder.append((char) c);
--            i++;
--        }
--        return builder.toString();
--    }
--
--    private static void putParam(Map<String, String[]> params, String key,
--            String value) {
--        String[] oldVal = params.get(key);
--        if (oldVal == null) {
--            String[] arr = new String[1];
--            arr[0] = value;
--            params.put(key, arr);
--        } else {
--            for (int i = 0; i < oldVal.length; i++) {
--                String string = oldVal[i];
--                if (string.equals(value)) {
--                    return;
--                }
--            }
--            String[] arr = new String[oldVal.length + 1];
--            System.arraycopy(oldVal, 0, arr, 0, oldVal.length);
--            arr[oldVal.length] = value;
--            params.put(key, arr);
--        }
--    }
--
--    public void destroy() {
--    }
--
--    public void doFilter(ServletRequest req, ServletResponse res,
--            FilterChain chain) throws IOException, ServletException {
--        HttpServletRequest request = (HttpServletRequest) req;
--        HttpServletResponse response = (HttpServletResponse) res;
--        if (ServletFileUpload.isMultipartContent(request)) {
--            try {
--                boolean utf8 = false;
--                String contentType = null;
--                Map<String, String[]> params = new HashMap<String, String[]>();
--                InputStream fileStream = null;
--                ServletFileUpload upload = new ServletFileUpload();
--                FileItemIterator iter = upload.getItemIterator(request);
--                while (iter.hasNext()) {
--                    FileItemStream fileItemStream = iter.next();
--                    if (fileItemStream.isFormField()) {
--                        String fieldName = fileItemStream.getFieldName();
--                        if ("content".equals(fieldName)) {
--                            utf8 = true;
--                            String[] parser = params.get("parser");
--                            if (parser != null && parser[0].startsWith("xml")) {
--                                contentType = "application/xml";
--                            } else {
--                                contentType = "text/html";
--                            }
--                            request.setAttribute("nu.validator.servlet.MultipartFormDataFilter.type", "textarea");
--                            fileStream = fileItemStream.openStream();
--                            break;
--                        } else {
--                            putParam(
--                                    params,
--                                    fieldName,
--                                    utf8ByteStreamToString(fileItemStream.openStream()));
--                        }
--                    } else {
--                        String fileName = fileItemStream.getName();
--                        if (fileName != null) {
--                            putParam(params, fileItemStream.getFieldName(),
--                                    fileName);
--                            request.setAttribute(
--                                    "nu.validator.servlet.MultipartFormDataFilter.filename",
--                                    fileName);
--                            Matcher m = EXTENSION.matcher(fileName);
--                            if (m.matches()) {
--                                contentType = EXTENSION_TO_TYPE.get(m.group(1));
--                            }
--                        }
--                        if (contentType == null) {
--                            contentType = fileItemStream.getContentType();
--                        }
--                        request.setAttribute("nu.validator.servlet.MultipartFormDataFilter.type", "file");
--                        fileStream = fileItemStream.openStream();
--                        break;
--                    }
--                }
--                if (fileStream == null) {
--                    fileStream = new ByteArrayInputStream(new byte[0]);
--                }
--                if (contentType == null) {
--                    contentType = "application/octet-stream";
--                }
--                chain.doFilter(new RequestWrapper(request, params, contentType,
--                        utf8, fileStream), response);
--            } catch (FileUploadException e) {
--                response.sendError(415, e.getMessage());
--            } catch (CharacterCodingException e) {
--                response.sendError(415, e.getMessage());
--            } catch (IOException e) {
--                response.sendError(HttpServletResponse.SC_BAD_REQUEST,
--                        e.getMessage());
--            }
--        } else {
--            chain.doFilter(req, res);
--        }
--    }
--
--    public void init(FilterConfig arg0) throws ServletException {
--    }
--
--    private final class RequestWrapper extends HttpServletRequestWrapper {
--
--        private final Map<String, String[]> params;
--
--        private final String contentType;
--
--        private final boolean utf8;
--
--        private final ServletInputStream stream;
--
--        public RequestWrapper(HttpServletRequest req,
--                Map<String, String[]> params, String contentType, boolean utf8,
--                InputStream stream) {
--            super(req);
--            this.params = Collections.unmodifiableMap(params);
--            this.contentType = contentType;
--            this.utf8 = utf8;
--            this.stream = new DelegatingServletInputStream(stream);
--        }
--
--        /**
--         * @see javax.servlet.http.HttpServletRequestWrapper#getDateHeader(java.lang.String)
--         */
--        @Override
--        public long getDateHeader(String name) {
--            if ("Content-Length".equalsIgnoreCase(name)) {
--                return -1;
--            } else if ("Content-MD5".equalsIgnoreCase(name)) {
--                return -1;
--            } else if ("Content-Encoding".equalsIgnoreCase(name)) {
--                return -1;
--            } else if ("Content-Type".equalsIgnoreCase(name)) {
--                return -1;
--            } else {
--                return super.getDateHeader(name);
--            }
--        }
--
--        /**
--         * @see javax.servlet.http.HttpServletRequestWrapper#getHeader(java.lang.String)
--         */
--        @Override
--        public String getHeader(String name) {
--            if ("Content-Length".equalsIgnoreCase(name)) {
--                return null;
--            } else if ("Content-MD5".equalsIgnoreCase(name)) {
--                return null;
--            } else if ("Content-Encoding".equalsIgnoreCase(name)) {
--                return null;
--            } else if ("Content-Type".equalsIgnoreCase(name)) {
--                return getContentType();
--            } else {
--                return super.getHeader(name);
--            }
--        }
--
--        /**
--         * @see javax.servlet.http.HttpServletRequestWrapper#getHeaderNames()
--         */
--        @Override
--        public Enumeration getHeaderNames() {
--            Enumeration e = super.getHeaderNames();
--            List<String> list = new ArrayList<String>();
--            while (e.hasMoreElements()) {
--                String name = (String) e.nextElement();
--                if ("Content-Length".equalsIgnoreCase(name)) {
--                    continue;
--                } else if ("Content-MD5".equalsIgnoreCase(name)) {
--                    continue;
--                } else if ("Content-Encoding".equalsIgnoreCase(name)) {
--                    continue;
--                } else if ("Content-Type".equalsIgnoreCase(name)) {
--                    list.add(getContentType());
--                } else {
--                    list.add(name);
--                }
--            }
--            return Collections.enumeration(list);
--        }
--
--        /**
--         * @see javax.servlet.http.HttpServletRequestWrapper#getHeaders(java.lang.String)
--         */
--        @SuppressWarnings("unchecked")
--        @Override
--        public Enumeration getHeaders(String name) {
--            if ("Content-Length".equalsIgnoreCase(name)) {
--                return Collections.enumeration(Collections.EMPTY_SET);
--            } else if ("Content-MD5".equalsIgnoreCase(name)) {
--                return Collections.enumeration(Collections.EMPTY_SET);
--            } else if ("Content-Encoding".equalsIgnoreCase(name)) {
--                return Collections.enumeration(Collections.EMPTY_SET);
--            } else if ("Content-Type".equalsIgnoreCase(name)) {
--                return Collections.enumeration(Collections.singleton(getContentType()));
--            } else {
--                return super.getHeaders(name);
--            }
--        }
--
--        /**
--         * @see javax.servlet.http.HttpServletRequestWrapper#getIntHeader(java.lang.String)
--         */
--        @Override
--        public int getIntHeader(String name) {
--            if ("Content-Length".equalsIgnoreCase(name)) {
--                return -1;
--            } else if ("Content-MD5".equalsIgnoreCase(name)) {
--                return -1;
--            } else if ("Content-Encoding".equalsIgnoreCase(name)) {
--                return -1;
--            } else if ("Content-Type".equalsIgnoreCase(name)) {
--                return -1;
--            } else {
--                return super.getIntHeader(name);
--            }
--        }
--
--        /**
--         * @see javax.servlet.ServletRequestWrapper#getCharacterEncoding()
--         */
--        @Override
--        public String getCharacterEncoding() {
--            return utf8 ? "utf-8" : null;
--        }
--
--        /**
--         * @see javax.servlet.ServletRequestWrapper#getContentLength()
--         */
--        @Override
--        public int getContentLength() {
--            return -1;
--        }
--
--        /**
--         * @see javax.servlet.ServletRequestWrapper#getContentType()
--         */
--        @Override
--        public String getContentType() {
--            return utf8 ? contentType + "; charset=utf-8" : contentType;
--        }
--
--        /**
--         * @see javax.servlet.ServletRequestWrapper#getInputStream()
--         */
--        @Override
--        public ServletInputStream getInputStream() throws IOException {
--            return stream;
--        }
--
--        /**
--         * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String)
--         */
--        @Override
--        public String getParameter(String key) {
--            String[] arr = params.get(key);
--            if (arr == null) {
--                return null;
--            } else {
--                return arr[0];
--            }
--        }
--
--        /**
--         * @see javax.servlet.ServletRequestWrapper#getParameterMap()
--         */
--        @Override
--        public Map getParameterMap() {
--            return params;
--        }
--
--        /**
--         * @see javax.servlet.ServletRequestWrapper#getParameterNames()
--         */
--        @Override
--        public Enumeration getParameterNames() {
--            return Collections.enumeration(params.keySet());
--        }
--
--        /**
--         * @see javax.servlet.ServletRequestWrapper#getParameterValues(java.lang.String)
--         */
--        @Override
--        public String[] getParameterValues(String key) {
--            return params.get(key);
--        }
--
--        /**
--         * @see javax.servlet.ServletRequestWrapper#getReader()
--         */
--        @Override
--        public BufferedReader getReader() throws IOException {
--            CharsetDecoder dec = Charset.forName("UTF-8").newDecoder();
--            dec.onMalformedInput(CodingErrorAction.REPORT);
--            dec.onUnmappableCharacter(CodingErrorAction.REPORT);
--            Reader reader = new InputStreamReader(stream, dec);
--            return new BufferedReader(reader);
--        }
--
--    }
--
--}
-diff --git a/src/nu/validator/servlet/NsFilterEmitter.java b/src/nu/validator/servlet/NsFilterEmitter.java
-deleted file mode 100644
-index d9e23be..0000000
---- a/src/nu/validator/servlet/NsFilterEmitter.java
-+++ /dev/null
-@@ -1,33 +0,0 @@
--/* This code was generated by nu.validator.tools.SaxCompiler. Please regenerate instead of editing. */
--package nu.validator.servlet;
--public final class NsFilterEmitter {
--private NsFilterEmitter() {}
--public static void emit(org.xml.sax.ContentHandler contentHandler, nu.validator.servlet.VerifierServletTransaction t) throws org.xml.sax.SAXException {
--org.xml.sax.helpers.AttributesImpl __attrs__ = new org.xml.sax.helpers.AttributesImpl();
--contentHandler.startPrefixMapping("", "http://www.w3.org/1999/xhtml");
--__attrs__.clear();
--__attrs__.addAttribute("", "title", "title", "CDATA", "Space-separated list of namespace URIs.");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "tr", "tr", __attrs__);
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "th", "th", __attrs__);
--__attrs__.clear();
--__attrs__.addAttribute("", "for", "for", "CDATA", "nsfilter");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "label", "label", __attrs__);
--__attrs__.clear();
--__attrs__.addAttribute("", "title", "title", "CDATA", "XML namespace");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "abbr", "abbr", __attrs__);
--contentHandler.characters(__chars__, 0, 5);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "abbr", "abbr");
--contentHandler.characters(__chars__, 5, 1);
--contentHandler.characters(__chars__, 6, 6);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "label", "label");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "th", "th");
--__attrs__.clear();
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "td", "td", __attrs__);
--t.emitNsfilterField(); 
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "td", "td");
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "tr", "tr");
--contentHandler.endPrefixMapping("");
--}
--private static final char[] __chars__ = { 'X', 'M', 'L', 'N', 'S', '\u00a0', 'F', 'i', 'l', 't', 'e', 'r' };
--}
-diff --git a/src/nu/validator/servlet/OutlineBuildingXMLReaderWrapper.java b/src/nu/validator/servlet/OutlineBuildingXMLReaderWrapper.java
-deleted file mode 100644
-index a22b654..0000000
---- a/src/nu/validator/servlet/OutlineBuildingXMLReaderWrapper.java
-+++ /dev/null
-@@ -1,847 +0,0 @@
--/*
-- * Copyright (c) 2012 Vadim Zaslawski, Ontos AG
-- * Copyright (c) 2012-2014 Mozilla Foundation
-- *
-- * 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.
-- *
-- * This code contains comments that are verbatim quotations from the
-- * document "HTML: The Living Standard", which has the following copyright
-- * and permission notice:
-- *
-- *   Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
-- *   Opera Software ASA. You are granted a license to use, reproduce and
-- *   create derivative works of this document.
-- */
--
--package nu.validator.servlet;
--
--import java.io.IOException;
--import java.util.Arrays;
--import java.util.Deque;
--import java.util.LinkedList;
--import java.util.regex.Pattern;
--
--import javax.servlet.http.HttpServletRequest;
--
--import org.xml.sax.Attributes;
--import org.xml.sax.ContentHandler;
--import org.xml.sax.DTDHandler;
--import org.xml.sax.EntityResolver;
--import org.xml.sax.ErrorHandler;
--import org.xml.sax.InputSource;
--import org.xml.sax.Locator;
--import org.xml.sax.SAXException;
--import org.xml.sax.SAXNotRecognizedException;
--import org.xml.sax.SAXNotSupportedException;
--import org.xml.sax.XMLReader;
--
--public final class OutlineBuildingXMLReaderWrapper implements XMLReader,
--        ContentHandler {
--
--    private final XMLReader wrappedReader;
--
--    private final HttpServletRequest request;
--
--    private ContentHandler contentHandler;
--
--    public OutlineBuildingXMLReaderWrapper(XMLReader wrappedReader,
--            HttpServletRequest request) {
--        this.request = request;
--        this.wrappedReader = wrappedReader;
--        this.contentHandler = wrappedReader.getContentHandler();
--        wrappedReader.setContentHandler(this);
--    }
--
--    private static final int MAX_EXCERPT = 500;
--
--    private static final String[] SECTIONING_CONTENT_ELEMENTS = { "article",
--            "aside", "nav", "section" };
--
--    private static final String[] SECTIONING_ROOT_ELEMENTS = { "blockquote",
--            "body", "details", "fieldset", "figure", "td" };
--
--    private static final String[] HEADING_CONTENT_ELEMENTS = { "h1", "h2",
--            "h3", "h4", "h5", "h6", "hgroup", };
--
--    private Deque<Section> outline;
--
--    public Deque<Section> getOutline() {
--        return this.outline;
--    }
--
--    protected void setOutline(Deque<Section> outline) {
--        this.outline = outline;
--    }
--
--    // an outlinee, a heading content element, or an element with a hidden
--    // attribute;
--    // during a walk over the nodes of a DOM tree, nodes are identified with
--    // their depth and local name
--    private class Element {
--        // the depth of element in the DOM
--        final private int depth;
--
--        // the local name of element
--        final private String name;
--
--        // whether the element is hidden
--        final private boolean hidden;
--
--        // the outline for a sectioning content element or a sectioning root
--        // element consists of a list of one or more potentially nested sections
--        final private Deque<Section> outline = new LinkedList<Section>();
--
--        public Element(int depth, String name, boolean hidden) {
--            this.depth = depth;
--            this.name = name;
--            this.hidden = hidden;
--        }
--
--        public boolean isHidden() {
--            return hidden;
--        }
--
--        public boolean equals(int depth, String name) {
--            return this.depth == depth && this.name.equals(name);
--        }
--
--        /**
--         * @return the outline
--         */
--        public Deque<Section> getOutline() {
--            return outline;
--        }
--
--        /**
--         * @return 1-6 for a heading content element MAX_VALUE for an implied
--         *         heading -1 for no section
--         */
--        public int getLastSectionHeadingRank() {
--            Section section = outline.peekLast();
--            return section != null ? section.getHeadingRank() : -1;
--        }
--    }
--
--    // a section is a container that corresponds to some nodes in the original
--    // DOM tree
--    public class Section {
--        // the section that contains this section
--        private Section parent;
--
--        // an outlinee or a heading content element
--        final String elementName;
--
--        // each section can have one heading associated with it
--        final private StringBuilder headingTextBuilder = new StringBuilder();
--
--        // we generate an "implied heading" for some sections that lack headings
--        private boolean hasImpliedHeading;
--
--        // Generating a special kind of implied heading specifically for
--        // the "empty heading" case (e.g., empty <h1></h1> descendant) as
--        // opposed to the "no heading" case (no h1-h6 descendants at all)
--        // isn't required by the spec, but it's nonetheless useful.
--        private boolean hasEmptyHeading;
--
--        // MAX_VALUE for an implied heading, 1-6 for a heading content element
--        private int headingRank = Integer.MAX_VALUE;
--
--        // each section can contain any number of further nested sections
--        final public Deque<Section> sections = new LinkedList<Section>();
--
--        public Section(String elementName) {
--            this.elementName = elementName;
--        }
--
--        /**
--         * @return the parent section
--         */
--        public Section getParent() {
--            return parent;
--        }
--
--        /**
--         * @return the lement name
--         */
--        public String getElementName() {
--            return elementName;
--        }
--
--        /**
--         * @param parent
--         *            the parent section to set
--         */
--        public void setParent(Section parent) {
--            this.parent = parent;
--        }
--
--        /**
--         * @return the heading text builder
--         */
--        public StringBuilder getHeadingTextBuilder() {
--            return headingTextBuilder;
--        }
--
--        /**
--         * @return the heading rank
--         */
--        public int getHeadingRank() {
--            return headingRank;
--        }
--
--        /**
--         * @return the sections
--         */
--        public Deque<Section> getSections() {
--            return sections;
--        }
--
--        public void setHeadingRank(int headingRank) {
--            this.headingRank = headingRank;
--        }
--
--        public boolean hasHeading() {
--            return headingRank < 7 || hasImpliedHeading;
--        }
--
--        public void createImpliedHeading() {
--            hasImpliedHeading = true;
--        }
--
--        public void createEmptyHeading() {
--            hasEmptyHeading = true;
--        }
--
--        public boolean hasEmptyHeading() {
--            return hasEmptyHeading;
--        }
--    }
--
--    // tracks the depth of walk through the DOM
--    private int currentWalkDepth;
--
--    // holds the element whose outline is being created;
--    // a sectioning content element or a sectioning root element
--    private Element currentOutlinee;
--
--    // A stack (not defined in the spec) to hold all open elements. We just
--    // use this stack for the purpose of checking whether there are any
--    // open elements at all with a "hidden" attribute -- including elements
--    // that may be descendants of heading-content elements (which per the
--    // spec never end up on the outline stack).
--    private Deque<Element> elementStack = new LinkedList<Element>();
--
--    private boolean inHiddenSubtree() {
--        for (Element element : elementStack) {
--            if (element.isHidden()) {
--                return true;
--            }
--        }
--        return false;
--    }
--
--    // A stack, defined in the spec, to which we only add open
--    // heading-content elements and elements with a "hidden" attribute that
--    // are ancestors to heading-content elements.
--    private Deque<Element> outlineStack = new LinkedList<Element>();
--
--    // The top of the outline stack defined in the spec is always either a
--    // heading content element or an element with a hidden attribute.
--    private boolean inHeadingContentOrHiddenElement;
--
--    private boolean needHeading;
--
--    private boolean skipHeading;
--
--    // holds a pointer to a section, so that elements in the DOM can all be
--    // associated with a section
--    private Section currentSection;
--
--    private boolean isWalkOver;
--
--    private static final Pattern excerptPattern = Pattern.compile("\\W*\\S*$");
--
--    private static final Pattern whitespacePattern = Pattern.compile("\\s+");
--
--    /*
--     * Returns the string excerpt.
--     */
--    private String excerpt(String str, int maxLength) {
--        return str.length() > maxLength ? excerptPattern.matcher(
--                str.substring(0, maxLength)).replaceFirst("&hellip;") : str;
--    }
--
--    /**
--     * @see org.xml.sax.helpers.XMLFilterImpl#characters(char[], int, int)
--     */
--    public void characters(char[] ch, int start, int length)
--            throws SAXException {
--        if (contentHandler == null) {
--            return;
--        }
--        if (isWalkOver) {
--            contentHandler.characters(ch, start, length);
--            return;
--        }
--
--        if (inHeadingContentOrHiddenElement && !inHiddenSubtree()) {
--            currentSection.getHeadingTextBuilder().append(ch, start, length);
--        }
--        contentHandler.characters(ch, start, length);
--    }
--
--    /**
--     * @see org.xml.sax.helpers.XMLFilterImpl#endElement(java.lang.String,
--     *      java.lang.String, java.lang.String)
--     */
--    public void endElement(String uri, String localName, String qName)
--            throws SAXException {
--        if (contentHandler == null) {
--            return;
--        }
--        elementStack.pop();
--        if ("hgroup".equals(localName)) {
--            needHeading = false;
--            skipHeading = false;
--        }
--        if (isWalkOver) {
--            contentHandler.endElement(uri, localName, qName);
--            return;
--        }
--
--        int depth = currentWalkDepth--;
--
--        if (inHeadingContentOrHiddenElement) {
--            // When exiting an element, if that element is the element at the
--            // top of the stack
--            // Note: The element being exited is a heading content element or an
--            // element with a hidden attribute.
--            Element topElement = outlineStack.peek();
--            assert topElement != null;
--            if (topElement.equals(depth, localName)) {
--                // Pop that element from the stack.
--                outlineStack.pop();
--                inHeadingContentOrHiddenElement = false;
--
--                if (currentSection != null) {
--                    StringBuilder headingTextBuilder = currentSection.getHeadingTextBuilder();
--                    String heading = excerpt(
--                            whitespacePattern.matcher(headingTextBuilder).replaceAll(
--                                    " ").trim(), MAX_EXCERPT);
--                    headingTextBuilder.setLength(0);
--                    if (heading.length() > 0) {
--                        headingTextBuilder.append(heading);
--                    } else {
--                        currentSection.createEmptyHeading();
--                    }
--                }
--            }
--
--            // If the top of the stack is a heading content element or an
--            // element with a hidden attribute
--            // Do nothing.
--            contentHandler.endElement(uri, localName, qName);
--            return;
--        }
--
--        if (Arrays.binarySearch(SECTIONING_CONTENT_ELEMENTS, localName) > -1) {
--            // When exiting a sectioning content element, if the stack is not
--            // empty
--            if (!outlineStack.isEmpty()) {
--                // If the current section has no heading,
--                if (currentSection != null && !currentSection.hasHeading()) {
--                    // create an implied heading and let that be the heading for
--                    // the current section.
--                    currentSection.createImpliedHeading();
--                }
--                Element exitedSectioningContentElement = currentOutlinee;
--                assert exitedSectioningContentElement != null;
--
--                // Pop the top element from the stack, and let the current
--                // outlinee be that element.
--                currentOutlinee = outlineStack.pop();
--
--                // Let current section be the last section in the outline of the
--                // current outlinee element.
--                currentSection = currentOutlinee.getOutline().peekLast();
--                assert currentSection != null;
--
--                // Append the outline of the sectioning content element being
--                // exited to the current section.
--                // (This does not change which section is the last section in
--                // the outline.)
--                for (Section section : exitedSectioningContentElement.outline) {
--                    section.setParent(currentSection);
--                    currentSection.sections.add(section);
--                }
--            }
--        } else if (Arrays.binarySearch(SECTIONING_ROOT_ELEMENTS, localName) > -1) {
--            // When exiting a sectioning root element, if the stack is not empty
--            if (!outlineStack.isEmpty()) {
--                // Run these steps:
--
--                // If the current section has no heading,
--                if (currentSection != null && !currentSection.hasHeading()) {
--                    // create an implied heading and let that be the heading for
--                    // the current section.
--                    currentSection.createImpliedHeading();
--                }
--
--                // Pop the top element from the stack, and let the current
--                // outlinee be that element.
--                currentOutlinee = outlineStack.pop();
--
--                // Let current section be the last section in the outline of the
--                // current outlinee element.
--                currentSection = currentOutlinee.getOutline().peekLast();
--
--                // Finding the deepest child:
--                // If current section has no child sections, stop these steps.
--                while (!currentSection.sections.isEmpty())
--                    // Let current section be the last child section of the
--                    // current current section.
--                    currentSection = currentSection.sections.peekLast();
--                // Go back to the substep labeled finding the deepest child.
--            }
--        } else {
--            // neither a sectioning content element nor a sectioning root
--            // element
--            contentHandler.endElement(uri, localName, qName);
--            return;
--        }
--
--        // When exiting a sectioning content element or a sectioning root
--        // element
--        // Note: The current outlinee is the element being exited, and
--        // it is the sectioning content element or a sectioning root element at
--        // the root of the subtree for which an outline is being generated.
--
--        // If the current section has no heading,
--        if (currentSection != null && !currentSection.hasHeading()) {
--            // create an implied heading and let that be the heading for the
--            // current section.
--            currentSection.createImpliedHeading();
--        }
--
--        // Skip to the next step in the overall set of steps.
--        // (The walk is over.)
--        // / isWalkOver = true;
--
--        contentHandler.endElement(uri, localName, qName);
--    }
--
--    /**
--     * @see org.xml.sax.helpers.XMLFilterImpl#startDocument()
--     */
--    public void startDocument() throws SAXException {
--        if (contentHandler == null) {
--            return;
--        }
--        contentHandler.startDocument();
--    }
--
--    /**
--     * @see org.xml.sax.helpers.XMLFilterImpl#startElement(java.lang.String,
--     *      java.lang.String, java.lang.String, org.xml.sax.Attributes)
--     */
--    public void startElement(String uri, String localName, String qName,
--            Attributes atts) throws SAXException {
--        if (contentHandler == null) {
--            return;
--        }
--        if (isWalkOver) {
--            contentHandler.startElement(uri, localName, qName, atts);
--            return;
--        }
--
--        ++currentWalkDepth;
--
--        boolean hidden = atts.getIndex("", "hidden") >= 0;
--        elementStack.push(new Element(currentWalkDepth, localName, hidden));
--
--        // If the top of the stack is a heading content element or an element
--        // with a hidden attribute
--        if (inHeadingContentOrHiddenElement) {
--            if (!inHiddenSubtree() && "img".equals(localName)
--                    && atts.getIndex("", "alt") >= 0) {
--                currentSection.getHeadingTextBuilder().append(
--                        atts.getValue("", "alt"));
--            }
--            // Do nothing.
--            contentHandler.startElement(uri, localName, qName, atts);
--            return;
--        }
--
--        // When entering an element with a hidden attribute
--        if (hidden) {
--            // Push the element being entered onto the stack. (This causes the
--            // algorithm to skip that element and any descendants of the
--            // element.)
--            outlineStack.push(new Element(currentWalkDepth, localName, hidden));
--            inHeadingContentOrHiddenElement = true;
--            contentHandler.startElement(uri, localName, qName, atts);
--            return;
--        }
--
--        // When entering a sectioning content element or a sectioning root
--        // element
--        if (Arrays.binarySearch(SECTIONING_CONTENT_ELEMENTS, localName) > -1
--                || Arrays.binarySearch(SECTIONING_ROOT_ELEMENTS, localName) > -1) {
--            if (currentOutlinee != null) {
--                // If current outlinee is not null, and the current section has
--                // no heading,
--                // create an implied heading and let that be the heading for the
--                // current section.
--                if (currentSection != null && !currentSection.hasHeading()) {
--                    currentSection.createImpliedHeading();
--                }
--                // If current outlinee is not null, push current outlinee onto
--                // the stack.
--                outlineStack.push(currentOutlinee);
--            }
--
--            // Let current outlinee be the element that is being entered.
--            currentOutlinee = new Element(currentWalkDepth, localName, hidden);
--
--            // Let current section be a newly created section for the current
--            // outlinee element.
--            // Associate current outlinee with current section.
--            currentSection = new Section(localName);
--
--            // Let there be a new outline for the new current outlinee,
--            // initialized with just the new current section as the only section
--            // in the outline.
--            currentOutlinee.getOutline().add(currentSection);
--            contentHandler.startElement(uri, localName, qName, atts);
--            return;
--        }
--
--        // When entering a heading content element
--        // Note: Recall that h1 has the highest rank, and h6 has the lowest
--        // rank.
--        if (Arrays.binarySearch(HEADING_CONTENT_ELEMENTS, localName) > -1
--                && currentOutlinee != null) {
--            if ("hgroup".equals(localName)) {
--                needHeading = true;
--                skipHeading = false;
--                contentHandler.startElement(uri, localName, qName, atts);
--                return;
--            } else if (skipHeading) {
--                contentHandler.startElement(uri, localName, qName, atts);
--                return;
--            } else if (needHeading) {
--                skipHeading = true;
--                needHeading = false;
--            }
--            int rank = localName.charAt(1) - '0';
--
--            // If the current section has no heading,
--            // let the element being entered be the heading for the current
--            // section.
--            if (currentSection != null && !currentSection.hasHeading()) {
--                currentSection.setHeadingRank(rank);
--            }
--            // Otherwise, if the element being entered has a rank equal to
--            // or higher than the heading of the last section of the
--            // outline of the current outlinee, or if the heading of the
--            // last section of the outline of the current outlinee is an
--            // implied heading,
--            else if (rank <= currentOutlinee.getLastSectionHeadingRank()) {
--                // then create a new section and append it to the outline
--                // of the current outlinee element, so that this new
--                // section is the new last section of that outline.
--                // Let current section be that new section.
--                currentSection = new Section(localName);
--                currentOutlinee.getOutline().add(currentSection);
--
--                // Let the element being entered be the new heading for the
--                // current section.
--                currentSection.setHeadingRank(rank);
--            }
--            // Otherwise, run these substeps:
--            else {
--                // Let candidate section be current section.
--                Section candidateSection = currentSection;
--
--                // Heading loop:
--                while (candidateSection != null) {
--                    // If the element being entered has a rank lower than the
--                    // rank of the heading of the candidate section,
--                    if (rank > candidateSection.getHeadingRank()) {
--                        // then create a new section, and append it to candidate
--                        // section.
--                        // (This does not change which section is the last
--                        // section in the outline.)
--                        // Let current section be this new section.
--                        currentSection = new Section(localName);
--                        currentSection.setParent(candidateSection);
--                        candidateSection.getSections().add(currentSection);
--
--                        // Let the element being entered be the new heading for
--                        // the current section.
--                        currentSection.setHeadingRank(rank);
--
--                        // Abort these substeps.
--                        break;
--                    }
--
--                    // Let new candidate section be the section that contains
--                    // candidate section in the outline of current outlinee.
--                    // Let candidate section be new candidate section.
--                    candidateSection = candidateSection.getParent();
--
--                    // Return to the step labeled heading loop.
--                }
--            }
--
--            // Push the element being entered onto the stack.
--            // (This causes the algorithm to skip any descendants of the
--            // element.)
--            outlineStack.push(new Element(currentWalkDepth, localName, hidden));
--            inHeadingContentOrHiddenElement = true;
--        }
--        contentHandler.startElement(uri, localName, qName, atts);
--    }
--
--    /**
--     * @see org.xml.sax.helpers.XMLFilterImpl#setDocumentLocator(org.xml.sax.Locator)
--     */
--    public void setDocumentLocator(Locator locator) {
--        if (contentHandler == null) {
--            return;
--        }
--        contentHandler.setDocumentLocator(locator);
--    }
--
--    public ContentHandler getContentHandler() {
--        return contentHandler;
--    }
--
--    /**
--     * @throws SAXException
--     * @see org.xml.sax.ContentHandler#endDocument()
--     */
--    public void endDocument() throws SAXException {
--        if (contentHandler == null) {
--            return;
--        }
--        if (currentOutlinee != null) {
--            request.setAttribute(
--                    "http://validator.nu/properties/document-outline",
--                    (Deque<Section>) currentOutlinee.outline);
--            setOutline(currentOutlinee.outline);
--        }
--        contentHandler.endDocument();
--    }
--
--    /**
--     * @param prefix
--     * @throws SAXException
--     * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
--     */
--    public void endPrefixMapping(String prefix) throws SAXException {
--        if (contentHandler == null) {
--            return;
--        }
--        contentHandler.endPrefixMapping(prefix);
--    }
--
--    /**
--     * @param ch
--     * @param start
--     * @param length
--     * @throws SAXException
--     * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
--     */
--    public void ignorableWhitespace(char[] ch, int start, int length)
--            throws SAXException {
--        if (contentHandler == null) {
--            return;
--        }
--        contentHandler.ignorableWhitespace(ch, start, length);
--    }
--
--    /**
--     * @param target
--     * @param data
--     * @throws SAXException
--     * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String,
--     *      java.lang.String)
--     */
--    public void processingInstruction(String target, String data)
--            throws SAXException {
--        if (contentHandler == null) {
--            return;
--        }
--        contentHandler.processingInstruction(target, data);
--    }
--
--    /**
--     * @param name
--     * @throws SAXException
--     * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
--     */
--    public void skippedEntity(String name) throws SAXException {
--        if (contentHandler == null) {
--            return;
--        }
--        contentHandler.skippedEntity(name);
--    }
--
--    /**
--     * @param prefix
--     * @param uri
--     * @throws SAXException
--     * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String,
--     *      java.lang.String)
--     */
--    public void startPrefixMapping(String prefix, String uri)
--            throws SAXException {
--        if (contentHandler == null) {
--            return;
--        }
--        contentHandler.startPrefixMapping(prefix, uri);
--    }
--
--    /**
--     * @return
--     * @see org.xml.sax.XMLReader#getDTDHandler()
--     */
--    public DTDHandler getDTDHandler() {
--        return wrappedReader.getDTDHandler();
--    }
--
--    /**
--     * @return
--     * @see org.xml.sax.XMLReader#getEntityResolver()
--     */
--    public EntityResolver getEntityResolver() {
--        return wrappedReader.getEntityResolver();
--    }
--
--    /**
--     * @return
--     * @see org.xml.sax.XMLReader#getErrorHandler()
--     */
--    public ErrorHandler getErrorHandler() {
--        return wrappedReader.getErrorHandler();
--    }
--
--    /**
--     * @param name
--     * @return
--     * @throws SAXNotRecognizedException
--     * @throws SAXNotSupportedException
--     * @see org.xml.sax.XMLReader#getFeature(java.lang.String)
--     */
--    public boolean getFeature(String name) throws SAXNotRecognizedException,
--            SAXNotSupportedException {
--        return wrappedReader.getFeature(name);
--    }
--
--    /**
--     * @param name
--     * @return
--     * @throws SAXNotRecognizedException
--     * @throws SAXNotSupportedException
--     * @see org.xml.sax.XMLReader#getProperty(java.lang.String)
--     */
--    public Object getProperty(String name) throws SAXNotRecognizedException,
--            SAXNotSupportedException {
--        return wrappedReader.getProperty(name);
--    }
--
--    /**
--     * @param input
--     * @throws IOException
--     * @throws SAXException
--     * @see org.xml.sax.XMLReader#parse(org.xml.sax.InputSource)
--     */
--    public void parse(InputSource input) throws IOException, SAXException {
--        wrappedReader.parse(input);
--    }
--
--    /**
--     * @param systemId
--     * @throws IOException
--     * @throws SAXException
--     * @see org.xml.sax.XMLReader#parse(java.lang.String)
--     */
--    public void parse(String systemId) throws IOException, SAXException {
--        wrappedReader.parse(systemId);
--    }
--
--    /**
--     * @param handler
--     * @see org.xml.sax.XMLReader#setContentHandler(org.xml.sax.ContentHandler)
--     */
--    public void setContentHandler(ContentHandler handler) {
--        contentHandler = handler;
--    }
--
--    /**
--     * @param handler
--     * @see org.xml.sax.XMLReader#setDTDHandler(org.xml.sax.DTDHandler)
--     */
--    public void setDTDHandler(DTDHandler handler) {
--        wrappedReader.setDTDHandler(handler);
--    }
--
--    /**
--     * @param resolver
--     * @see org.xml.sax.XMLReader#setEntityResolver(org.xml.sax.EntityResolver)
--     */
--    public void setEntityResolver(EntityResolver resolver) {
--        wrappedReader.setEntityResolver(resolver);
--    }
--
--    /**
--     * @param handler
--     * @see org.xml.sax.XMLReader#setErrorHandler(org.xml.sax.ErrorHandler)
--     */
--    public void setErrorHandler(ErrorHandler handler) {
--        wrappedReader.setErrorHandler(handler);
--    }
--
--    /**
--     * @param name
--     * @param value
--     * @throws SAXNotRecognizedException
--     * @throws SAXNotSupportedException
--     * @see org.xml.sax.XMLReader#setFeature(java.lang.String, boolean)
--     */
--    public void setFeature(String name, boolean value)
--            throws SAXNotRecognizedException, SAXNotSupportedException {
--        wrappedReader.setFeature(name, value);
--    }
--
--    /**
--     * @param name
--     * @param value
--     * @throws SAXNotRecognizedException
--     * @throws SAXNotSupportedException
--     * @see org.xml.sax.XMLReader#setProperty(java.lang.String,
--     *      java.lang.Object)
--     */
--    public void setProperty(String name, Object value)
--            throws SAXNotRecognizedException, SAXNotSupportedException {
--        wrappedReader.setProperty(name, value);
--    }
--
--}
-diff --git a/src/nu/validator/servlet/ParseTreePrinter.java b/src/nu/validator/servlet/ParseTreePrinter.java
-deleted file mode 100644
-index 4203c1c..0000000
---- a/src/nu/validator/servlet/ParseTreePrinter.java
-+++ /dev/null
-@@ -1,198 +0,0 @@
--/*
-- * Copyright (c) 2007-2015 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.io.IOException;
--import java.io.OutputStreamWriter;
--import java.io.StringReader;
--import java.io.Writer;
--
--import javax.servlet.http.HttpServletRequest;
--import javax.servlet.http.HttpServletResponse;
--
--import nu.validator.gnu.xml.aelfred2.SAXDriver;
--import nu.validator.htmlparser.common.Heuristics;
--import nu.validator.htmlparser.common.XmlViolationPolicy;
--import nu.validator.io.BoundedInputStream;
--import nu.validator.io.StreamBoundException;
--import nu.validator.xml.ContentTypeParser;
--import nu.validator.xml.NullEntityResolver;
--import nu.validator.xml.PrudentHttpEntityResolver;
--import nu.validator.xml.TypedInputSource;
--
--import org.xml.sax.SAXException;
--import org.xml.sax.XMLReader;
--
--import io.mola.galimatias.URL;
--import io.mola.galimatias.GalimatiasParseException;
--
--public class ParseTreePrinter {
--    
--    private static final String FORM_HTML = "<!DOCTYPE html><title>Parse Tree Dump</title><form><p><input type='url' name='doc' id='doc' pattern='(?:https?://.+)?'> <input name='submit' value='Print Tree' type='submit' id='submit'></form><hr><form><p><select id=parser name=parser><option value=xml>XML; don\u2019t load external entities</option><option value=html5 selected>HTML5</option></select><p><textarea name=content rows=20 cols=72></textarea> <input name='submit' value='Print Tree' type='submit' id='submit'></form>";
--    
--    private static final long SIZE_LIMIT = Integer.parseInt(System.getProperty(
--            "nu.validator.servlet.max-file-size", "2097152"));
--    
--    private final HttpServletRequest request;
--
--    private final HttpServletResponse response;
--
--    /**
--     * @param request
--     * @param response
--     */
--    public ParseTreePrinter(final HttpServletRequest request,
--            final HttpServletResponse response) {
--        this.request = request;
--        this.response = response;
--    }
--
--    private String scrubUrl(String urlStr) {
--        if (urlStr == null) {
--            return null;
--        }
--        try {
--            return URL.parse(urlStr).toString();
--        } catch (GalimatiasParseException e) {
--            return null;
--        }
--    }
--
--    public void service() throws IOException {
--        request.setCharacterEncoding("utf-8");
--        String content = null;
--        String document = scrubUrl(request.getParameter("doc"));
--        document = ("".equals(document)) ? null : document;
--        Writer writer = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
--        if (document == null && methodIsGet() && (content = request.getParameter("content")) == null) {
--            response.setContentType("text/html; charset=utf-8");
--            writer.write(FORM_HTML);
--            writer.flush();
--            writer.close();
--            return;
--        } else {
--            response.setContentType("text/plain; charset=utf-8");
--            try {
--            PrudentHttpEntityResolver entityResolver = new PrudentHttpEntityResolver(
--                    2048 * 1024, false, null);
--            entityResolver.setAllowGenericXml(false);
--            entityResolver.setAcceptAllKnownXmlTypes(false);
--            entityResolver.setAllowHtml(true);
--            entityResolver.setAllowXhtml(true);
--            TypedInputSource documentInput;
--            if (methodIsGet()) {
--                if (content == null) {
--                    documentInput = (TypedInputSource) entityResolver.resolveEntity(
--                            null, document);
--                } else {
--                    documentInput = new TypedInputSource(new StringReader(content));
--                    if ("xml".equals(request.getParameter("parser"))) {
--                        documentInput.setType("application/xhtml+xml");
--                    } else {
--                        documentInput.setType("text/html");
--                    }
--                }
--            } else { // POST
--                String postContentType = request.getContentType();
--                if (postContentType == null) {
--                    response.sendError(HttpServletResponse.SC_BAD_REQUEST,
--                            "Content-Type missing");
--                    return;
--                } else if (postContentType.trim().toLowerCase().startsWith(
--                        "application/x-www-form-urlencoded")) {
--                    response.sendError(
--                            HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE,
--                            "application/x-www-form-urlencoded not supported. Please use multipart/form-data.");
--                    return;
--                }
--                long len = request.getContentLength();
--                if (len > SIZE_LIMIT) {
--                    throw new StreamBoundException("Resource size exceeds limit.");
--                }
--                ContentTypeParser contentTypeParser = new ContentTypeParser(null, false);
--                contentTypeParser.setAllowGenericXml(false);
--                contentTypeParser.setAcceptAllKnownXmlTypes(false);
--                contentTypeParser.setAllowHtml(true);
--                contentTypeParser.setAllowXhtml(true);
--                documentInput = contentTypeParser.buildTypedInputSource(document,
--                        null, postContentType);
--                documentInput.setByteStream(len < 0 ? new BoundedInputStream(
--                        request.getInputStream(), SIZE_LIMIT, document)
--                        : request.getInputStream());
--                documentInput.setSystemId(request.getHeader("Content-Location"));
--            }
--            String type = documentInput.getType();
--            XMLReader parser;
--            if ("text/html".equals(type) || "text/html-sandboxed".equals(type)) {
--                writer.write("HTML parser\n\n#document\n");
--                parser = new nu.validator.htmlparser.sax.HtmlParser();
--                parser.setProperty("http://validator.nu/properties/heuristics", Heuristics.ALL);
--                parser.setProperty("http://validator.nu/properties/xml-policy", XmlViolationPolicy.ALLOW);
--            } else if ("application/xhtml+xml".equals(type)) {
--                writer.write("XML parser\n\n#document\n");
--                parser = new SAXDriver();
--                parser.setFeature(
--                        "http://xml.org/sax/features/external-general-entities",
--                        false);
--                parser.setFeature(
--                        "http://xml.org/sax/features/external-parameter-entities",
--                        false);
--                parser.setEntityResolver(new NullEntityResolver());
--            } else {
--                writer.write("Unsupported content type.\n");
--                writer.flush();
--                writer.close();
--                return;
--            }
--            TreeDumpContentHandler treeDumpContentHandler = new TreeDumpContentHandler(writer, false);
--            ListErrorHandler listErrorHandler = new ListErrorHandler();
--            parser.setContentHandler(treeDumpContentHandler);
--            parser.setProperty("http://xml.org/sax/properties/lexical-handler", treeDumpContentHandler);
--            parser.setErrorHandler(listErrorHandler);
--            parser.parse(documentInput);
--            writer.write("#errors\n");
--            for (String err : listErrorHandler.getErrors()) {
--                writer.write(err);
--                writer.write('\n');
--            }
--            } catch (SAXException e) {
--                writer.write("SAXException:\n");
--                writer.write(e.getMessage());
--                writer.write("\n");
--            } catch (IOException e) {
--                writer.write("IOException:\n");
--                writer.write(e.getMessage());
--                writer.write("\n");
--            } finally {
--                writer.flush();
--                writer.close();
--            }
--        }
--    }
--
--    private boolean methodIsGet() {
--        return "GET".equals(request.getMethod())
--                || "HEAD".equals(request.getMethod());
--    }
--
--}
-diff --git a/src/nu/validator/servlet/RootNamespaceSniffer.java b/src/nu/validator/servlet/RootNamespaceSniffer.java
-deleted file mode 100644
-index df4bad2..0000000
---- a/src/nu/validator/servlet/RootNamespaceSniffer.java
-+++ /dev/null
-@@ -1,121 +0,0 @@
--/*
-- * Copyright (c) 2006 Henri Sivonen
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import org.xml.sax.Attributes;
--import org.xml.sax.ContentHandler;
--import org.xml.sax.Locator;
--import org.xml.sax.SAXException;
--
--public class RootNamespaceSniffer implements ContentHandler {
--
--    private VerifierServletTransaction vst;
--    private ContentHandler ch;
--    private Locator locator;
--
--    public RootNamespaceSniffer(VerifierServletTransaction vst, ContentHandler ch) {
--        super();
--        this.vst = vst;
--        this.ch = ch;
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#characters(char[], int, int)
--     */
--    public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
--        ch.characters(arg0, arg1, arg2);
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#endDocument()
--     */
--    public void endDocument() throws SAXException {
--        ch.endDocument();
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
--     */
--    public void endElement(String arg0, String arg1, String arg2) throws SAXException {
--        ch.endElement(arg0, arg1, arg2);
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
--     */
--    public void endPrefixMapping(String arg0) throws SAXException {
--        ch.endPrefixMapping(arg0);
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
--     */
--    public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
--        ch.ignorableWhitespace(arg0, arg1, arg2);
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
--     */
--    public void processingInstruction(String arg0, String arg1) throws SAXException {
--        ch.processingInstruction(arg0, arg1);
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
--     */
--    public void setDocumentLocator(Locator arg0) {
--        this.locator = arg0;
--        ch.setDocumentLocator(arg0);
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
--     */
--    public void skippedEntity(String arg0) throws SAXException {
--        ch.skippedEntity(arg0);
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#startDocument()
--     */
--    public void startDocument() throws SAXException {
--        ch.startDocument();
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
--     */
--    public void startElement(String arg0, String arg1, String arg2, Attributes arg3) throws SAXException {
--        vst.rootNamespace(arg0, locator);
--        ch.startElement(arg0, arg1, arg2, arg3);
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
--     */
--    public void startPrefixMapping(String arg0, String arg1) throws SAXException {
--        ch.startPrefixMapping(arg0, arg1);
--    }
--
--}
-diff --git a/src/nu/validator/servlet/Statistics.java b/src/nu/validator/servlet/Statistics.java
-deleted file mode 100644
-index 37ada19..0000000
---- a/src/nu/validator/servlet/Statistics.java
-+++ /dev/null
-@@ -1,248 +0,0 @@
--/*
-- * Copyright (c) 2012 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.io.IOException;
--import java.text.DecimalFormat;
--
--import javax.servlet.http.HttpServletResponse;
--
--import nu.validator.htmlparser.sax.HtmlSerializer;
--import nu.validator.xml.EmptyAttributes;
--
--import org.xml.sax.ContentHandler;
--import org.xml.sax.SAXException;
--
--public class Statistics {
--
--    public static final Statistics STATISTICS;
--
--    private static final char[] VALIDATOR_STATISTICS = "Validator statistics".toCharArray();
--
--    private static final char[] COUNTER_NAME = "Counter".toCharArray();
--
--    private static final char[] COUNTER_VALUE = "Value".toCharArray();
--
--    private static final char[] COUNTER_PROPORTION = "Proportion".toCharArray();
--
--    private static final char[] TOTAL_VALIDATIONS = "Total number of validations".toCharArray();
--
--    private static final char[] UPTIME_DAYS = "Uptime in days".toCharArray();
--
--    private static final char[] VALIDATIONS_PER_SECOND = "Validations per second".toCharArray();
--
--    public enum Field {
--        // Sigh. Eclipse's formatting of the following code is sad.
--        CUSTOM_ENC("Manually set character encoding"), AUTO_SCHEMA(
--                "Automatically chosen schema"), PRESET_SCHEMA("Preset schema"), BUILT_IN_NON_PRESET(
--                "Custom schema combined from built-ins"), HTML5_SCHEMA(
--                "(X)HTML5 schema"), HTML5_RDFA_LITE_SCHEMA(
--                "(X)HTML5+RDFa Lite schema"), HTML4_STRICT_SCHEMA(
--                "Legacy Strict schema"), HTML4_TRANSITIONAL_SCHEMA(
--                "Legacy Transitional schema"), HTML4_FRAMESET_SCHEMA(
--                "Legacy Frameset schema"), XHTML1_COMPOUND_SCHEMA(
--                "Legacy XHTML+SVG+MathML schema"), SVG_SCHEMA("SVG schema"), EXTERNAL_SCHEMA_NON_SCHEMATRON(
--                "non-Schematron custom schema"), EXTERNAL_SCHEMA_SCHEMATRON(
--                "Schematron custom schema"), LOGIC_ERROR(
--                "Logic errors in schema stats"), PARSER_XML_EXTERNAL(
--                "Parser set to XML with external entities"), PARSER_HTML4(
--                "Parser set to explicit HTML4 mode"), XMLNS_FILTER(
--                "XMLNS filter set"), LAX_TYPE(
--                "Being lax about HTTP content type"), IMAGE_REPORT(
--                "Image report"), SHOW_SOURCE("Show source"), SHOW_OUTLINE(
--                "Show outline"), INPUT_GET("GET-based input"), INPUT_POST(
--                "POST-based input"), INPUT_TEXT_FIELD("\u2514 Text-field input"), INPUT_FILE_UPLOAD(
--                "\u2514 File-upload input"), INPUT_ENTITY_BODY(
--                "\u2514 Entity-body input"), OUTPUT_HTML("HTML output"), OUTPUT_XHTML(
--                "XHTML output"), OUTPUT_XML("XML output"), OUTPUT_JSON(
--                "JSON output"), OUTPUT_GNU("GNU output"), OUTPUT_TEXT(
--                "Text output"), INPUT_HTML("HTML input"), INPUT_XML("XML input");
--
--        Field(String description) {
--            this.description = description;
--        }
--
--        private final String description;
--
--        /**
--         * @see java.lang.Enum#toString()
--         */
--        @Override public String toString() {
--            return description;
--        }
--    }
--
--    static {
--        if ("1".equals(System.getProperty("nu.validator.servlet.statistics"))) {
--            STATISTICS = new Statistics();
--        } else {
--            STATISTICS = null;
--        }
--    }
--
--    private final long startTime = System.currentTimeMillis();
--
--    private long total = 0;
--
--    private final long[] counters;
--
--    private Statistics() {
--        counters = new long[Field.values().length];
--    }
--
--    public void incrementTotal() {
--        total++;
--    }
--
--    public void incrementField(Field field) {
--        counters[field.ordinal()]++;
--    }
--
--    public void writeToResponse(HttpServletResponse response)
--            throws IOException {
--        try {
--            long totalCopy;
--            long[] countersCopy = new long[counters.length];
--            synchronized (this) {
--                totalCopy = total;
--                System.arraycopy(counters, 0, countersCopy, 0, counters.length);
--            }
--            double totalDouble = (double) totalCopy;
--            double uptimeMillis = (double) (System.currentTimeMillis() - startTime);
--            response.setContentType("text/html; charset=utf-8");
--            ContentHandler ch = new HtmlSerializer(response.getOutputStream());
--            try {
--                ch.startDocument();
--                startElement(ch, "html");
--                startElement(ch, "head");
--                startElement(ch, "title");
--                characters(ch, VALIDATOR_STATISTICS);
--                endElement(ch, "title");
--                endElement(ch, "head");
--                startElement(ch, "body");
--                startElement(ch, "h1");
--                characters(ch, VALIDATOR_STATISTICS);
--                endElement(ch, "h1");
--
--                startElement(ch, "dl");
--                startElement(ch, "dt");
--                characters(ch, TOTAL_VALIDATIONS);
--                endElement(ch, "dt");
--                startElement(ch, "dd");
--                characters(ch, totalCopy);
--                endElement(ch, "dd");
--
--                startElement(ch, "dt");
--                characters(ch, UPTIME_DAYS);
--                endElement(ch, "dt");
--                startElement(ch, "dd");
--                characters(ch, uptimeMillis / (1000 * 60 * 60 * 24));
--                endElement(ch, "dd");
--
--                startElement(ch, "dt");
--                characters(ch, VALIDATIONS_PER_SECOND);
--                endElement(ch, "dt");
--                startElement(ch, "dd");
--                characters(ch, totalDouble / (uptimeMillis / 1000.0));
--                endElement(ch, "dd");
--
--                endElement(ch, "dl");
--
--                startElement(ch, "table");
--                startElement(ch, "thead");
--                startElement(ch, "tr");
--                startElement(ch, "th");
--                characters(ch, COUNTER_NAME);
--                endElement(ch, "th");
--                startElement(ch, "th");
--                characters(ch, COUNTER_VALUE);
--                endElement(ch, "th");
--                startElement(ch, "th");
--                characters(ch, COUNTER_PROPORTION);
--                endElement(ch, "th");
--                endElement(ch, "tr");
--                endElement(ch, "thead");
--                startElement(ch, "tbody");
--                for (int i = 0; i < countersCopy.length; i++) {
--                    long count = countersCopy[i];
--                    startElement(ch, "tr");
--                    startElement(ch, "td");
--
--                    characters(ch, Field.values()[i].toString());
--
--                    endElement(ch, "td");
--                    startElement(ch, "td");
--
--                    characters(ch, count);
--
--                    endElement(ch, "td");
--                    startElement(ch, "td");
--
--                    characters(ch, ((double) count) / totalDouble);
--
--                    endElement(ch, "td");
--                    endElement(ch, "tr");
--                }
--                endElement(ch, "tbody");
--                endElement(ch, "table");
--                endElement(ch, "body");
--                endElement(ch, "html");
--            } finally {
--                ch.endDocument();
--            }
--        } catch (SAXException e) {
--            throw new IOException(e);
--        }
--    }
--
--    private void characters(ContentHandler ch, double d) throws SAXException {
--        // Let's just create a new DecimalFormat each time to avoid the 
--        // complexity of recycling an instance correctly without threading
--        // hazards.
--        DecimalFormat df = new DecimalFormat("#,###,##0.000000");
--        characters(ch, df.format(d));
--    }
--
--    private void characters(ContentHandler ch, long l) throws SAXException {
--        characters(ch, Long.toString(l));
--    }
--
--    private void characters(ContentHandler ch, String str) throws SAXException {
--        characters(ch, str.toCharArray());
--    }
--
--    private void characters(ContentHandler ch, char[] cs) throws SAXException {
--        ch.characters(cs, 0, cs.length);
--    }
--
--    private void endElement(ContentHandler ch, String name) throws SAXException {
--        ch.endElement("http://www.w3.org/1999/xhtml", name, name);
--    }
--
--    private void startElement(ContentHandler ch, String name)
--            throws SAXException {
--        ch.startElement("http://www.w3.org/1999/xhtml", name, name,
--                EmptyAttributes.EMPTY_ATTRIBUTES);
--    }
--
--}
-diff --git a/src/nu/validator/servlet/StatsEmitter.java b/src/nu/validator/servlet/StatsEmitter.java
-deleted file mode 100644
-index 9ed17a1..0000000
---- a/src/nu/validator/servlet/StatsEmitter.java
-+++ /dev/null
-@@ -1,18 +0,0 @@
--/* This code was generated by nu.validator.tools.SaxCompiler. Please regenerate instead of editing. */
--package nu.validator.servlet;
--public final class StatsEmitter {
--private StatsEmitter() {}
--public static void emit(org.xml.sax.ContentHandler contentHandler, nu.validator.servlet.VerifierServletTransaction t) throws org.xml.sax.SAXException {
--org.xml.sax.helpers.AttributesImpl __attrs__ = new org.xml.sax.helpers.AttributesImpl();
--contentHandler.startPrefixMapping("", "http://www.w3.org/1999/xhtml");
--__attrs__.clear();
--__attrs__.addAttribute("", "class", "class", "CDATA", "stats");
--contentHandler.startElement("http://www.w3.org/1999/xhtml", "p", "p", __attrs__);
--contentHandler.characters(__chars__, 0, 21);
--t.emitTotalDuration(); 
--contentHandler.characters(__chars__, 21, 14);
--contentHandler.endElement("http://www.w3.org/1999/xhtml", "p", "p");
--contentHandler.endPrefixMapping("");
--}
--private static final char[] __chars__ = { 'T', 'o', 't', 'a', 'l', ' ', 'e', 'x', 'e', 'c', 'u', 't', 'i', 'o', 'n', ' ', 't', 'i', 'm', 'e', ' ', ' ', 'm', 'i', 'l', 'l', 'i', 's', 'e', 'c', 'o', 'n', 'd', 's', '.' };
--}
-diff --git a/src/nu/validator/servlet/TreeDumpContentHandler.java b/src/nu/validator/servlet/TreeDumpContentHandler.java
-deleted file mode 100644
-index 5728c8d..0000000
---- a/src/nu/validator/servlet/TreeDumpContentHandler.java
-+++ /dev/null
-@@ -1,232 +0,0 @@
--/*
-- * Copyright (c) 2007 Henri Sivonen
-- * Copyright (c) 2008 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.io.IOException;
--import java.io.Writer;
--import java.util.Map;
--import java.util.TreeMap;
--
--import org.xml.sax.Attributes;
--import org.xml.sax.ContentHandler;
--import org.xml.sax.Locator;
--import org.xml.sax.SAXException;
--import org.xml.sax.ext.LexicalHandler;
--
--public class TreeDumpContentHandler implements ContentHandler, LexicalHandler {
--
--    private final Writer writer;
--
--    private int level = 0;
--
--    private boolean inCharacters = false;
--
--    private boolean close;
--
--    /**
--     * @param writer
--     */
--    public TreeDumpContentHandler(final Writer writer, boolean close) {
--        this.writer = writer;
--        this.close = close;
--    }
--
--    public TreeDumpContentHandler(final Writer writer) {
--        this(writer, true);
--    }
--
--    private void printLead() throws IOException {
--        if (inCharacters) {
--            writer.write("\"\n");
--            inCharacters = false;
--        }
--        writer.write("| ");
--        for (int i = 0; i < level; i++) {
--            writer.write("  ");
--        }
--    }
--
--    /**
--     * @see org.xml.sax.ContentHandler#characters(char[], int, int)
--     */
--    public void characters(char[] ch, int start, int length)
--            throws SAXException {
--        try {
--            if (!inCharacters) {
--                printLead();
--                writer.write('"');
--                inCharacters = true;
--            }
--            writer.write(ch, start, length);
--        } catch (IOException e) {
--            throw new SAXException(e);
--        }
--    }
--
--    public void endElement(String uri, String localName, String qName)
--            throws SAXException {
--        try {
--            if (inCharacters) {
--                writer.write("\"\n");
--                inCharacters = false;
--            }
--            level--;
--        } catch (IOException e) {
--            throw new SAXException(e);
--        }
--    }
--
--    public void startElement(String uri, String localName, String qName,
--            Attributes atts) throws SAXException {
--        try {
--            printLead();
--            writer.write('<');
--            if ("http://www.w3.org/1998/Math/MathML" == uri) {
--                writer.write("math ");                
--            } else if ("http://www.w3.org/2000/svg" == uri) {
--                writer.write("svg ");                                
--            } else if ("http://www.w3.org/1999/xhtml" != uri) {
--                writer.write("otherns ");                                
--            }
--            writer.write(localName);
--            writer.write(">\n");
--            level++;
--
--            TreeMap<String, String> map = new TreeMap<String, String>();
--            for (int i = 0; i < atts.getLength(); i++) {
--                String ns = atts.getURI(i);
--                String name;
--                if ("http://www.w3.org/1999/xlink" == ns) {
--                    name = "xlink " + atts.getLocalName(i);
--                } else if ("http://www.w3.org/XML/1998/namespace" == ns) {
--                    name = "xml " + atts.getLocalName(i);                    
--                } else if ("http://www.w3.org/2000/xmlns/" == ns) {
--                    name = "xmlns " + atts.getLocalName(i);                    
--                } else if ("" != uri) {
--                    name = atts.getLocalName(i);                    
--                } else {
--                    name = "otherns " + atts.getLocalName(i);                    
--                }
--                map.put(name, atts.getValue(i));
--            }
--            for (Map.Entry<String, String> entry : map.entrySet()) {
--                printLead();
--                writer.write(entry.getKey());
--                writer.write("=\"");
--                writer.write(entry.getValue());
--                writer.write("\"\n");
--            }
--        } catch (IOException e) {
--            throw new SAXException(e);
--        }
--    }
--
--    public void comment(char[] ch, int offset, int len) throws SAXException {
--        try {
--            printLead();
--            writer.write("<!-- ");
--            writer.write(ch, offset, len);
--            writer.write(" -->\n");
--        } catch (IOException e) {
--            throw new SAXException(e);
--        }
--    }
--
--    public void startDTD(String name, String publicIdentifier,
--            String systemIdentifier) throws SAXException {
--        try {
--            printLead();
--            writer.write("<!DOCTYPE ");
--            writer.write(name);
--            if (publicIdentifier.length() > 0 || systemIdentifier.length() > 0) {
--                writer.write(' ');
--                writer.write('\"');
--                writer.write(publicIdentifier);
--                writer.write('\"');
--                writer.write(' ');
--                writer.write('\"');
--                writer.write(systemIdentifier);
--                writer.write('\"');
--            }
--            writer.write(">\n");
--        } catch (IOException e) {
--            throw new SAXException(e);
--        }
--    }
--
--    public void endDocument() throws SAXException {
--        try {
--            if (inCharacters) {
--                writer.write("\"\n");
--                inCharacters = false;
--            }
--            if (close) {
--                writer.flush();
--                writer.close();
--            }
--        } catch (IOException e) {
--            throw new SAXException(e);
--        }
--    }
--
--    public void startPrefixMapping(String prefix, String uri)
--            throws SAXException {
--    }
--
--    public void startEntity(String arg0) throws SAXException {
--    }
--
--    public void endCDATA() throws SAXException {
--    }
--
--    public void endDTD() throws SAXException {
--    }
--
--    public void endEntity(String arg0) throws SAXException {
--    }
--
--    public void startCDATA() throws SAXException {
--    }
--
--    public void endPrefixMapping(String prefix) throws SAXException {
--    }
--
--    public void ignorableWhitespace(char[] ch, int start, int length)
--            throws SAXException {
--    }
--
--    public void processingInstruction(String target, String data)
--            throws SAXException {
--    }
--
--    public void setDocumentLocator(Locator locator) {
--    }
--
--    public void skippedEntity(String name) throws SAXException {
--    }
--
--    public void startDocument() throws SAXException {
--    }
--
--}
-diff --git a/src/nu/validator/servlet/VerifierServlet.java b/src/nu/validator/servlet/VerifierServlet.java
-deleted file mode 100644
-index 987fed9..0000000
---- a/src/nu/validator/servlet/VerifierServlet.java
-+++ /dev/null
-@@ -1,306 +0,0 @@
--/*
-- * Copyright (c) 2005 Henri Sivonen
-- * Copyright (c) 2007-2014 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.io.IOException;
--import java.io.InputStream;
--import java.io.OutputStream;
--import java.io.ByteArrayOutputStream;
--import java.io.UnsupportedEncodingException;
--
--import javax.servlet.ServletException;
--import javax.servlet.http.HttpServlet;
--import javax.servlet.http.HttpServletRequest;
--import javax.servlet.http.HttpServletResponse;
--
--import nu.validator.messages.MessageEmitterAdapter;
--import nu.validator.xml.PrudentHttpEntityResolver;
--
--import org.apache.log4j.Logger;
--
--
--/**
-- * @version $Id$
-- * @author hsivonen
-- */
--public class VerifierServlet extends HttpServlet {
--    /**
--     * 
--     */
--    private static final long serialVersionUID = 7811043632732680935L;
--
--    private static final Logger log4j = Logger.getLogger(VerifierServlet.class);
--
--    static final String GENERIC_HOST = System.getProperty("nu.validator.servlet.host.generic", "");
--
--    static final String HTML5_HOST = System.getProperty("nu.validator.servlet.host.html5", "");
--
--    static final String PARSETREE_HOST = System.getProperty("nu.validator.servlet.host.parsetree", "");
--
--    static final String GENERIC_PATH = System.getProperty("nu.validator.servlet.path.generic", "/");
--
--    static final String HTML5_PATH = System.getProperty("nu.validator.servlet.path.html5", "/html5/");
--
--    static final String PARSETREE_PATH = System.getProperty("nu.validator.servlet.path.parsetree", "/parsetree/");
--
--    private static final byte[] GENERIC_ROBOTS_TXT;
--
--    private static final byte[] HTML5_ROBOTS_TXT;
--
--    private static final byte[] PARSETREE_ROBOTS_TXT;
--
--    private static final byte[] STYLE_CSS;
--
--    private static final byte[] SCRIPT_JS;
--
--    private static final byte[] ICON_PNG;
--
--    private static final byte[] ABOUT_HTML;
--
--    static {
--        try {
--            GENERIC_ROBOTS_TXT = buildRobotsTxt(GENERIC_HOST, GENERIC_PATH, HTML5_HOST, HTML5_PATH, PARSETREE_HOST, PARSETREE_PATH);
--            HTML5_ROBOTS_TXT = buildRobotsTxt(HTML5_HOST, HTML5_PATH, GENERIC_HOST, GENERIC_PATH, PARSETREE_HOST, PARSETREE_PATH);
--            PARSETREE_ROBOTS_TXT = buildRobotsTxt(PARSETREE_HOST, PARSETREE_PATH, HTML5_HOST, HTML5_PATH, GENERIC_HOST, GENERIC_PATH);
--        } catch (UnsupportedEncodingException e) {
--            throw new RuntimeException(e);
--        }
--        try {
--            STYLE_CSS = readFromClassLoaderIntoByteArray("nu/validator/localentities/files/style.css");
--            SCRIPT_JS = readFromClassLoaderIntoByteArray("nu/validator/localentities/files/script.js");
--            ICON_PNG = readFromClassLoaderIntoByteArray("nu/validator/localentities/files/icon.png");
--            ABOUT_HTML = readFromClassLoaderIntoByteArray("nu/validator/localentities/files/about.html");
--        } catch (IOException e) {
--            throw new RuntimeException(e);
--        }
--        PrudentHttpEntityResolver.setParams(
--            Integer.parseInt(System.getProperty("nu.validator.servlet.connection-timeout","5000")),
--            Integer.parseInt(System.getProperty("nu.validator.servlet.socket-timeout","5000")),
--            100);
--        // force some class loading
--        new VerifierServletTransaction(null, null);
--        new MessageEmitterAdapter(null, false, null, 0, false, null);
--    }
--
--    /**
--     * @return
--     * @throws UnsupportedEncodingException
--     */
--    private static byte[] buildRobotsTxt(String primaryHost, String primaryPath, String secondaryHost, String secondaryPath, String tertiaryHost, String tertiaryPath) throws UnsupportedEncodingException {
--        StringBuilder builder = new StringBuilder();
--        builder.append("User-agent: *\nDisallow: ");
--        builder.append(primaryPath);
--        builder.append("?\n");
--        if (primaryHost.equals(secondaryHost)) {
--            builder.append("Disallow: ");
--            builder.append(secondaryPath);
--            builder.append("?\n");
--        }
--        if (primaryHost.equals(tertiaryHost)) {
--            builder.append("Disallow: ");
--            builder.append(tertiaryPath);
--            builder.append("?\n");
--        }
--        return builder.toString().getBytes("UTF-8");
--    }
--
--    private static byte[] readFromClassLoaderIntoByteArray(String name)
--            throws IOException {
--        InputStream ios = VerifierServlet.class.getClassLoader().getResourceAsStream(
--                name);
--        ByteArrayOutputStream baos = new ByteArrayOutputStream();
--        try {
--            for (int b = ios.read(); b != -1; b = ios.read()) {
--                baos.write(b);
--            }
--            ios.close();
--            baos.close();
--        } catch (IOException e) {
--            throw new RuntimeException(e);
--        }
--        return baos.toByteArray();
--    }
--
--    private void writeResponse(byte[] buffer, String type,
--            HttpServletResponse response) throws IOException {
--        try {
--            response.setContentType(type);
--            response.setContentLength(buffer.length);
--            response.setDateHeader("Expires",
--                    System.currentTimeMillis() + 43200000); // 12 hours
--            OutputStream out = response.getOutputStream();
--            out.write(buffer);
--            out.flush();
--            out.close();
--        } catch (IOException e) {
--            throw new RuntimeException(e);
--        }
--    }
--
--    /**
--     * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
--     */
--    @Override
--    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
--        if ("/robots.txt".equals(request.getPathInfo())) {
--            String serverName = request.getServerName();
--            byte[] robotsTxt = null;
--            if (hostMatch(GENERIC_HOST, serverName)) {
--                robotsTxt = GENERIC_ROBOTS_TXT;
--            } else if (hostMatch(HTML5_HOST, serverName)) {
--                robotsTxt = HTML5_ROBOTS_TXT;
--            } else if (hostMatch(PARSETREE_HOST, serverName)) {
--                robotsTxt = PARSETREE_ROBOTS_TXT;
--            } else {
--                response.sendError(HttpServletResponse.SC_NOT_FOUND);
--                return;
--            }
--            writeResponse(robotsTxt, "text/plain; charset=utf-8", response);
--            return;
--        } else if ("/style.css".equals(request.getPathInfo())) {
--            writeResponse(STYLE_CSS, "text/css; charset=utf-8", response);
--            return;
--        } else if ("/script.js".equals(request.getPathInfo())) {
--            writeResponse(SCRIPT_JS, "text/javascript; charset=utf-8", response);
--            return;
--        } else if ("/icon.png".equals(request.getPathInfo())) {
--            writeResponse(ICON_PNG, "image/png", response);
--            return;
--        } else if ("/about.html".equals(request.getPathInfo())) {
--            writeResponse(ABOUT_HTML, "text/html; charset=utf-8", response);
--            return;
--        } else if (Statistics.STATISTICS != null && "/stats.html".equals(request.getPathInfo())) {
--            Statistics.STATISTICS.writeToResponse(response);
--            return;
--        }
--        doPost(request, response);
--    }
--
--    private boolean hostMatch(String reference, String host) {
--        if ("".equals(reference)) {
--            return true;
--        } else {
--            // XXX case-sensitivity
--            return reference.equalsIgnoreCase(host);
--        }
--    }
--
--    /**
--     * @see javax.servlet.http.HttpServlet#doOptions(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
--     */
--    @Override
--    protected void doOptions(HttpServletRequest request,
--            HttpServletResponse response) throws ServletException, IOException {
--        String pathInfo = request.getPathInfo();
--        if ("*".equals(pathInfo)) { // useless RFC 2616 complication
--            return;
--        } else if ("/robots.txt".equals(pathInfo)) {
--            String serverName = request.getServerName();
--            if (hostMatch(GENERIC_HOST, serverName)
--                    || hostMatch(HTML5_HOST, serverName)
--                    || hostMatch(PARSETREE_HOST, serverName)) {
--                sendGetOnlyOptions(request, response);
--                return;
--            } else {
--                response.sendError(HttpServletResponse.SC_NOT_FOUND);
--                return;
--            }
--        }
--        doPost(request, response);
--    }
--
--    /**
--     * @see javax.servlet.http.HttpServlet#doTrace(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
--     */
--    @Override
--    protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
--        response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
--    }
--
--    /**
--     * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
--     *      javax.servlet.http.HttpServletResponse)
--     */
--    protected void doPost(HttpServletRequest request,
--            HttpServletResponse response) throws ServletException, IOException {
--        String pathInfo = request.getPathInfo();
--        if (pathInfo == null) {
--            pathInfo = "/"; // Fix for Jigsaw
--        }
--        String serverName = request.getServerName();
--        if ("/robots.txt".equals(pathInfo)) {
--            // if we get here, we've got a POST
--            response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
--            return;
--        }
--        log4j.debug("pathInfo: " + pathInfo);
--        log4j.debug("serverName: " + serverName);
--        boolean isOptions = "OPTIONS".equals(request.getMethod());
--
--        if ("validator.nu".equals(serverName) && "/html5/".equals(pathInfo)) {
--                response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
--                String queryString = request.getQueryString();
--                response.setHeader("Location", "http://html5.validator.nu/" + (queryString == null ? "" : "?" + queryString));
--        } else if (hostMatch(GENERIC_HOST, serverName) && GENERIC_PATH.equals(pathInfo)) {
--            response.setHeader("Access-Control-Allow-Origin", "*");
--            response.setHeader("Access-Control-Allow-Headers", "content-type");
--            if (isOptions) {
--                sendOptions(request, response);
--            } else {
--                new VerifierServletTransaction(request, response).service();
--            }
--        } else if (hostMatch(HTML5_HOST, serverName) && HTML5_PATH.equals(pathInfo)) {
--            response.setHeader("Access-Control-Allow-Origin", "*");
--            response.setHeader("Access-Control-Allow-Headers", "content-type");
--            if (isOptions) {
--                sendOptions(request, response);
--            } else {
--                new Html5ConformanceCheckerTransaction(request, response).service();
--            }
--        } else if (hostMatch(PARSETREE_HOST, serverName) && PARSETREE_PATH.equals(pathInfo)) {
--            if (isOptions) {
--                sendGetOnlyOptions(request, response);
--            } else {
--                new ParseTreePrinter(request, response).service();
--            }
--        } else {
--            response.sendError(HttpServletResponse.SC_NOT_FOUND);
--        }
--    }
--
--    private void sendGetOnlyOptions(HttpServletRequest request, HttpServletResponse response) {
--        response.setHeader("Allow", "GET, HEAD, OPTIONS");
--        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, OPTIONS");
--        response.setContentType("application/octet-stream");
--        response.setContentLength(0);
--    }
--
--    private void sendOptions(HttpServletRequest request, HttpServletResponse response) {
--        response.setHeader("Access-Control-Max-Age", "43200"); // 12 hours
--        response.setHeader("Allow", "GET, HEAD, POST, OPTIONS");
--        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, OPTIONS");
--        response.setContentType("application/octet-stream");
--        response.setContentLength(0);
--    }
--}
-diff --git a/src/nu/validator/servlet/VerifierServletTransaction.java b/src/nu/validator/servlet/VerifierServletTransaction.java
-deleted file mode 100644
-index 5239a06..0000000
---- a/src/nu/validator/servlet/VerifierServletTransaction.java
-+++ /dev/null
-@@ -1,2051 +0,0 @@
--/*
-- * Copyright (c) 2005, 2006 Henri Sivonen
-- * Copyright (c) 2007-2015 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.io.BufferedReader;
--import java.io.IOException;
--import java.io.InputStreamReader;
--import java.io.OutputStream;
--import java.util.Arrays;
--import java.util.Deque;
--import java.util.HashMap;
--import java.util.HashSet;
--import java.util.LinkedHashSet;
--import java.util.LinkedList;
--import java.util.List;
--import java.util.Map;
--import java.util.Properties;
--import java.util.Set;
--import java.util.SortedMap;
--import java.util.TreeMap;
--import java.util.regex.Matcher;
--import java.util.regex.Pattern;
--
--import javax.servlet.ServletException;
--import javax.servlet.http.HttpServletRequest;
--import javax.servlet.http.HttpServletResponse;
--
--import nu.validator.checker.XmlPiChecker;
--import nu.validator.checker.jing.CheckerSchema;
--import nu.validator.gnu.xml.aelfred2.SAXDriver;
--import nu.validator.htmlparser.common.DoctypeExpectation;
--import nu.validator.htmlparser.common.DocumentMode;
--import nu.validator.htmlparser.common.DocumentModeHandler;
--import nu.validator.htmlparser.common.Heuristics;
--import nu.validator.htmlparser.common.XmlViolationPolicy;
--import nu.validator.htmlparser.sax.HtmlParser;
--import nu.validator.htmlparser.sax.HtmlSerializer;
--import nu.validator.htmlparser.sax.XmlSerializer;
--import nu.validator.io.BoundedInputStream;
--import nu.validator.io.DataUri;
--import nu.validator.io.StreamBoundException;
--import nu.validator.localentities.LocalCacheEntityResolver;
--import nu.validator.messages.GnuMessageEmitter;
--import nu.validator.messages.JsonMessageEmitter;
--import nu.validator.messages.MessageEmitterAdapter;
--import nu.validator.messages.TextMessageEmitter;
--import nu.validator.messages.TooManyErrorsException;
--import nu.validator.messages.XhtmlMessageEmitter;
--import nu.validator.messages.XmlMessageEmitter;
--import nu.validator.servlet.imagereview.ImageCollector;
--import nu.validator.servlet.OutlineBuildingXMLReaderWrapper.Section;
--import nu.validator.source.SourceCode;
--import nu.validator.spec.Spec;
--import nu.validator.spec.html5.Html5SpecBuilder;
--import nu.validator.xml.AttributesImpl;
--import nu.validator.xml.AttributesPermutingXMLReaderWrapper;
--import nu.validator.xml.BaseUriTracker;
--import nu.validator.xml.CharacterUtil;
--import nu.validator.xml.CombineContentHandler;
--import nu.validator.xml.ContentTypeParser;
--import nu.validator.xml.DataUriEntityResolver;
--import nu.validator.xml.IdFilter;
--import nu.validator.xml.NamespaceDroppingXMLReaderWrapper;
--import nu.validator.xml.NullEntityResolver;
--import nu.validator.xml.PrudentHttpEntityResolver;
--import nu.validator.xml.SystemErrErrorHandler;
--import nu.validator.xml.TypedInputSource;
--import nu.validator.xml.WiretapXMLReaderWrapper;
--import nu.validator.xml.XhtmlSaxEmitter;
--import nu.validator.xml.dataattributes.DataAttributeDroppingSchemaWrapper;
--import nu.validator.xml.langattributes.XmlLangAttributeDroppingSchemaWrapper;
--import nu.validator.xml.roleattributes.RoleAttributeFilteringSchemaWrapper;
--
--import org.xml.sax.ContentHandler;
--import org.xml.sax.EntityResolver;
--import org.xml.sax.ErrorHandler;
--import org.xml.sax.Locator;
--import org.xml.sax.SAXException;
--import org.xml.sax.SAXNotRecognizedException;
--import org.xml.sax.SAXNotSupportedException;
--import org.xml.sax.SAXParseException;
--import org.xml.sax.XMLReader;
--import org.xml.sax.ext.LexicalHandler;
--
--import com.thaiopensource.relaxng.impl.CombineValidator;
--import com.thaiopensource.util.PropertyMap;
--import com.thaiopensource.util.PropertyMapBuilder;
--import com.thaiopensource.validate.IncorrectSchemaException;
--import com.thaiopensource.validate.Schema;
--import com.thaiopensource.validate.SchemaReader;
--import com.thaiopensource.validate.SchemaResolver;
--import com.thaiopensource.validate.ValidateProperty;
--import com.thaiopensource.validate.Validator;
--import com.thaiopensource.validate.auto.AutoSchemaReader;
--import com.thaiopensource.validate.prop.rng.RngProperty;
--import com.thaiopensource.validate.prop.wrap.WrapProperty;
--import com.thaiopensource.validate.rng.CompactSchemaReader;
--
--import org.apache.log4j.Logger;
--import com.ibm.icu.text.Normalizer;
--
--/**
-- * @version $Id: VerifierServletTransaction.java,v 1.10 2005/07/24 07:32:48
-- *          hsivonen Exp $
-- * @author hsivonen
-- */
--class VerifierServletTransaction implements DocumentModeHandler, SchemaResolver {
--
--    private enum OutputFormat {
--        HTML, XHTML, TEXT, XML, JSON, RELAXED, SOAP, UNICORN, GNU
--    }
--
--    private static final Logger log4j = Logger.getLogger(VerifierServletTransaction.class);
--
--    private static final Pattern SPACE = Pattern.compile("\\s+");
--
--    private static final Pattern JS_IDENTIFIER = Pattern.compile("[\\p{Lu}\\p{Ll}\\p{Lt}\\p{Lm}\\p{Lo}\\p{Nl}_\\$][\\p{Lu}\\p{Ll}\\p{Lt}\\p{Lm}\\p{Lo}\\p{Nl}_\\$\\p{Mn}\\p{Mc}\\p{Nd}\\p{Pc}]*");
--
--    private static final String[] JS_RESERVED_WORDS = { "abstract", "boolean",
--            "break", "byte", "case", "catch", "char", "class", "const",
--            "continue", "debugger", "default", "delete", "do", "double",
--            "else", "enum", "export", "extends", "final", "finally", "float",
--            "for", "function", "goto", "if", "implements", "import", "in",
--            "instanceof", "int", "interface", "long", "native", "new",
--            "package", "private", "protected", "public", "return", "short",
--            "static", "super", "switch", "synchronized", "this", "throw",
--            "throws", "transient", "try", "typeof", "var", "void", "volatile",
--            "while", "with" };
--
--    private static final String[] CHARSETS = { "UTF-8", "UTF-16",
--            "Windows-1250", "Windows-1251", "Windows-1252", "Windows-1253",
--            "Windows-1254", "Windows-1255", "Windows-1256", "Windows-1257",
--            "Windows-1258", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3",
--            "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7",
--            "ISO-8859-8", "ISO-8859-9", "ISO-8859-13", "ISO-8859-15", "KOI8-R",
--            "TIS-620", "GBK", "GB18030", "Big5", "Big5-HKSCS", "Shift_JIS",
--            "ISO-2022-JP", "EUC-JP", "ISO-2022-KR", "EUC-KR" };
--
--    private static final char[][] CHARSET_DESCRIPTIONS = {
--            "UTF-8 (Global)".toCharArray(), "UTF-16 (Global)".toCharArray(),
--            "Windows-1250 (Central European)".toCharArray(),
--            "Windows-1251 (Cyrillic)".toCharArray(),
--            "Windows-1252 (Western)".toCharArray(),
--            "Windows-1253 (Greek)".toCharArray(),
--            "Windows-1254 (Turkish)".toCharArray(),
--            "Windows-1255 (Hebrew)".toCharArray(),
--            "Windows-1256 (Arabic)".toCharArray(),
--            "Windows-1257 (Baltic)".toCharArray(),
--            "Windows-1258 (Vietnamese)".toCharArray(),
--            "ISO-8859-1 (Western)".toCharArray(),
--            "ISO-8859-2 (Central European)".toCharArray(),
--            "ISO-8859-3 (South European)".toCharArray(),
--            "ISO-8859-4 (Baltic)".toCharArray(),
--            "ISO-8859-5 (Cyrillic)".toCharArray(),
--            "ISO-8859-6 (Arabic)".toCharArray(),
--            "ISO-8859-7 (Greek)".toCharArray(),
--            "ISO-8859-8 (Hebrew)".toCharArray(),
--            "ISO-8859-9 (Turkish)".toCharArray(),
--            "ISO-8859-13 (Baltic)".toCharArray(),
--            "ISO-8859-15 (Western)".toCharArray(),
--            "KOI8-R (Russian)".toCharArray(), "TIS-620 (Thai)".toCharArray(),
--            "GBK (Chinese, simplified)".toCharArray(),
--            "GB18030 (Chinese, simplified)".toCharArray(),
--            "Big5 (Chinese, traditional)".toCharArray(),
--            "Big5-HKSCS (Chinese, traditional)".toCharArray(),
--            "Shift_JIS (Japanese)".toCharArray(),
--            "ISO-2022-JP (Japanese)".toCharArray(),
--            "EUC-JP (Japanese)".toCharArray(),
--            "ISO-2022-KR (Korean)".toCharArray(),
--            "EUC-KR (Korean)".toCharArray() };
--
--    protected static final int HTML5_SCHEMA = 3;
--
--    protected static final int XHTML1STRICT_SCHEMA = 2;
--
--    protected static final int XHTML1TRANSITIONAL_SCHEMA = 1;
--
--    protected static final int XHTML5_SCHEMA = 7;
--
--    private static final char[] SERVICE_TITLE;
--
--    private static final char[] LIVING_VERSION = "Living Validator".toCharArray();
--
--    private static final char[] VERSION;
--
--    private static final char[] RESULTS_TITLE;
--
--    private static final char[] FOR = " for ".toCharArray();
--
--    private static final char[] ABOUT_THIS_SERVICE = "About this Service".toCharArray();
--
--    private static final char[] SIMPLE_UI = "Simplified Interface".toCharArray();
--
--    private static final String USER_AGENT;
--
--    private static Spec html5spec;
--
--    private static int[] presetDoctypes;
--
--    private static String[] presetLabels;
--
--    private static String[] presetUrls;
--
--    private static String[] presetNamespaces;
--
--    // XXX SVG!!!
--
--    private static final String[] KNOWN_CONTENT_TYPES = {
--            "application/atom+xml", "application/docbook+xml",
--            "application/xhtml+xml", "application/xv+xml", "image/svg+xml" };
--
--    private static final String[] NAMESPACES_FOR_KNOWN_CONTENT_TYPES = {
--            "http://www.w3.org/2005/Atom", "http://docbook.org/ns/docbook",
--            "http://www.w3.org/1999/xhtml", "http://www.w3.org/1999/xhtml",
--            "http://www.w3.org/2000/svg" };
--
--    private static final String[] ALL_CHECKERS = {
--            "http://c.validator.nu/table/", "http://c.validator.nu/nfc/",
--            "http://c.validator.nu/text-content/",
--            "http://c.validator.nu/unchecked/",
--            "http://c.validator.nu/usemap/", "http://c.validator.nu/obsolete/",
--            "http://c.validator.nu/xml-pi/", "http://c.validator.nu/unsupported/",
--            "http://c.validator.nu/microdata/" };
--
--    private static final String[] ALL_CHECKERS_HTML4 = {
--            "http://c.validator.nu/table/", "http://c.validator.nu/nfc/",
--            "http://c.validator.nu/unchecked/", "http://c.validator.nu/usemap/" };
--
--    private long start = System.currentTimeMillis();
--
--    protected final HttpServletRequest request;
--
--    private final HttpServletResponse response;
--
--    protected String document = null;
--
--    private ParserMode parser = ParserMode.AUTO;
--
--    private String profile = "";
--
--    private boolean laxType = false;
--
--    protected ContentHandler contentHandler;
--
--    protected XhtmlSaxEmitter emitter;
--
--    protected MessageEmitterAdapter errorHandler;
--
--    protected final AttributesImpl attrs = new AttributesImpl();
--
--    private OutputStream out;
--
--    private PropertyMap jingPropertyMap;
--
--    protected LocalCacheEntityResolver entityResolver;
--
--    private static long lastModified;
--
--    private static String[] preloadedSchemaUrls;
--
--    private static Schema[] preloadedSchemas;
--
--    private final static String ABOUT_PAGE = System.getProperty(
--            "nu.validator.servlet.about-page", "https://about.validator.nu/");
--
--    private final static String HTML5_FACET = (VerifierServlet.HTML5_HOST.isEmpty() ? "" : ("//" + VerifierServlet.HTML5_HOST)) + VerifierServlet.HTML5_PATH;
--
--    private final static String STYLE_SHEET = System.getProperty(
--            "nu.validator.servlet.style-sheet",
--            "style.css");
--
--    private final static String ICON = System.getProperty(
--            "nu.validator.servlet.icon",
--            "icon.png");
--
--    private final static String SCRIPT = System.getProperty(
--            "nu.validator.servlet.script",
--            "script.js");
--
--    private final static String[] LEGACY_HOSTS = System.getProperty(
--            "nu.validator.servlet.host.legacy", "").split("\\s+");
--
--    private static final long SIZE_LIMIT = Integer.parseInt(System.getProperty(
--            "nu.validator.servlet.max-file-size", "2097152"));
--
--    private String schemaUrls = null;
--
--    protected Validator validator = null;
--
--    private BufferingRootNamespaceSniffer bufferingRootNamespaceSniffer = null;
--
--    private String contentType = null;
--
--    protected HtmlParser htmlParser = null;
--
--    protected SAXDriver xmlParser = null;
--
--    protected XMLReader reader;
--
--    protected TypedInputSource documentInput;
--
--    protected PrudentHttpEntityResolver httpRes;
--
--    protected DataUriEntityResolver dataRes;
--
--    protected ContentTypeParser contentTypeParser;
--
--    private Set<String> loadedValidatorUrls = new HashSet<String>();
--
--    private boolean checkNormalization = false;
--
--    private boolean rootNamespaceSeen = false;
--
--    private OutputFormat outputFormat;
--
--    private String postContentType;
--
--    private boolean methodIsGet;
--
--    private SourceCode sourceCode = new SourceCode();
--
--    private Deque<Section> outline;
--
--    private boolean showSource;
--
--    private boolean showOutline;
--
--    private String userAgent;
--
--    private BaseUriTracker baseUriTracker = null;
--
--    private String charsetOverride = null;
--
--    private Set<String> filteredNamespaces = new LinkedHashSet<String>(); // linked
--
--    private LexicalHandler lexicalHandler;
--
--    // for
--    // UI
--    // stability
--
--    protected ImageCollector imageCollector;
--
--    private boolean externalSchema = false;
--
--    private boolean externalSchematron = false;
--
--    private String schemaListForStats = null;
--
--    static {
--        try {
--            log4j.debug("Starting static initializer.");
--
--            lastModified = 0;
--            BufferedReader r = new BufferedReader(new InputStreamReader(LocalCacheEntityResolver.getPresetsAsStream(), "UTF-8"));
--            String line;
--            List<String> doctypes = new LinkedList<String>();
--            List<String> namespaces = new LinkedList<String>();
--            List<String> labels = new LinkedList<String>();
--            List<String> urls = new LinkedList<String>();
--            Properties props = new Properties();
--
--            log4j.debug("Reading miscellaneous properties.");
--
--            props.load(VerifierServlet.class.getClassLoader().getResourceAsStream(
--                    "nu/validator/localentities/files/misc.properties"));
--            SERVICE_TITLE = (System.getProperty(
--                    "nu.validator.servlet.service-name",
--                    props.getProperty("nu.validator.servlet.service-name",
--                            "Validator.nu")) + " ").toCharArray();
--            RESULTS_TITLE = (System.getProperty(
--                    "nu.validator.servlet.results-title", props.getProperty(
--                            "nu.validator.servlet.results-title",
--                            "Validation results"))).toCharArray();
--            VERSION = (System.getProperty("nu.validator.servlet.version",
--                    props.getProperty("nu.validator.servlet.version",
--                            "Living Validator"))).toCharArray();
--            USER_AGENT= (System.getProperty("nu.validator.servlet.user-agent",
--                    props.getProperty("nu.validator.servlet.user-agent",
--                            "Validator.nu/LV")));
--
--            log4j.debug("Starting to loop over config file lines.");
--
--            while ((line = r.readLine()) != null) {
--                if ("".equals(line.trim())) {
--                    break;
--                }
--                String s[] = line.split("\t");
--                doctypes.add(s[0]);
--                namespaces.add(s[1]);
--                labels.add(s[2]);
--                urls.add(s[3]);
--            }
--
--            log4j.debug("Finished reading config.");
--
--            String[] presetDoctypesAsStrings = doctypes.toArray(new String[0]);
--            presetNamespaces = namespaces.toArray(new String[0]);
--            presetLabels = labels.toArray(new String[0]);
--            presetUrls = urls.toArray(new String[0]);
--
--            log4j.debug("Converted config to arrays.");
--
--            for (int i = 0; i < presetNamespaces.length; i++) {
--                String str = presetNamespaces[i];
--                if ("-".equals(str)) {
--                    presetNamespaces[i] = null;
--                } else {
--                    presetNamespaces[i] = presetNamespaces[i].intern();
--                }
--            }
--
--            log4j.debug("Prepared namespace array.");
--
--            presetDoctypes = new int[presetDoctypesAsStrings.length];
--            for (int i = 0; i < presetDoctypesAsStrings.length; i++) {
--                presetDoctypes[i] = Integer.parseInt(presetDoctypesAsStrings[i]);
--            }
--
--            log4j.debug("Parsed doctype numbers into ints.");
--
--            String prefix = System.getProperty("nu.validator.servlet.cachepathprefix");
--
--            log4j.debug("The cache path prefix is: " + prefix);
--
--            ErrorHandler eh = new SystemErrErrorHandler();
--            LocalCacheEntityResolver er = new LocalCacheEntityResolver(new NullEntityResolver());
--            er.setAllowRnc(true);
--            PropertyMapBuilder pmb = new PropertyMapBuilder();
--            pmb.put(ValidateProperty.ERROR_HANDLER, eh);
--            pmb.put(ValidateProperty.ENTITY_RESOLVER, er);
--            pmb.put(ValidateProperty.XML_READER_CREATOR,
--                    new VerifierServletXMLReaderCreator(eh, er));
--            RngProperty.CHECK_ID_IDREF.add(pmb);
--            PropertyMap pMap = pmb.toPropertyMap();
--
--            log4j.debug("Parsing set up. Starting to read schemas.");
--
--            SortedMap<String, Schema> schemaMap = new TreeMap<String, Schema>();
--
--            schemaMap.put("http://c.validator.nu/table/",
--                    CheckerSchema.TABLE_CHECKER);
--            schemaMap.put("http://hsivonen.iki.fi/checkers/table/",
--                    CheckerSchema.TABLE_CHECKER);
--            schemaMap.put("http://c.validator.nu/nfc/",
--                    CheckerSchema.NORMALIZATION_CHECKER);
--            schemaMap.put("http://hsivonen.iki.fi/checkers/nfc/",
--                    CheckerSchema.NORMALIZATION_CHECKER);
--            schemaMap.put("http://c.validator.nu/debug/",
--                    CheckerSchema.DEBUG_CHECKER);
--            schemaMap.put("http://hsivonen.iki.fi/checkers/debug/",
--                    CheckerSchema.DEBUG_CHECKER);
--            schemaMap.put("http://c.validator.nu/text-content/",
--                    CheckerSchema.TEXT_CONTENT_CHECKER);
--            schemaMap.put("http://hsivonen.iki.fi/checkers/text-content/",
--                    CheckerSchema.TEXT_CONTENT_CHECKER);
--            schemaMap.put("http://c.validator.nu/usemap/",
--                    CheckerSchema.USEMAP_CHECKER);
--            schemaMap.put("http://n.validator.nu/checkers/usemap/",
--                    CheckerSchema.USEMAP_CHECKER);
--            schemaMap.put("http://c.validator.nu/unchecked/",
--                    CheckerSchema.UNCHECKED_SUBTREE_WARNER);
--            schemaMap.put("http://s.validator.nu/html5/assertions.sch",
--                    CheckerSchema.ASSERTION_SCH);
--            schemaMap.put("http://s.validator.nu/html4/assertions.sch",
--                    CheckerSchema.HTML4ASSERTION_SCH);
--            schemaMap.put("http://c.validator.nu/obsolete/",
--                    CheckerSchema.CONFORMING_BUT_OBSOLETE_WARNER);
--            schemaMap.put("http://c.validator.nu/xml-pi/",
--                    CheckerSchema.XML_PI_CHECKER);
--            schemaMap.put("http://c.validator.nu/unsupported/",
--                    CheckerSchema.UNSUPPORTED_CHECKER);
--            schemaMap.put("http://c.validator.nu/microdata/",
--                    CheckerSchema.MICRODATA_CHECKER);
--            schemaMap.put("http://c.validator.nu/rdfalite/",
--                    CheckerSchema.RDFALITE_CHECKER);
--
--            for (int i = 0; i < presetUrls.length; i++) {
--                String[] urls1 = SPACE.split(presetUrls[i]);
--                for (int j = 0; j < urls1.length; j++) {
--                    String url = urls1[j];
--                    if (schemaMap.get(url) == null && !isCheckerUrl(url)) {
--                        Schema sch = schemaByUrl(url, er, pMap);
--                        schemaMap.put(url, sch);
--                    }
--                }
--            }
--
--            log4j.debug("Schemas read.");
--
--            preloadedSchemaUrls = new String[schemaMap.size()];
--            preloadedSchemas = new Schema[schemaMap.size()];
--            int i = 0;
--            for (Map.Entry<String, Schema> entry : schemaMap.entrySet()) {
--                preloadedSchemaUrls[i] = entry.getKey().intern();
--                Schema s = entry.getValue();
--                String u = entry.getKey();
--                if (isDataAttributeDroppingSchema(u)) {
--                    s = new DataAttributeDroppingSchemaWrapper(
--                            s);
--                }
--                if (isXmlLangAllowingSchema(u)) {
--                    s = new XmlLangAttributeDroppingSchemaWrapper(s);
--                }
--                if (isRoleAttributeFilteringSchema(u)) {
--                    s = new RoleAttributeFilteringSchemaWrapper(s);
--                }
--                preloadedSchemas[i] = s;
--                i++;
--            }
--
--            log4j.debug("Reading spec.");
--
--            html5spec = Html5SpecBuilder.parseSpec(LocalCacheEntityResolver.getHtml5SpecAsStream());
--
--            log4j.debug("Spec read.");
--
--            log4j.debug("Initialization complete.");
--        } catch (Exception e) {
--            throw new RuntimeException(e);
--        }
--    }
--
--    protected static String scrub(CharSequence s) {
--        return Normalizer.normalize(
--                CharacterUtil.prudentlyScrubCharacterData(s), Normalizer.NFC);
--    }
--
--    private static boolean isDataAttributeDroppingSchema(String key) {
--        return ("http://s.validator.nu/xhtml5.rnc".equals(key)
--                || "http://s.validator.nu/html5.rnc".equals(key)
--                || "http://s.validator.nu/html5-all.rnc".equals(key)
--                || "http://s.validator.nu/xhtml5-all.rnc".equals(key)
--                || "http://s.validator.nu/html5-its.rnc".equals(key)
--                || "http://s.validator.nu/xhtml5-rdfalite.rnc".equals(key)
--                || "http://s.validator.nu/html5-rdfalite.rnc".equals(key));
--    }
--
--    private static boolean isXmlLangAllowingSchema(String key) {
--        return ("http://s.validator.nu/xhtml5.rnc".equals(key)
--                || "http://s.validator.nu/html5.rnc".equals(key)
--                || "http://s.validator.nu/html5-all.rnc".equals(key)
--                || "http://s.validator.nu/xhtml5-all.rnc".equals(key)
--                || "http://s.validator.nu/html5-its.rnc".equals(key)
--                || "http://s.validator.nu/xhtml5-rdfalite.rnc".equals(key)
--                || "http://s.validator.nu/html5-rdfalite.rnc".equals(key));
--    }
--
--    private static boolean isRoleAttributeFilteringSchema(String key) {
--        return ("http://s.validator.nu/xhtml5.rnc".equals(key)
--                || "http://s.validator.nu/html5.rnc".equals(key)
--                || "http://s.validator.nu/html5-all.rnc".equals(key)
--                || "http://s.validator.nu/xhtml5-all.rnc".equals(key)
--                || "http://s.validator.nu/html5-its.rnc".equals(key)
--                || "http://s.validator.nu/xhtml5-rdfalite.rnc".equals(key)
--                || "http://s.validator.nu/html5-rdfalite.rnc".equals(key));
--    }
--
--    private static boolean isCheckerUrl(String url) {
--        if ("http://c.validator.nu/all/".equals(url)
--                || "http://hsivonen.iki.fi/checkers/all/".equals(url)) {
--            return true;
--        } else if ("http://c.validator.nu/all-html4/".equals(url)
--                || "http://hsivonen.iki.fi/checkers/all-html4/".equals(url)) {
--            return true;
--        } else if ("http://c.validator.nu/base/".equals(url)) {
--            return true;
--        } else if ("http://c.validator.nu/rdfalite/".equals(url)) {
--            return true;
--        }
--        for (int i = 0; i < ALL_CHECKERS.length; i++) {
--            if (ALL_CHECKERS[i].equals(url)) {
--                return true;
--            }
--        }
--        return false;
--    }
--
--    /**
--     * @param request
--     * @param response
--     */
--    VerifierServletTransaction(HttpServletRequest request,
--            HttpServletResponse response) {
--        this.request = request;
--        this.response = response;
--    }
--
--    protected boolean willValidate() {
--        if (methodIsGet) {
--            return document != null;
--        } else { // POST
--            return true;
--        }
--    }
--
--    void service() throws ServletException, IOException {
--        this.methodIsGet = "GET".equals(request.getMethod())
--                || "HEAD".equals(request.getMethod());
--
--        this.out = response.getOutputStream();
--
--        System.setProperty("nu.validator.servlet.request.legacy", "false");
--
--        if (Arrays.asList(LEGACY_HOSTS).contains(request.getRemoteHost())) {
--            System.setProperty("nu.validator.servlet.request.legacy", "true");
--        }
--
--        try {
--            request.setCharacterEncoding("utf-8");
--        } catch (NoSuchMethodError e) {
--            log4j.debug("Vintage Servlet API doesn't support setCharacterEncoding().", e);
--        }
--
--        if (!methodIsGet) {
--            postContentType = request.getContentType();
--            if (postContentType == null) {
--                response.sendError(HttpServletResponse.SC_BAD_REQUEST,
--                        "Content-Type missing");
--                return;
--            } else if (postContentType.trim().toLowerCase().startsWith(
--                    "application/x-www-form-urlencoded")) {
--                response.sendError(
--                        HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE,
--                        "application/x-www-form-urlencoded not supported. Please use multipart/form-data.");
--                return;
--            }
--        }
--
--        String outFormat = request.getParameter("out");
--        if (outFormat == null) {
--            outputFormat = OutputFormat.HTML;
--        } else {
--            if ("html".equals(outFormat)) {
--                outputFormat = OutputFormat.HTML;
--            } else if ("xhtml".equals(outFormat)) {
--                outputFormat = OutputFormat.XHTML;
--            } else if ("text".equals(outFormat)) {
--                outputFormat = OutputFormat.TEXT;
--            } else if ("gnu".equals(outFormat)) {
--                outputFormat = OutputFormat.GNU;
--            } else if ("xml".equals(outFormat)) {
--                outputFormat = OutputFormat.XML;
--            } else if ("json".equals(outFormat)) {
--                outputFormat = OutputFormat.JSON;
--            } else {
--                response.sendError(HttpServletResponse.SC_BAD_REQUEST,
--                        "Unsupported output format");
--                return;
--            }
--        }
--
--        if (!methodIsGet) {
--            document = request.getHeader("Content-Location");
--        }
--        if (document == null) {
--            document = request.getParameter("doc");
--        }
--        if (document == null) {
--            document = request.getParameter("file");
--        }
--
--        document = ("".equals(document)) ? null : document;
--
--        String callback = null;
--        if (outputFormat == OutputFormat.JSON) {
--            callback = request.getParameter("callback");
--            if (callback != null) {
--                Matcher m = JS_IDENTIFIER.matcher(callback);
--                if (m.matches()) {
--                    if (Arrays.binarySearch(JS_RESERVED_WORDS, callback) >= 0) {
--                        response.sendError(HttpServletResponse.SC_BAD_REQUEST,
--                                "Callback is a reserved word.");
--                        return;
--                    }
--                } else {
--                    response.sendError(HttpServletResponse.SC_BAD_REQUEST,
--                            "Callback is not a valid ECMA 262 IdentifierName.");
--                    return;
--                }
--            }
--        }
--
--        if (willValidate()) {
--            response.setDateHeader("Expires", 0);
--            response.setHeader("Cache-Control", "no-cache");
--        } else if (outputFormat == OutputFormat.HTML
--                || outputFormat == OutputFormat.XHTML) {
--            response.setDateHeader("Last-Modified", lastModified);
--        } else {
--            response.sendError(HttpServletResponse.SC_BAD_REQUEST,
--                    "No input document");
--            return;
--        }
--
--        setup();
--
--        if (request.getParameter("useragent") != null) {
--            userAgent = scrub(request.getParameter("useragent"));
--        } else {
--            userAgent = USER_AGENT;
--        }
--        showSource = (request.getParameter("showsource") != null);
--        showOutline = (request.getParameter("showoutline") != null);
--        if (request.getParameter("showimagereport") != null) {
--            imageCollector = new ImageCollector(sourceCode);
--        }
--
--        String charset = request.getParameter("charset");
--        if (charset != null) {
--            charset = scrub(charset.trim());
--            if (!"".equals(charset)) {
--                charsetOverride = charset;
--            }
--        }
--
--        String nsfilter = request.getParameter("nsfilter");
--        if (nsfilter != null) {
--            String[] nsfilterArr = SPACE.split(nsfilter);
--            for (int i = 0; i < nsfilterArr.length; i++) {
--                String ns = nsfilterArr[i];
--                if (ns.length() > 0) {
--                    filteredNamespaces.add(ns);
--                }
--            }
--        }
--
--        boolean errorsOnly = ("error".equals(request.getParameter("level")));
--
--        boolean asciiQuotes = (request.getParameter("asciiquotes") != null);
--
--        int lineOffset = 0;
--        String lineOffsetStr = request.getParameter("lineoffset");
--        if (lineOffsetStr != null) {
--            try {
--                lineOffset = Integer.parseInt(lineOffsetStr);
--            } catch (NumberFormatException e) {
--
--            }
--        }
--
--        try {
--            if (outputFormat == OutputFormat.HTML
--                    || outputFormat == OutputFormat.XHTML) {
--                if (outputFormat == OutputFormat.HTML) {
--                    response.setContentType("text/html; charset=utf-8");
--                    contentHandler = new HtmlSerializer(out);
--                } else {
--                    response.setContentType("application/xhtml+xml");
--                    contentHandler = 
--                            new XmlSerializer(out);
--                }
--                emitter = new XhtmlSaxEmitter(contentHandler);
--                errorHandler = new MessageEmitterAdapter(sourceCode,
--                        showSource, imageCollector, lineOffset, false,
--                        new XhtmlMessageEmitter(contentHandler));
--                PageEmitter.emit(contentHandler, this);
--            } else {
--                if (outputFormat == OutputFormat.TEXT) {
--                    response.setContentType("text/plain; charset=utf-8");
--                    errorHandler = new MessageEmitterAdapter(sourceCode,
--                            showSource, null, lineOffset, false,
--                            new TextMessageEmitter(out, asciiQuotes));
--                } else if (outputFormat == OutputFormat.GNU) {
--                    response.setContentType("text/plain; charset=utf-8");
--                    errorHandler = new MessageEmitterAdapter(sourceCode,
--                            showSource, null, lineOffset, false,
--                            new GnuMessageEmitter(out, asciiQuotes));
--                } else if (outputFormat == OutputFormat.XML) {
--                    response.setContentType("application/xml");
--                    errorHandler = new MessageEmitterAdapter(sourceCode,
--                            showSource, null, lineOffset, false,
--                            new XmlMessageEmitter(new XmlSerializer(out)));
--                } else if (outputFormat == OutputFormat.JSON) {
--                    if (callback == null) {
--                        response.setContentType("application/json; charset=utf-8");
--                    } else {
--                        response.setContentType("application/javascript; charset=utf-8");
--                    }
--                    errorHandler = new MessageEmitterAdapter(sourceCode,
--                            showSource, null, lineOffset, false,
--                            new JsonMessageEmitter(
--                                    new nu.validator.json.Serializer(out),
--                                    callback));
--                } else {
--                    throw new RuntimeException("Unreachable.");
--                }
--                errorHandler.setErrorsOnly(errorsOnly);
--                validate();
--            }
--        } catch (SAXException e) {
--            throw new ServletException(e);
--        }
--    }
--
--    /**
--     * @throws ServletException
--     */
--    protected void setup() throws ServletException {
--        String preset = request.getParameter("preset");
--
--        if (preset != null && !"".equals(preset)) {
--            schemaUrls = preset;
--        } else {
--            schemaUrls = request.getParameter("schema");
--        }
--        if (schemaUrls == null) {
--            schemaUrls = "";
--        }
--
--        String parserStr = request.getParameter("parser");
--
--        if ("html".equals(parserStr)) {
--            parser = ParserMode.HTML_AUTO;
--        } else if ("xmldtd".equals(parserStr)) {
--            parser = ParserMode.XML_EXTERNAL_ENTITIES_NO_VALIDATION;
--        } else if ("xml".equals(parserStr)) {
--            parser = ParserMode.XML_NO_EXTERNAL_ENTITIES;
--        } else if ("html5".equals(parserStr)) {
--            parser = ParserMode.HTML;
--        } else if ("html4".equals(parserStr)) {
--            parser = ParserMode.HTML401_STRICT;
--        } else if ("html4tr".equals(parserStr)) {
--            parser = ParserMode.HTML401_TRANSITIONAL;
--        } // else auto
--
--        laxType = (request.getParameter("laxtype") != null);
--    }
--
--    private boolean useHtml5Schema() {
--        if ("".equals(schemaUrls)) {
--            return false;
--        }
--        return (schemaUrls.contains("http://s.validator.nu/html5.rnc")
--                || schemaUrls.contains("http://s.validator.nu/html5-all.rnc")
--                || schemaUrls.contains("http://s.validator.nu/html5-its.rnc")
--                || schemaUrls.contains("http://s.validator.nu/html5-rdfalite.rnc"));
--    }
--
--    private boolean isHtmlUnsafePreset() {
--        if ("".equals(schemaUrls)) {
--            return false;
--        }
--        boolean preset = false;
--        for (int i = 0; i < presetUrls.length; i++) {
--            if (presetUrls[i].equals(schemaUrls)) {
--                preset = true;
--                break;
--            }
--        }
--        if (!preset) {
--            return false;
--        }
--        return !(schemaUrls.startsWith("http://s.validator.nu/xhtml10/xhtml-basic.rnc")
--                || schemaUrls.startsWith("http://s.validator.nu/xhtml10/xhtml-strict.rnc")
--                || schemaUrls.startsWith("http://s.validator.nu/xhtml10/xhtml-transitional.rnc")
--                || schemaUrls.startsWith("http://s.validator.nu/xhtml10/xhtml-frameset.rnc")
--                || schemaUrls.startsWith("http://s.validator.nu/html5.rnc")
--                || schemaUrls.startsWith("http://s.validator.nu/html5-all.rnc")
--                || schemaUrls.startsWith("http://s.validator.nu/html5-its.rnc")
--                || schemaUrls.startsWith("http://s.validator.nu/html5-rdfalite.rnc"));
--
--    }
--
--    /**
--     * @throws SAXException
--     */
--    @SuppressWarnings("deprecation") void validate() throws SAXException {
--        if (!willValidate()) {
--            return;
--        }
--
--        boolean isHtmlOrXhtml = (outputFormat == OutputFormat.HTML || outputFormat == OutputFormat.XHTML);
--        if (isHtmlOrXhtml) {
--            try {
--                out.flush();
--            } catch (IOException e1) {
--                throw new SAXException(e1);
--            }
--        }
--        httpRes = new PrudentHttpEntityResolver(SIZE_LIMIT, laxType,
--                errorHandler);
--        httpRes.setUserAgent(userAgent);
--        dataRes = new DataUriEntityResolver(httpRes, laxType, errorHandler);
--        contentTypeParser = new ContentTypeParser(errorHandler, laxType);
--        entityResolver = new LocalCacheEntityResolver(dataRes);
--        setAllowRnc(true);
--        try {
--            this.errorHandler.start(document);
--            PropertyMapBuilder pmb = new PropertyMapBuilder();
--            pmb.put(ValidateProperty.ERROR_HANDLER, errorHandler);
--            pmb.put(ValidateProperty.ENTITY_RESOLVER, entityResolver);
--            pmb.put(ValidateProperty.XML_READER_CREATOR,
--                    new VerifierServletXMLReaderCreator(errorHandler,
--                            entityResolver));
--            pmb.put(ValidateProperty.SCHEMA_RESOLVER, this);
--            RngProperty.CHECK_ID_IDREF.add(pmb);
--            jingPropertyMap = pmb.toPropertyMap();
--
--            tryToSetupValidator();
--
--            setAllowRnc(false);
--
--            loadDocAndSetupParser();
--            setErrorProfile();
--
--            reader.setErrorHandler(errorHandler);
--            contentType = documentInput.getType();
--            sourceCode.initialize(documentInput);
--            if (validator == null) {
--                checkNormalization = true;
--            }
--            if (checkNormalization) {
--                reader.setFeature(
--                        "http://xml.org/sax/features/unicode-normalization-checking",
--                        true);
--            }
--            WiretapXMLReaderWrapper wiretap = new WiretapXMLReaderWrapper(
--                    reader);
--            ContentHandler recorder = sourceCode.getLocationRecorder();
--            if (baseUriTracker == null) {
--                wiretap.setWiretapContentHander(recorder);
--            } else {
--                wiretap.setWiretapContentHander(new CombineContentHandler(
--                        recorder, baseUriTracker));
--            }
--            wiretap.setWiretapLexicalHandler((LexicalHandler) recorder);
--            reader = wiretap;
--            if (htmlParser != null) {
--                htmlParser.addCharacterHandler(sourceCode);
--                htmlParser.setMappingLangToXmlLang(true);
--                htmlParser.setErrorHandler(errorHandler.getExactErrorHandler());
--                htmlParser.setTreeBuilderErrorHandlerOverride(errorHandler);
--                errorHandler.setHtml(true);
--            } else if (xmlParser != null) {
--                // this must be after wiretap!
--                if (!filteredNamespaces.isEmpty()) {
--                    reader = new NamespaceDroppingXMLReaderWrapper(reader,
--                            filteredNamespaces);
--                }
--                xmlParser.setErrorHandler(errorHandler.getExactErrorHandler());
--                xmlParser.lockErrorHandler();
--            } else {
--                throw new RuntimeException("Bug. Unreachable.");
--            }
--            reader = new AttributesPermutingXMLReaderWrapper(reader); // make
--            // RNG
--            // validation
--            // better
--            if (charsetOverride != null) {
--                String charset = documentInput.getEncoding();
--                if (charset == null) {
--                    errorHandler.warning(new SAXParseException(
--                            "Overriding document character encoding from none to \u201C"
--                                    + charsetOverride + "\u201D.", null));
--                } else {
--                    errorHandler.warning(new SAXParseException(
--                            "Overriding document character encoding from \u201C"
--                                    + charset + "\u201D to \u201C"
--                                    + charsetOverride + "\u201D.", null));
--                }
--                documentInput.setEncoding(charsetOverride);
--            }
--            if (showOutline) {
--                reader = new OutlineBuildingXMLReaderWrapper(reader, request);
--                reader.parse(documentInput);
--                outline = (Deque<Section>) request.getAttribute("http://validator.nu/properties/document-outline");
--            } else {
--                reader.parse(documentInput);
--            }
--        } catch (TooManyErrorsException e) {
--            log4j.debug("TooManyErrorsException", e);
--            errorHandler.fatalError(e);
--        } catch (SAXException e) {
--            log4j.debug("SAXException", e);
--        } catch (IOException e) {
--            isHtmlOrXhtml = false;
--            log4j.info("IOException", e);
--            errorHandler.ioError(e);
--        } catch (IncorrectSchemaException e) {
--            log4j.debug("IncorrectSchemaException", e);
--            errorHandler.schemaError(e);
--        } catch (RuntimeException e) {
--            isHtmlOrXhtml = false;
--            log4j.error("RuntimeException, doc: " + document + " schema: "
--                    + schemaUrls + " lax: " + laxType, e);
--            errorHandler.internalError(
--                    e,
--                    "Oops. That was not supposed to happen. A bug manifested itself in the application internals. Unable to continue. Sorry. The admin was notified.");
--        } catch (Error e) {
--            isHtmlOrXhtml = false;
--            log4j.error("Error, doc: " + document + " schema: " + schemaUrls
--                    + " lax: " + laxType, e);
--            errorHandler.internalError(
--                    e,
--                    "Oops. That was not supposed to happen. A bug manifested itself in the application internals. Unable to continue. Sorry. The admin was notified.");
--        } finally {
--            errorHandler.end(successMessage(), failureMessage());
--            gatherStatistics();
--        }
--        if (isHtmlOrXhtml) {
--            XhtmlOutlineEmitter outlineEmitter = new XhtmlOutlineEmitter(
--                    contentHandler, outline);
--            outlineEmitter.emit();
--            StatsEmitter.emit(contentHandler, this);
--        }
--    }
--
--    private void gatherStatistics() {
--        Statistics stats = Statistics.STATISTICS;
--        if (stats == null) {
--            return;
--        }
--        synchronized (stats) {
--            stats.incrementTotal();
--            if (charsetOverride != null) {
--                stats.incrementField(Statistics.Field.CUSTOM_ENC);
--            }
--            switch (parser) {
--                case HTML401_STRICT:
--                case HTML401_TRANSITIONAL:
--                    stats.incrementField(Statistics.Field.PARSER_HTML4);
--                    break;
--                case XML_EXTERNAL_ENTITIES_NO_VALIDATION:
--                    stats.incrementField(Statistics.Field.PARSER_XML_EXTERNAL);
--                    break;
--            }
--            if (!filteredNamespaces.isEmpty()) {
--                stats.incrementField(Statistics.Field.XMLNS_FILTER);
--            }
--            if (laxType) {
--                stats.incrementField(Statistics.Field.LAX_TYPE);
--            }
--            if (imageCollector != null) {
--                stats.incrementField(Statistics.Field.IMAGE_REPORT);
--            }
--            if (showSource) {
--                stats.incrementField(Statistics.Field.SHOW_SOURCE);
--            }
--            if (showOutline) {
--                stats.incrementField(Statistics.Field.SHOW_OUTLINE);
--            }
--            if (methodIsGet) {
--                stats.incrementField(Statistics.Field.INPUT_GET);
--            } else { // POST
--                stats.incrementField(Statistics.Field.INPUT_POST);
--                Object inputType = request.getAttribute("nu.validator.servlet.MultipartFormDataFilter.type");
--                if ("textarea".equals(inputType)) {
--                    stats.incrementField(Statistics.Field.INPUT_TEXT_FIELD);
--                } else if ("file".equals(inputType)) {
--                    stats.incrementField(Statistics.Field.INPUT_FILE_UPLOAD);
--                } else {
--                    stats.incrementField(Statistics.Field.INPUT_ENTITY_BODY);
--                }
--            }
--            if (htmlParser != null) {
--                stats.incrementField(Statistics.Field.INPUT_HTML);
--            }
--            if (xmlParser != null) {
--                stats.incrementField(Statistics.Field.INPUT_XML);
--            }
--            switch (outputFormat) {
--                case GNU:
--                    stats.incrementField(Statistics.Field.OUTPUT_GNU);
--                    break;
--                case HTML:
--                    stats.incrementField(Statistics.Field.OUTPUT_HTML);
--                    break;
--                case JSON:
--                    stats.incrementField(Statistics.Field.OUTPUT_JSON);
--                    break;
--                case TEXT:
--                    stats.incrementField(Statistics.Field.OUTPUT_TEXT);
--                    break;
--                case XHTML:
--                    stats.incrementField(Statistics.Field.OUTPUT_XHTML);
--                    break;
--                case XML:
--                    stats.incrementField(Statistics.Field.OUTPUT_XML);
--                    break;
--            }
--            if (schemaListForStats == null) {
--                stats.incrementField(Statistics.Field.LOGIC_ERROR);
--            } else {
--                boolean preset = false;
--                for (int i = 0; i < presetUrls.length; i++) {
--                    if (presetUrls[i].equals(schemaListForStats)) {
--                        preset = true;
--                        if (externalSchema || externalSchematron) {
--                            stats.incrementField(Statistics.Field.LOGIC_ERROR);
--                        } else {
--                            stats.incrementField(Statistics.Field.PRESET_SCHEMA);
--                            /*
--                             * XXX WARNING WARNING: These mappings correspond to
--                             * values in the presets.txt file in the validator
--                             * source repo. They might be bogus if a custom
--                             * presets file is used instead.
--                             */
--                            switch (i) {
--                                case 0:
--                                case 5:
--                                    stats.incrementField(Statistics.Field.HTML5_SCHEMA);
--                                    break;
--                                case 1:
--                                case 6:
--                                    stats.incrementField(Statistics.Field.HTML5_RDFA_LITE_SCHEMA);
--                                    break;
--                                case 2:
--                                    stats.incrementField(Statistics.Field.HTML4_STRICT_SCHEMA);
--                                    break;
--                                case 3:
--                                    stats.incrementField(Statistics.Field.HTML4_TRANSITIONAL_SCHEMA);
--                                    break;
--                                case 4:
--                                    stats.incrementField(Statistics.Field.HTML4_FRAMESET_SCHEMA);
--                                    break;
--                                case 7:
--                                    stats.incrementField(Statistics.Field.XHTML1_COMPOUND_SCHEMA);
--                                    break;
--                                case 8:
--                                    stats.incrementField(Statistics.Field.SVG_SCHEMA);
--                                    break;
--                                default:
--                                    stats.incrementField(Statistics.Field.LOGIC_ERROR);
--                                    break;
--                            }
--                        }
--                        break;
--                    }
--                }
--                if (!preset && !externalSchema) {
--                    stats.incrementField(Statistics.Field.BUILT_IN_NON_PRESET);
--                }
--            }
--            if ("".equals(schemaUrls)) {
--                stats.incrementField(Statistics.Field.AUTO_SCHEMA);
--                if (externalSchema) {
--                    stats.incrementField(Statistics.Field.LOGIC_ERROR);
--                }
--            } else if (externalSchema) {
--                if (externalSchematron) {
--                    stats.incrementField(Statistics.Field.EXTERNAL_SCHEMA_SCHEMATRON);
--                } else {
--                    stats.incrementField(Statistics.Field.EXTERNAL_SCHEMA_NON_SCHEMATRON);
--                }
--            } else if (externalSchematron) {
--                stats.incrementField(Statistics.Field.LOGIC_ERROR);
--            }
--        }
--    }
--
--    /**
--     * @return
--     * @throws SAXException
--     */
--    protected String successMessage() throws SAXException {
--        return "The document validates according to the specified schema(s) and to additional constraints checked by the validator.";
--    }
--
--    protected String failureMessage() throws SAXException {
--        return "There were errors.";
--    }
--
--    /**
--     * @throws SAXException
--     * @throws IOException
--     * @throws IncorrectSchemaException
--     */
--    protected void tryToSetupValidator() throws SAXException, IOException,
--            IncorrectSchemaException {
--        validator = validatorByUrls(schemaUrls);
--    }
--
--    protected void setErrorProfile() {
--        profile = request.getParameter("profile");
--
--        HashMap<String, String> profileMap = new HashMap<String, String>();
--
--        if ("pedagogical".equals(profile)) {
--            profileMap.put("xhtml1", "warn");
--        } else if ("polyglot".equals(profile)) {
--            profileMap.put("xhtml1", "warn");
--            profileMap.put("xhtml2", "warn");
--        } else {
--            return; // presumed to be permissive
--        }
--
--        htmlParser.setErrorProfile(profileMap);
--    }
--
--    /**
--     * @throws SAXException
--     * @throws IOException
--     * @throws IncorrectSchemaException
--     * @throws SAXNotRecognizedException
--     * @throws SAXNotSupportedException
--     */
--    protected void loadDocAndSetupParser() throws SAXException, IOException,
--            IncorrectSchemaException, SAXNotRecognizedException,
--            SAXNotSupportedException {
--        switch (parser) {
--            case HTML_AUTO:
--            case HTML:
--            case HTML401_STRICT:
--            case HTML401_TRANSITIONAL:
--                if (isHtmlUnsafePreset()) {
--                    String message = "The chosen preset schema is not appropriate for HTML.";
--                    SAXException se = new SAXException(message);
--                    errorHandler.schemaError(se);
--                    throw se;
--                }
--                setAllowGenericXml(false);
--                setAllowHtml(true);
--                setAcceptAllKnownXmlTypes(false);
--                setAllowXhtml(false);
--                loadDocumentInput();
--                newHtmlParser();
--                DoctypeExpectation doctypeExpectation;
--                int schemaId;
--                switch (parser) {
--                    case HTML:
--                        doctypeExpectation = DoctypeExpectation.HTML;
--                        schemaId = HTML5_SCHEMA;
--                        break;
--                    case HTML401_STRICT:
--                        doctypeExpectation = DoctypeExpectation.HTML401_STRICT;
--                        schemaId = XHTML1STRICT_SCHEMA;
--                        break;
--                    case HTML401_TRANSITIONAL:
--                        doctypeExpectation = DoctypeExpectation.HTML401_TRANSITIONAL;
--                        schemaId = XHTML1TRANSITIONAL_SCHEMA;
--                        break;
--                    default:
--                        doctypeExpectation = DoctypeExpectation.AUTO;
--                        schemaId = 0;
--                        break;
--                }
--                htmlParser.setDoctypeExpectation(doctypeExpectation);
--                htmlParser.setDocumentModeHandler(this);
--                reader = htmlParser;
--                if (validator == null) {
--                    validator = validatorByDoctype(schemaId);
--                }
--                if (validator != null) {
--                    reader.setContentHandler(validator.getContentHandler());
--                }
--                break;
--            case XML_NO_EXTERNAL_ENTITIES:
--            case XML_EXTERNAL_ENTITIES_NO_VALIDATION:
--                setAllowGenericXml(true);
--                setAllowHtml(false);
--                setAcceptAllKnownXmlTypes(true);
--                setAllowXhtml(true);
--                loadDocumentInput();
--                setupXmlParser();
--                break;
--            default:
--                setAllowGenericXml(true);
--                setAllowHtml(true);
--                setAcceptAllKnownXmlTypes(true);
--                setAllowXhtml(true);
--                loadDocumentInput();
--                String type = documentInput.getType();
--                if ("text/html".equals(type) || "text/html-sandboxed".equals(type)) {
--                    if (isHtmlUnsafePreset()) {
--                        String message = "The Content-Type was \u201C" + type + "\u201D, but the chosen preset schema is not appropriate for HTML.";
--                        SAXException se = new SAXException(message);
--                        errorHandler.schemaError(se);
--                        throw se;
--                    }
--                    errorHandler.info("The Content-Type was \u201C" + type + "\u201D. Using the HTML parser.");
--                    newHtmlParser();
--                    if (useHtml5Schema()) {
--                        htmlParser.setDoctypeExpectation(DoctypeExpectation.HTML);
--                    } else {
--                        htmlParser.setDoctypeExpectation(DoctypeExpectation.AUTO);
--                    }
--                    htmlParser.setDocumentModeHandler(this);
--                    reader = htmlParser;
--                    if (validator != null) {
--                        reader.setContentHandler(validator.getContentHandler());
--                    }
--                } else {
--                    errorHandler.info("The Content-Type was \u201C"
--                            + type
--                            + "\u201D. Using the XML parser (not resolving external entities).");
--                    setupXmlParser();
--                }
--                break;
--        }
--    }
--
--    /**
--     * 
--     */
--    protected void newHtmlParser() {
--        htmlParser = new HtmlParser();
--        htmlParser.setCommentPolicy(XmlViolationPolicy.ALLOW);
--        htmlParser.setContentNonXmlCharPolicy(XmlViolationPolicy.ALLOW);
--        htmlParser.setContentSpacePolicy(XmlViolationPolicy.ALTER_INFOSET);
--        htmlParser.setNamePolicy(XmlViolationPolicy.ALLOW);
--        htmlParser.setStreamabilityViolationPolicy(XmlViolationPolicy.FATAL);
--        htmlParser.setXmlnsPolicy(XmlViolationPolicy.ALTER_INFOSET);
--        htmlParser.setMappingLangToXmlLang(true);
--        htmlParser.setHtml4ModeCompatibleWithXhtml1Schemata(true);
--        htmlParser.setHeuristics(Heuristics.ALL);
--    }
--
--    protected Validator validatorByDoctype(int schemaId) throws SAXException,
--            IOException, IncorrectSchemaException {
--        if (schemaId == 0) {
--            return null;
--        }
--        for (int i = 0; i < presetDoctypes.length; i++) {
--            if (presetDoctypes[i] == schemaId) {
--                return validatorByUrls(presetUrls[i]);
--            }
--        }
--        throw new RuntimeException("Doctype mappings not initialized properly.");
--    }
--
--    /**
--     * @throws SAXNotRecognizedException
--     * @throws SAXNotSupportedException
--     */
--    protected void setupXmlParser() throws SAXNotRecognizedException,
--            SAXNotSupportedException {
--        xmlParser = new SAXDriver();
--        xmlParser.setCharacterHandler(sourceCode);
--        if (lexicalHandler != null) {
--          xmlParser.setProperty("http://xml.org/sax/properties/lexical-handler",
--              (LexicalHandler) lexicalHandler);
--        }
--        reader = new IdFilter(xmlParser);
--        reader.setFeature("http://xml.org/sax/features/string-interning", true);
--        reader.setFeature(
--                "http://xml.org/sax/features/external-general-entities",
--                parser == ParserMode.XML_EXTERNAL_ENTITIES_NO_VALIDATION);
--        reader.setFeature(
--                "http://xml.org/sax/features/external-parameter-entities",
--                parser == ParserMode.XML_EXTERNAL_ENTITIES_NO_VALIDATION);
--        if (parser == ParserMode.XML_EXTERNAL_ENTITIES_NO_VALIDATION) {
--            reader.setEntityResolver(entityResolver);
--        } else {
--            reader.setEntityResolver(new NullEntityResolver());
--        }
--        if (validator == null) {
--            bufferingRootNamespaceSniffer = new BufferingRootNamespaceSniffer(
--                    this);
--            reader.setContentHandler(bufferingRootNamespaceSniffer);
--        } else {
--            reader.setContentHandler(new RootNamespaceSniffer(this,
--                    validator.getContentHandler()));
--            reader.setDTDHandler(validator.getDTDHandler());
--        }
--    }
--
--    /**
--     * @param validator
--     * @return
--     * @throws SAXException
--     * @throws IOException
--     * @throws IncorrectSchemaException
--     */
--    private Validator validatorByUrls(String schemaList) throws SAXException,
--            IOException, IncorrectSchemaException {
--        System.setProperty("nu.validator.schema.rdfa-full", "0");
--        schemaListForStats  = schemaList;
--        Validator v = null;
--        String[] schemas = SPACE.split(schemaList);
--        for (int i = schemas.length - 1; i > -1; i--) {
--            String url = schemas[i];
--            if ("http://s.validator.nu/html5-all.rnc".equals(url)) {
--                System.setProperty("nu.validator.schema.rdfa-full", "1");
--            }
--            if ("http://c.validator.nu/all/".equals(url)
--                    || "http://hsivonen.iki.fi/checkers/all/".equals(url)) {
--                for (int j = 0; j < ALL_CHECKERS.length; j++) {
--                    v = combineValidatorByUrl(v, ALL_CHECKERS[j]);
--                }
--            } else if ("http://c.validator.nu/all-html4/".equals(url)
--                    || "http://hsivonen.iki.fi/checkers/all-html4/".equals(url)) {
--                for (int j = 0; j < ALL_CHECKERS_HTML4.length; j++) {
--                    v = combineValidatorByUrl(v, ALL_CHECKERS_HTML4[j]);
--                }
--            } else {
--                v = combineValidatorByUrl(v, url);
--            }
--        }
--        if (imageCollector != null && v != null) {
--            v = new CombineValidator(imageCollector, v);
--        }
--        return v;
--    }
--
--    /**
--     * @param val
--     * @param url
--     * @return
--     * @throws SAXException
--     * @throws IOException
--     * @throws IncorrectSchemaException
--     */
--    private Validator combineValidatorByUrl(Validator val, String url)
--            throws SAXException, IOException, IncorrectSchemaException {
--        if (!"".equals(url)) {
--            Validator v = validatorByUrl(url);
--            if (val == null) {
--                val = v;
--            } else {
--                val = new CombineValidator(v, val);
--            }
--        }
--        return val;
--    }
--
--    /**
--     * @param url
--     * @return
--     * @throws SAXException
--     * @throws IOException
--     * @throws IncorrectSchemaException
--     */
--    private Validator validatorByUrl(String url) throws SAXException,
--            IOException, IncorrectSchemaException {
--        if (loadedValidatorUrls.contains(url)) {
--            return null;
--        }
--        loadedValidatorUrls.add(url);
--        if ("http://s.validator.nu/xhtml5.rnc".equals(url)
--                || "http://s.validator.nu/html5.rnc".equals(url)
--                || "http://s.validator.nu/html5-all.rnc".equals(url)
--                || "http://s.validator.nu/xhtml5-all.rnc".equals(url)
--                || "http://s.validator.nu/html5-its.rnc".equals(url)
--                || "http://s.validator.nu/xhtml5-rdfalite.rnc".equals(url)
--                || "http://s.validator.nu/html5-rdfalite.rnc".equals(url)) {
--            errorHandler.setSpec(html5spec);
--        }
--        Schema sch = resolveSchema(url, jingPropertyMap);
--        Validator validator = sch.createValidator(jingPropertyMap);
--        if (validator.getContentHandler() instanceof XmlPiChecker) {
--          lexicalHandler = (LexicalHandler) validator.getContentHandler();
--        }
--        return validator;
--    }
--
--    public Schema resolveSchema(String url, PropertyMap options)
--            throws SAXException, IOException, IncorrectSchemaException {
--        int i = Arrays.binarySearch(preloadedSchemaUrls, url);
--        if (i > -1) {
--            Schema rv = preloadedSchemas[i];
--            if (options.contains(WrapProperty.ATTRIBUTE_OWNER)) {
--                if (rv instanceof CheckerSchema) {
--                    errorHandler.error(new SAXParseException(
--                            "A non-schema checker cannot be used as an attribute schema.",
--                            null, url, -1, -1));
--                    throw new IncorrectSchemaException();
--                } else {
--                    // ugly fall through
--                }
--            } else {
--                return rv;
--            }
--        }
--
--        externalSchema  = true;
--
--        TypedInputSource schemaInput = (TypedInputSource) entityResolver.resolveEntity(
--                null, url);
--        SchemaReader sr = null;
--        if ("application/relax-ng-compact-syntax".equals(schemaInput.getType())) {
--            sr = CompactSchemaReader.getInstance();
--        } else {
--            sr = new AutoSchemaReader();
--        }
--        Schema sch = sr.createSchema(schemaInput, options);
--
--        if (Statistics.STATISTICS != null && "com.thaiopensource.validate.schematron.SchemaImpl".equals(sch.getClass().getName())) {
--            externalSchematron  = true;
--        }
--
--        return sch;
--    }
--
--    /**
--     * @param url
--     * @return
--     * @throws SAXException
--     * @throws IOException
--     * @throws IncorrectSchemaException
--     */
--    private static Schema schemaByUrl(String url, EntityResolver resolver,
--            PropertyMap pMap) throws SAXException, IOException,
--            IncorrectSchemaException {
--        log4j.debug("Will load schema: " + url);
--        TypedInputSource schemaInput;
--        try {
--        schemaInput = (TypedInputSource) resolver.resolveEntity(
--                null, url);
--        } catch (ClassCastException e) {
--            log4j.fatal(url, e);
--            throw e;
--        }
--        SchemaReader sr = null;
--        if ("application/relax-ng-compact-syntax".equals(schemaInput.getType())) {
--            sr = CompactSchemaReader.getInstance();
--        } else {
--            sr = new AutoSchemaReader();
--        }
--        Schema sch = sr.createSchema(schemaInput, pMap);
--        return sch;
--    }
--
--    /**
--     * @throws SAXException
--     */
--    void emitTitle(boolean markupAllowed) throws SAXException {
--        if (willValidate()) {
--            emitter.characters(RESULTS_TITLE);
--            emitter.characters(FOR);
--            if (document != null && document.length() > 0) {
--                emitter.characters(scrub(shortenDataUri(document)));
--            } else if (request.getAttribute("nu.validator.servlet.MultipartFormDataFilter.filename") != null) {
--                emitter.characters("uploaded file "
--                        + scrub(request.getAttribute(
--                                "nu.validator.servlet.MultipartFormDataFilter.filename").toString()));
--            } else {
--                emitter.characters("contents of text-input area");
--            }
--        } else {
--            emitter.characters(SERVICE_TITLE);
--            if (markupAllowed
--                    && System.getProperty("nu.validator.servlet.service-name",
--                            "").equals("Validator.nu")) {
--                emitter.startElement("span");
--                emitter.characters(LIVING_VERSION);
--                emitter.endElement("span");
--            }
--        }
--    }
--
--    protected String shortenDataUri(String uri) {
--        if (DataUri.startsWithData(uri)) {
--            return "data:\u2026";
--        } else {
--            return uri;
--        }
--    }
--
--    void emitForm() throws SAXException {
--        attrs.clear();
--        attrs.addAttribute("method", "get");
--//        attrs.addAttribute("action", request.getRequestURL().toString());
--        if (isSimple()) {
--            attrs.addAttribute("class", "simple");
--        }
--        // attrs.addAttribute("onsubmit", "formSubmission()");
--        emitter.startElement("form", attrs);
--        emitFormContent();
--        emitter.endElement("form");
--    }
--
--    protected boolean isSimple() {
--        return false;
--    }
--
--    /**
--     * @throws SAXException
--     */
--    protected void emitFormContent() throws SAXException {
--        FormEmitter.emit(contentHandler, this);
--    }
--
--    void emitSchemaField() throws SAXException {
--        attrs.clear();
--        attrs.addAttribute("name", "schema");
--        attrs.addAttribute("id", "schema");
--        // attrs.addAttribute("onchange", "schemaChanged();");
--        attrs.addAttribute(
--                "pattern",
--                "(?:(?:(?:https?://\\S+)|(?:data:\\S+))(?:\\s+(?:(?:https?://\\S+)|(?:data:\\S+)))*)?");
--        attrs.addAttribute("title",
--                "Space-separated list of schema IRIs. (Leave blank to let the service guess.)");
--        if (schemaUrls != null) {
--            attrs.addAttribute("value", scrub(schemaUrls));
--        }
--        emitter.startElement("input", attrs);
--        emitter.endElement("input");
--    }
--
--    void emitDocField() throws SAXException {
--        attrs.clear();
--        attrs.addAttribute("type", "url");
--        attrs.addAttribute("name", "doc");
--        attrs.addAttribute("id", "doc");
--        attrs.addAttribute("pattern", "(?:(?:https?://.+)|(?:data:.+))?");
--        attrs.addAttribute("title",
--                "Absolute IRI (http, https or data only) of the document to be checked.");
--        if (document != null) {
--            attrs.addAttribute("value", scrub(document));
--        }
--        Object att = request.getAttribute("nu.validator.servlet.MultipartFormDataFilter.type");
--        if (att != null) {
--            attrs.addAttribute("class", att.toString());
--        }
--        emitter.startElement("input", attrs);
--        emitter.endElement("input");
--    }
--
--    /**
--     * @throws SAXException
--     * 
--     */
--    void emitSchemaDuration() throws SAXException {
--    }
--
--    /**
--     * @throws SAXException
--     * 
--     */
--    void emitDocDuration() throws SAXException {
--    }
--
--    /**
--     * @throws SAXException
--     * 
--     */
--    void emitTotalDuration() throws SAXException {
--        emitter.characters("" + (System.currentTimeMillis() - start));
--    }
--
--    /**
--     * @throws SAXException
--     * 
--     */
--    void emitPresetOptions() throws SAXException {
--        for (int i = 0; i < presetUrls.length; i++) {
--            emitter.option(presetLabels[i], presetUrls[i], false);
--        }
--    }
--
--    /**
--     * @throws SAXException
--     * 
--     */
--    void emitParserOptions() throws SAXException {
--        emitter.option("Automatically from Content-Type", "",
--                (parser == ParserMode.AUTO));
--        emitter.option("XML; don\u2019t load external entities", "xml",
--                (parser == ParserMode.XML_NO_EXTERNAL_ENTITIES));
--        emitter.option("XML; load external entities", "xmldtd",
--                (parser == ParserMode.XML_EXTERNAL_ENTITIES_NO_VALIDATION));
--        emitter.option("HTML; flavor from doctype", "html",
--                (parser == ParserMode.HTML_AUTO));
--        emitter.option("HTML5", "html5", (parser == ParserMode.HTML));
--        emitter.option("HTML 4.01 Strict", "html4",
--                (parser == ParserMode.HTML401_STRICT));
--        emitter.option("HTML 4.01 Transitional", "html4tr",
--                (parser == ParserMode.HTML401_TRANSITIONAL));
--    }
--
--    /**
--     * @throws SAXException
--     * 
--     */
--    void emitProfileOptions() throws SAXException {
--        profile = request.getParameter("profile");
--
--        emitter.option("Permissive: only what the spec requires",
--                "", ("".equals(profile)));
--        emitter.option("Pedagogical: suitable for teaching purposes",
--                "pedagogical", ("pedagogical".equals(profile)));
--        emitter.option("Polyglot: works both as HTML and as XML",
--                "polyglot", ("polyglot".equals(profile)));
--    }
--
--    /**
--     * @throws SAXException
--     * 
--     */
--    void emitLaxTypeField() throws SAXException {
--        emitter.checkbox("laxtype", "yes", laxType);
--    }
--
--    /**
--     * @throws SAXException
--     * 
--     */
--    void emitShowSourceField() throws SAXException {
--        emitter.checkbox("showsource", "yes", showSource);
--    }
--
--    /**
--     * @throws SAXException
--     *
--     */
--    void emitShowOutlineField() throws SAXException {
--        emitter.checkbox("showoutline", "yes", showOutline);
--    }
--
--    /**
--     * @throws SAXException
--     * 
--     */
--    void emitShowImageReportField() throws SAXException {
--        emitter.checkbox("showimagereport", "yes", imageCollector != null);
--    }
--
--    void rootNamespace(String namespace, Locator locator) throws SAXException {
--        if (validator == null) {
--            int index = -1;
--            for (int i = 0; i < presetNamespaces.length; i++) {
--                if (namespace.equals(presetNamespaces[i])) {
--                    index = i;
--                    break;
--                }
--            }
--            if (index == -1) {
--                String message = "Cannot find preset schema for namespace: \u201C"
--                        + namespace + "\u201D.";
--                SAXException se = new SAXException(message);
--                errorHandler.schemaError(se);
--                throw se;
--            }
--            String label = presetLabels[index];
--            String urls = presetUrls[index];
--            errorHandler.info("Using the preset for " + label
--                    + " based on the root namespace.");
--            try {
--                validator = validatorByUrls(urls);
--            } catch (IOException ioe) {
--                // At this point the schema comes from memory.
--                throw new RuntimeException(ioe);
--            } catch (IncorrectSchemaException e) {
--                // At this point the schema comes from memory.
--                throw new RuntimeException(e);
--            }
--            if (bufferingRootNamespaceSniffer == null) {
--                throw new RuntimeException(
--                        "Bug! bufferingRootNamespaceSniffer was null.");
--            }
--            bufferingRootNamespaceSniffer.setContentHandler(validator.getContentHandler());
--        }
--
--        if (!rootNamespaceSeen) {
--            rootNamespaceSeen = true;
--            if (contentType != null) {
--                int i;
--                if ((i = Arrays.binarySearch(KNOWN_CONTENT_TYPES, contentType)) > -1) {
--                    if (!NAMESPACES_FOR_KNOWN_CONTENT_TYPES[i].equals(namespace)) {
--                        String message = "".equals(namespace) ? "\u201C"
--                                + contentType
--                                + "\u201D is not an appropriate Content-Type for a document whose root element is not in a namespace."
--                                : "\u201C"
--                                        + contentType
--                                        + "\u201D is not an appropriate Content-Type for a document whose root namespace is \u201C"
--                                        + namespace + "\u201D.";
--                        SAXParseException spe = new SAXParseException(message,
--                                locator);
--                        errorHandler.warning(spe);
--                    }
--                }
--            }
--        }
--    }
--
--    public void documentMode(DocumentMode mode, String publicIdentifier,
--            String systemIdentifier, boolean html4SpecificAdditionalErrorChecks)
--            throws SAXException {
--        if (validator == null) {
--            try {
--                if ("yes".equals(request.getParameter("sniffdoctype"))) {
--                    if ("-//W3C//DTD XHTML 1.0 Transitional//EN".equals(publicIdentifier)) {
--                        errorHandler.info("XHTML 1.0 Transitional doctype seen. Appendix C is not supported. Proceeding anyway for your convenience. The parser is still an HTML parser, so namespace processing is not performed and \u201Cxml:*\u201D attributes are not supported. Using the schema for "
--                                + getPresetLabel(XHTML1TRANSITIONAL_SCHEMA)
--                                + "."
--                                + (html4SpecificAdditionalErrorChecks ? " HTML4-specific tokenization errors are enabled."
--                                        : ""));
--                        validator = validatorByDoctype(XHTML1TRANSITIONAL_SCHEMA);
--                    } else if ("-//W3C//DTD XHTML 1.0 Strict//EN".equals(publicIdentifier)) {
--                        errorHandler.info("XHTML 1.0 Strict doctype seen. Appendix C is not supported. Proceeding anyway for your convenience. The parser is still an HTML parser, so namespace processing is not performed and \u201Cxml:*\u201D attributes are not supported. Using the schema for "
--                                + getPresetLabel(XHTML1STRICT_SCHEMA)
--                                + "."
--                                + (html4SpecificAdditionalErrorChecks ? " HTML4-specific tokenization errors are enabled."
--                                        : ""));
--                        validator = validatorByDoctype(XHTML1STRICT_SCHEMA);
--                    } else if ("-//W3C//DTD HTML 4.01 Transitional//EN".equals(publicIdentifier)) {
--                        errorHandler.info("HTML 4.01 Transitional doctype seen. Using the schema for "
--                                + getPresetLabel(XHTML1TRANSITIONAL_SCHEMA)
--                                + "."
--                                + (html4SpecificAdditionalErrorChecks ? ""
--                                        : " HTML4-specific tokenization errors are not enabled."));
--                        validator = validatorByDoctype(XHTML1TRANSITIONAL_SCHEMA);
--                    } else if ("-//W3C//DTD HTML 4.01//EN".equals(publicIdentifier)) {
--                        errorHandler.info("HTML 4.01 Strict doctype seen. Using the schema for "
--                                + getPresetLabel(XHTML1STRICT_SCHEMA)
--                                + "."
--                                + (html4SpecificAdditionalErrorChecks ? ""
--                                        : " HTML4-specific tokenization errors are not enabled."));
--                        validator = validatorByDoctype(XHTML1STRICT_SCHEMA);
--                    } else if ("-//W3C//DTD HTML 4.0 Transitional//EN".equals(publicIdentifier)) {
--                        errorHandler.info("Legacy HTML 4.0 Transitional doctype seen.  Please consider using HTML 4.01 Transitional instead. Proceeding anyway for your convenience with the schema for "
--                                + getPresetLabel(XHTML1TRANSITIONAL_SCHEMA)
--                                + "."
--                                + (html4SpecificAdditionalErrorChecks ? ""
--                                        : " HTML4-specific tokenization errors are not enabled."));
--                        validator = validatorByDoctype(XHTML1TRANSITIONAL_SCHEMA);
--                    } else if ("-//W3C//DTD HTML 4.0//EN".equals(publicIdentifier)) {
--                        errorHandler.info("Legacy HTML 4.0 Strict doctype seen. Please consider using HTML 4.01 instead. Proceeding anyway for your convenience with the schema for "
--                                + getPresetLabel(XHTML1STRICT_SCHEMA)
--                                + "."
--                                + (html4SpecificAdditionalErrorChecks ? ""
--                                        : " HTML4-specific tokenization errors are not enabled."));
--                        validator = validatorByDoctype(XHTML1STRICT_SCHEMA);
--                    }
--                } else {
--                    errorHandler.info("Using the schema for "
--                            + getPresetLabel(HTML5_SCHEMA)
--                            + "."
--                            + (html4SpecificAdditionalErrorChecks ? " HTML4-specific tokenization errors are enabled."
--                                    : ""));
--                    validator = validatorByDoctype(HTML5_SCHEMA);
--                }
--            } catch (IOException ioe) {
--                // At this point the schema comes from memory.
--                throw new RuntimeException(ioe);
--            } catch (IncorrectSchemaException e) {
--                // At this point the schema comes from memory.
--                throw new RuntimeException(e);
--            }
--            ContentHandler ch = validator.getContentHandler();
--            ch.setDocumentLocator(htmlParser.getDocumentLocator());
--            ch.startDocument();
--            reader.setContentHandler(ch);
--        } else {
--            if (html4SpecificAdditionalErrorChecks) {
--                errorHandler.info("HTML4-specific tokenization errors are enabled.");
--            }
--        }
--    }
--
--    private String getPresetLabel(int schemaId) {
--        for (int i = 0; i < presetDoctypes.length; i++) {
--            if (presetDoctypes[i] == schemaId) {
--                return presetLabels[i];
--            }
--        }
--        return "unknown";
--    }
--
--    /**
--     * @param acceptAllKnownXmlTypes
--     * @see nu.validator.xml.ContentTypeParser#setAcceptAllKnownXmlTypes(boolean)
--     */
--    protected void setAcceptAllKnownXmlTypes(boolean acceptAllKnownXmlTypes) {
--        contentTypeParser.setAcceptAllKnownXmlTypes(acceptAllKnownXmlTypes);
--        dataRes.setAcceptAllKnownXmlTypes(acceptAllKnownXmlTypes);
--        httpRes.setAcceptAllKnownXmlTypes(acceptAllKnownXmlTypes);
--    }
--
--    /**
--     * @param allowGenericXml
--     * @see nu.validator.xml.ContentTypeParser#setAllowGenericXml(boolean)
--     */
--    protected void setAllowGenericXml(boolean allowGenericXml) {
--        contentTypeParser.setAllowGenericXml(allowGenericXml);
--        httpRes.setAllowGenericXml(allowGenericXml);
--        dataRes.setAllowGenericXml(allowGenericXml);
--    }
--
--    /**
--     * @param allowHtml
--     * @see nu.validator.xml.ContentTypeParser#setAllowHtml(boolean)
--     */
--    protected void setAllowHtml(boolean allowHtml) {
--        contentTypeParser.setAllowHtml(allowHtml);
--        httpRes.setAllowHtml(allowHtml);
--        dataRes.setAllowHtml(allowHtml);
--    }
--
--    /**
--     * @param allowRnc
--     * @see nu.validator.xml.ContentTypeParser#setAllowRnc(boolean)
--     */
--    protected void setAllowRnc(boolean allowRnc) {
--        contentTypeParser.setAllowRnc(allowRnc);
--        httpRes.setAllowRnc(allowRnc);
--        dataRes.setAllowRnc(allowRnc);
--        entityResolver.setAllowRnc(allowRnc);
--    }
--
--    /**
--     * @param allowXhtml
--     * @see nu.validator.xml.ContentTypeParser#setAllowXhtml(boolean)
--     */
--    protected void setAllowXhtml(boolean allowXhtml) {
--        contentTypeParser.setAllowXhtml(allowXhtml);
--        httpRes.setAllowXhtml(allowXhtml);
--        dataRes.setAllowXhtml(allowXhtml);
--    }
--
--    /**
--     * @throws SAXException
--     * @throws IOException
--     */
--    protected void loadDocumentInput() throws SAXException, IOException {
--        if (methodIsGet) {
--            documentInput = (TypedInputSource) entityResolver.resolveEntity(
--                    null, document);
--            errorHandler.setLoggingOk(true);
--        } else { // POST
--            long len = request.getContentLength();
--            if (len > SIZE_LIMIT) {
--                throw new StreamBoundException("Resource size exceeds limit.");
--            }
--            documentInput = contentTypeParser.buildTypedInputSource(document,
--                    null, postContentType);
--            documentInput.setByteStream(len < 0 ? new BoundedInputStream(
--                    request.getInputStream(), SIZE_LIMIT, document)
--                    : request.getInputStream());
--            documentInput.setSystemId(request.getHeader("Content-Location"));
--        }
--        if (imageCollector != null) {
--            baseUriTracker = new BaseUriTracker(documentInput.getSystemId(),
--                    documentInput.getLanguage());
--            imageCollector.initializeContext(baseUriTracker);
--        }
--    }
--
--    void emitStyle() throws SAXException {
--        attrs.clear();
--        attrs.addAttribute("href", STYLE_SHEET);
--        attrs.addAttribute("rel", "stylesheet");
--        emitter.startElement("link", attrs);
--        emitter.endElement("link");
--    }
--
--    void emitIcon() throws SAXException {
--        attrs.clear();
--        attrs.addAttribute("href", ICON);
--        attrs.addAttribute("rel", "icon");
--        emitter.startElement("link", attrs);
--        emitter.endElement("link");
--    }
--
--    void emitScript() throws SAXException {
--        attrs.clear();
--        attrs.addAttribute("src", SCRIPT);
--        emitter.startElement("script", attrs);
--        emitter.endElement("script");
--    }
--
--    void emitAbout() throws SAXException {
--        attrs.clear();
--        attrs.addAttribute("href", ABOUT_PAGE);
--        emitter.startElement("a", attrs);
--        emitter.characters(ABOUT_THIS_SERVICE);
--        emitter.endElement("a");
--    }
--
--    void emitVersion() throws SAXException {
--        emitter.characters(VERSION);
--    }
--
--    void emitUserAgentInput() throws SAXException {
--        attrs.clear();
--        attrs.addAttribute("name", "useragent");
--        attrs.addAttribute("list", "useragents");
--        attrs.addAttribute("value", userAgent);
--        emitter.startElement("input", attrs);
--        emitter.endElement("input");
--    }
--
--    void emitOtherFacetLink() throws SAXException {
--        attrs.clear();
--        attrs.addAttribute("href", HTML5_FACET);
--        emitter.startElement("a", attrs);
--        emitter.characters(SIMPLE_UI);
--        emitter.endElement("a");
--    }
--
--    void emitNsfilterField() throws SAXException {
--        attrs.clear();
--        attrs.addAttribute("name", "nsfilter");
--        attrs.addAttribute("id", "nsfilter");
--        attrs.addAttribute("pattern", "(?:.+:.+(?:\\s+.+:.+)*)?");
--        attrs.addAttribute("title",
--                "Space-separated namespace URIs for vocabularies to be filtered out.");
--        if (!filteredNamespaces.isEmpty()) {
--            StringBuilder sb = new StringBuilder();
--            boolean first = true;
--            for (String ns : filteredNamespaces) {
--                if (!first) {
--                    sb.append(' ');
--                }
--                sb.append(ns);
--                first = false;
--            }
--            attrs.addAttribute("value", scrub(sb));
--        }
--        emitter.startElement("input", attrs);
--        emitter.endElement("input");
--    }
--
--    void maybeEmitNsfilterField() throws SAXException {
--        NsFilterEmitter.emit(contentHandler, this);
--    }
--
--    void emitCharsetOptions() throws SAXException {
--        boolean found = false;
--        for (int i = 0; i < CHARSETS.length; i++) {
--            String charset = CHARSETS[i];
--            boolean selected = charset.equalsIgnoreCase(charsetOverride); // XXX
--            // use
--            // ASCII-caseinsensitivity
--            emitter.option(CHARSET_DESCRIPTIONS[i], charset, selected);
--            if (selected) {
--                found = true;
--            }
--        }
--        if (!found && charsetOverride != null) {
--            emitter.option(charsetOverride, charsetOverride, true);
--        }
--    }
--
--    void maybeEmitCharsetField() throws SAXException {
--        CharsetEmitter.emit(contentHandler, this);
--    }
--
--}
-diff --git a/src/nu/validator/servlet/VerifierServletXMLReaderCreator.java b/src/nu/validator/servlet/VerifierServletXMLReaderCreator.java
-deleted file mode 100644
-index 9fb99e1..0000000
---- a/src/nu/validator/servlet/VerifierServletXMLReaderCreator.java
-+++ /dev/null
-@@ -1,69 +0,0 @@
--/*
-- * Copyright (c) 2005, 2006 Henri Sivonen
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import nu.validator.gnu.xml.aelfred2.SAXDriver;
--
--import org.xml.sax.EntityResolver;
--import org.xml.sax.ErrorHandler;
--import org.xml.sax.SAXException;
--import org.xml.sax.XMLReader;
--
--import com.thaiopensource.xml.sax.XMLReaderCreator;
--
--
--/**
-- * @version $Id$
-- * @author hsivonen
-- */
--public class VerifierServletXMLReaderCreator implements XMLReaderCreator {
--
--    private ErrorHandler errorHandler;
--
--    private EntityResolver entityResolver;
--
--    /**
--     * @param errorHandler
--     * @param entityResolver
--     */
--    public VerifierServletXMLReaderCreator(ErrorHandler errorHandler,
--            EntityResolver entityResolver) {
--        this.errorHandler = errorHandler;
--        this.entityResolver = entityResolver;
--    }
--
--    /**
--     * @see com.thaiopensource.xml.sax.XMLReaderCreator#createXMLReader()
--     */
--    public XMLReader createXMLReader() throws SAXException {
--        XMLReader r = new SAXDriver();
--        r.setFeature("http://xml.org/sax/features/external-general-entities",
--                true);
--        r.setFeature("http://xml.org/sax/features/external-parameter-entities",
--                true);
--        r.setEntityResolver(this.entityResolver);
--        r.setErrorHandler(this.errorHandler);
--        return r;
--    }
--
--}
-diff --git a/src/nu/validator/servlet/XhtmlOutlineEmitter.java b/src/nu/validator/servlet/XhtmlOutlineEmitter.java
-deleted file mode 100644
-index e34feef..0000000
---- a/src/nu/validator/servlet/XhtmlOutlineEmitter.java
-+++ /dev/null
-@@ -1,101 +0,0 @@
--/*
-- * Copyright (c) 2012 Vadim Zaslawski, Ontos AG
-- * Copyright (c) 2012 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.servlet;
--
--import java.io.IOException;
--import java.util.Deque;
--
--import nu.validator.servlet.OutlineBuildingXMLReaderWrapper.Section;
--import nu.validator.xml.AttributesImpl;
--import nu.validator.xml.XhtmlSaxEmitter;
--
--import org.xml.sax.ContentHandler;
--import org.xml.sax.SAXException;
--
--public class XhtmlOutlineEmitter {
--
--    private static final char[] OUTLINE = "Outline".toCharArray();
--
--    private final Deque<Section> outline;
--
--    private final XhtmlSaxEmitter emitter;
--
--    private final AttributesImpl attrs = new AttributesImpl();
--
--    public XhtmlOutlineEmitter(final ContentHandler contentHandler,
--            final Deque<Section> outline) {
--        this.emitter = new XhtmlSaxEmitter(contentHandler);
--        this.outline = outline;
--    }
--
--    public void emit() throws SAXException {
--        if (outline != null) {
--            attrs.clear();
--            attrs.addAttribute("id", "outline");
--            emitter.startElement("section", attrs);
--            emitter.startElement("h2");
--            emitter.characters(OUTLINE);
--            emitter.endElement("h2");
--            try {
--                emitOutline(outline, 0);
--            } catch (IOException e) {
--                throw new RuntimeException(e);
--            }
--            emitter.endElement("section");
--        }
--    }
--
--    protected void emitOutline(Deque<Section> outline, int currentDepth)
--            throws IOException, SAXException {
--        emitter.startElement("ol");
--        for (Section section : outline) {
--            emitter.startElement("li");
--            StringBuilder headingText = section.getHeadingTextBuilder();
--            if (headingText.length() > 0) {
--                emitter.startElementWithClass("span", "heading");
--                emitter.characters(headingText.toString().toCharArray());
--                emitter.endElement("span");
--            } else if (section.hasEmptyHeading()) {
--                emitter.characters(("[" + section.getElementName() + " element with empty heading]").toCharArray());
--            } else if ("h1".equals(section.getElementName())
--                    || "h2".equals(section.getElementName())
--                    || "h3".equals(section.getElementName())
--                    || "h4".equals(section.getElementName())
--                    || "h5".equals(section.getElementName())
--                    || "h6".equals(section.getElementName())) {
--                emitter.characters(("[section implied by empty "
--                        + section.getElementName() + " element]").toCharArray());
--            } else {
--                emitter.characters(("[" + section.getElementName() + " element with no heading]").toCharArray());
--            }
--            Deque<Section> sections = section.sections;
--            if (!sections.isEmpty()) {
--                emitOutline(sections, currentDepth + 1);
--            }
--            emitter.endElement("li");
--        }
--        emitter.endElement("ol");
--    }
--
--}
-diff --git a/src/nu/validator/xml/BaseUriTracker.java b/src/nu/validator/xml/BaseUriTracker.java
-index 8a4c91b..afea01c 100644
---- a/src/nu/validator/xml/BaseUriTracker.java
-+++ b/src/nu/validator/xml/BaseUriTracker.java
-@@ -32,17 +32,17 @@ import org.xml.sax.ContentHandler;
- import org.xml.sax.Locator;
- import org.xml.sax.SAXException;
- 
--import io.mola.galimatias.URL;
--import io.mola.galimatias.GalimatiasParseException;
-+import com.hp.hpl.jena.iri.IRI;
-+import com.hp.hpl.jena.iri.IRIFactory;
- 
- public class BaseUriTracker implements ContentHandler, UriLangContext {
--
-+    
-     private enum Direction {
-         LTR, RTL, INHERIT
-     }
- 
-     private class Node {
--        public URL currentAbsolute; // not null
-+        public URI currentAbsolute; // not null
- 
-         public String originalRelative; // null if no xml:base
- 
-@@ -56,7 +56,7 @@ public class BaseUriTracker implements ContentHandler, UriLangContext {
-          * @param currentAbsolute
-          * @param originalRelative
-          */
--        public Node(URL currentAbsolute, String originalRelative, String lang,
-+        public Node(URI currentAbsolute, String originalRelative, String lang,
-                 boolean langSpecified, boolean rtl) {
-             this.currentAbsolute = currentAbsolute;
-             this.originalRelative = originalRelative;
-@@ -66,6 +66,8 @@ public class BaseUriTracker implements ContentHandler, UriLangContext {
-         }
-     }
- 
-+    private final IRIFactory iriFactory;
-+    
-     private LinkedList<Node> stack = new LinkedList<Node>();
- 
-     private boolean baseSeen = false;
-@@ -110,13 +112,26 @@ public class BaseUriTracker implements ContentHandler, UriLangContext {
- 
-     public BaseUriTracker(String systemId, String contentLanguage) {
- 
--        URL url = null;
-+        this.iriFactory = new IRIFactory();
-+        this.iriFactory.shouldViolation(false, false);
-+        this.iriFactory.securityViolation(false, false);
-+        this.iriFactory.dnsViolation(false, false);
-+        this.iriFactory.mintingViolation(false, false);
-+        this.iriFactory.useSpecificationIRI(false);
-+        this.iriFactory.useSchemeSpecificRules("http", false);
-+        this.iriFactory.useSchemeSpecificRules("https", false);
-+        this.iriFactory.useSchemeSpecificRules("ftp", false);
-+        this.iriFactory.useSchemeSpecificRules("data", false);
-+
-+        URI uri = null;
-         try {
--            url = URL.parse(systemId);
--        } catch (GalimatiasParseException e) {
--            url = null;
-+            IRI iri = iriFactory.construct(systemId);
-+            uri = new URI(iri.toASCIIString());
-+            if (!uri.isAbsolute()) {
-+                uri = null;
-+            }
-         } catch (Exception e) {
--            url = null;
-+            uri = null;
-         }
- 
-         String lang = "";
-@@ -131,8 +146,8 @@ public class BaseUriTracker implements ContentHandler, UriLangContext {
-             } catch (DatatypeException e) {
-             }
-         }
--        stack.add(new Node(url, null, lang, langSpecified, false));
--        stack.add(new Node(url, null, lang, false, false)); // base/content-language placeholder
-+        stack.add(new Node(uri, null, lang, langSpecified, false));
-+        stack.add(new Node(uri, null, lang, false, false)); // base/content-language placeholder
-     }
- 
-     private Node peek() {
-@@ -158,7 +173,7 @@ public class BaseUriTracker implements ContentHandler, UriLangContext {
-         }
- 
-         Node curr = peek();
--        URL base = curr.currentAbsolute;
-+        URI base = curr.currentAbsolute;
-         if (!langSpecified) {
-             lang = curr.lang;
-         }
-@@ -178,19 +193,19 @@ public class BaseUriTracker implements ContentHandler, UriLangContext {
-         if (relative == null) {
-             stack.addLast(new Node(base, null, lang, langSpecified, rtl));
-         } else {
--            URL newBase;
-+            URI newBase;
-             String ascii = null;
-             try {
-+                IRI relIri = iriFactory.construct(relative);
-+                ascii = relIri.toASCIIString();
-                 if (base != null) {
--                    try {
--                        newBase = base.resolve(relative);
--                    } catch (GalimatiasParseException e) {
-+                    newBase = base.resolve(ascii);
-+                    if (!newBase.isAbsolute()) {
-                         newBase = base;
-                     }
-                 } else {
--                    try {
--                        newBase = URL.parse((new URI(ascii)).toString());
--                    } catch (GalimatiasParseException e) {
-+                    newBase = new URI(ascii);
-+                    if (!newBase.isAbsolute()) {
-                         newBase = null;
-                     }
-                 }
-@@ -283,22 +298,23 @@ public class BaseUriTracker implements ContentHandler, UriLangContext {
-      */
-     public String toAbsoluteUriWithCurrentBase(String uri) {
-         try {
--            URL relUrl = URL.parse(uri);
-+            IRI relIri = iriFactory.construct(uri);
-             String ascii;
--            ascii = relUrl.toString();
-+            ascii = relIri.toASCIIString();
- 
--            URL base = stack.getLast().currentAbsolute;
--            URL rv;
--            try {
--                if (base == null) {
--                    rv = URL.parse(ascii);
--                } else {
--                    rv = base.resolve(ascii);
--                }
--            } catch (GalimatiasParseException e) {
-+            URI base = stack.getLast().currentAbsolute;
-+            URI rv;
-+            if (base == null) {
-+                rv = new URI(ascii);
-+            } else {
-+                rv = base.resolve(ascii);
-+
-+            }
-+            if (rv.isAbsolute()) {
-+                return rv.toASCIIString();
-+            } else {
-                 return null;
-             }
--            return rv.toString();
-         } catch (Exception e) {
-             return null;
-         }
-diff --git a/src/nu/validator/xml/DataUriEntityResolver.java b/src/nu/validator/xml/DataUriEntityResolver.java
-index eaacb82..2eac45a 100644
---- a/src/nu/validator/xml/DataUriEntityResolver.java
-+++ b/src/nu/validator/xml/DataUriEntityResolver.java
-@@ -31,8 +31,11 @@ import org.xml.sax.InputSource;
- import org.xml.sax.SAXException;
- import org.xml.sax.SAXParseException;
- 
--import io.mola.galimatias.URL;
--import io.mola.galimatias.GalimatiasParseException;
-+//import io.mola.galimatias.URL;
-+//import io.mola.galimatias.GalimatiasParseException;
-+import com.hp.hpl.jena.iri.IRI;
-+import com.hp.hpl.jena.iri.IRIException;
-+import com.hp.hpl.jena.iri.IRIFactory;
- 
- public class DataUriEntityResolver implements EntityResolver {
- 
-@@ -51,6 +54,8 @@ public class DataUriEntityResolver implements EntityResolver {
-     private boolean acceptAllKnownXmlTypes = false;
- 
-     private boolean allowGenericXml = true;
-+    
-+    private final IRIFactory iriFactory;
- 
-     private final ContentTypeParser contentTypeParser;
-     
-@@ -61,6 +66,9 @@ public class DataUriEntityResolver implements EntityResolver {
-             ErrorHandler errorHandler) {
-         this.laxContentType = laxContentType;
-         this.errorHandler = errorHandler;
-+        this.iriFactory = new IRIFactory();
-+        this.iriFactory.useSpecificationXMLSystemID(true);
-+        this.iriFactory.useSchemeSpecificRules("data", true);
-         this.contentTypeParser = new ContentTypeParser(errorHandler,
-                 laxContentType, this.allowRnc, this.allowHtml, this.allowXhtml,
-                 this.acceptAllKnownXmlTypes, this.allowGenericXml);
-@@ -74,10 +82,10 @@ public class DataUriEntityResolver implements EntityResolver {
-     public InputSource resolveEntity(String publicId, String systemId)
-             throws SAXException, IOException {
-         if (DataUri.startsWithData(systemId)) {
--            URL url;
-+            IRI iri;
-             try {
--                url = URL.parse(systemId);
--            } catch (GalimatiasParseException e) {
-+                iri = iriFactory.construct(systemId);
-+            } catch (IRIException e) {
-                 IOException ioe = (IOException) new IOException(e.getMessage()).initCause(e);
-                 SAXParseException spe = new SAXParseException(e.getMessage(),
-                         publicId, systemId, -1, -1, ioe);
-@@ -86,7 +94,7 @@ public class DataUriEntityResolver implements EntityResolver {
-                 }
-                 throw spe;
-             }
--            systemId = url.toString();
-+            systemId = iri.toASCIIString();
-             DataUri du = new DataUri(systemId);
-             TypedInputSource is = contentTypeParser.buildTypedInputSource(systemId, publicId,
-                     du.getContentType());
-diff --git a/src/nu/validator/xml/PrudentHttpEntityResolver.java b/src/nu/validator/xml/PrudentHttpEntityResolver.java
-deleted file mode 100644
-index 1a172f1..0000000
---- a/src/nu/validator/xml/PrudentHttpEntityResolver.java
-+++ /dev/null
-@@ -1,548 +0,0 @@
--/*
-- * Copyright (c) 2005 Henri Sivonen
-- * Copyright (c) 2007-2015 Mozilla Foundation
-- *
-- * 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.
-- */
--
--package nu.validator.xml;
--
--import java.io.IOException;
--import java.io.InputStream;
--import java.security.KeyManagementException;
--import java.security.KeyStoreException;
--import java.security.NoSuchAlgorithmException;
--import java.security.cert.CertificateException;
--import java.security.cert.X509Certificate;
--import java.util.zip.GZIPInputStream;
--
--import javax.net.ssl.HostnameVerifier;
--import javax.net.ssl.SSLContext;
--
--import nu.validator.io.BoundedInputStream;
--import nu.validator.io.ObservableInputStream;
--import nu.validator.io.StreamBoundException;
--import nu.validator.io.StreamObserver;
--import nu.validator.io.SystemIdIOException;
--
--import org.apache.http.Header;
--import org.apache.http.HttpEntity;
--import org.apache.http.HttpResponse;
--import org.apache.http.client.HttpClient;
--import org.apache.http.client.config.CookieSpecs;
--import org.apache.http.client.config.RequestConfig;
--import org.apache.http.client.methods.HttpGet;
--import org.apache.http.config.Registry;
--import org.apache.http.config.RegistryBuilder;
--import org.apache.http.conn.socket.ConnectionSocketFactory;
--import org.apache.http.conn.socket.PlainConnectionSocketFactory;
--import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
--import org.apache.http.conn.ssl.SSLContextBuilder;
--import org.apache.http.conn.ssl.TrustStrategy;
--import org.apache.http.impl.client.HttpClientBuilder;
--import org.apache.http.impl.client.HttpClients;
--import org.apache.http.impl.client.LaxRedirectStrategy;
--import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
--import org.apache.log4j.Logger;
--
--import org.xml.sax.EntityResolver;
--import org.xml.sax.ErrorHandler;
--import org.xml.sax.InputSource;
--import org.xml.sax.SAXException;
--import org.xml.sax.SAXParseException;
--
--import io.mola.galimatias.URL;
--import io.mola.galimatias.GalimatiasParseException;
--
--/**
-- * @version $Id: PrudentHttpEntityResolver.java,v 1.1 2005/01/08 08:11:26
-- *          hsivonen Exp $
-- * @author hsivonen
-- */
--@SuppressWarnings("deprecation") public class PrudentHttpEntityResolver
--        implements EntityResolver {
--
--    private static final Logger log4j = Logger.getLogger(PrudentHttpEntityResolver.class);
--
--    private static HttpClient client;
--
--    private static int maxRequests;
--
--    private long sizeLimit;
--
--    private final ErrorHandler errorHandler;
--
--    private int requestsLeft;
--
--    private boolean allowRnc = false;
--
--    private boolean allowHtml = false;
--
--    private boolean allowXhtml = false;
--
--    private boolean acceptAllKnownXmlTypes = false;
--
--    private boolean allowGenericXml = true;
--
--    private final ContentTypeParser contentTypeParser;
--
--    private String userAgent;
--
--    /**
--     * Sets the timeouts of the HTTP client.
--     *
--     * @param connectionTimeout
--     *            timeout until connection established in milliseconds. Zero
--     *            means no timeout.
--     * @param socketTimeout
--     *            timeout for waiting for data in milliseconds. Zero means no
--     *            timeout.
--     * @param maxRequests
--     *            maximum number of connections to a particuar host
--     */
--    public static void setParams(int connectionTimeout, int socketTimeout,
--            int maxRequests) {
--        PrudentHttpEntityResolver.maxRequests = maxRequests;
--        PoolingHttpClientConnectionManager phcConnMgr;
--        Registry<ConnectionSocketFactory> registry = //
--        RegistryBuilder.<ConnectionSocketFactory> create() //
--        .register("http", PlainConnectionSocketFactory.getSocketFactory()) //
--        .register("https", SSLConnectionSocketFactory.getSocketFactory()) //
--        .build();
--        HttpClientBuilder builder = HttpClients.custom();
--        builder.setRedirectStrategy(new LaxRedirectStrategy());
--        builder.setMaxConnPerRoute(maxRequests);
--        builder.setMaxConnTotal(200);
--        if ("true".equals(System.getProperty(
--                "nu.validator.xml.promiscuous-ssl", "false"))) { //
--            try {
--                SSLContext promiscuousSSLContext = new SSLContextBuilder() //
--                .loadTrustMaterial(null, new TrustStrategy() {
--                    public boolean isTrusted(X509Certificate[] arg0, String arg1)
--                            throws CertificateException {
--                        return true;
--                    }
--                }).build();
--                builder.setSslcontext(promiscuousSSLContext);
--                HostnameVerifier verifier = //
--                SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
--                SSLConnectionSocketFactory promiscuousSSLConnSocketFactory = //
--                new SSLConnectionSocketFactory(promiscuousSSLContext, verifier);
--                registry = RegistryBuilder.<ConnectionSocketFactory> create() //
--                .register("https", promiscuousSSLConnSocketFactory) //
--                .register("http",
--                        PlainConnectionSocketFactory.getSocketFactory()) //
--                .build();
--            } catch (KeyManagementException e) {
--                e.printStackTrace();
--            } catch (NumberFormatException e) {
--                e.printStackTrace();
--            } catch (NoSuchAlgorithmException e) {
--                e.printStackTrace();
--            } catch (KeyStoreException e) {
--                e.printStackTrace();
--            }
--        }
--        phcConnMgr = new PoolingHttpClientConnectionManager(registry);
--        phcConnMgr.setDefaultMaxPerRoute(maxRequests);
--        phcConnMgr.setMaxTotal(200);
--        builder.setConnectionManager(phcConnMgr);
--        RequestConfig.Builder config = RequestConfig.custom();
--        config.setCircularRedirectsAllowed(true);
--        config.setMaxRedirects(20); // Gecko default
--        config.setConnectTimeout(connectionTimeout);
--        config.setCookieSpec(CookieSpecs.BEST_MATCH);
--        config.setSocketTimeout(socketTimeout);
--        client = builder.setDefaultRequestConfig(config.build()).build();
--    }
--
--    public void setUserAgent(String ua) {
--        userAgent = ua;
--    }
--
--    /**
--     * @param sizeLimit
--     * @param laxContentType
--     * @param errorHandler
--     */
--    public PrudentHttpEntityResolver(long sizeLimit, boolean laxContentType,
--            ErrorHandler errorHandler) {
--        this.sizeLimit = sizeLimit;
--        this.requestsLeft = maxRequests;
--        this.errorHandler = errorHandler;
--        this.contentTypeParser = new ContentTypeParser(errorHandler,
--                laxContentType, this.allowRnc, this.allowHtml, this.allowXhtml,
--                this.acceptAllKnownXmlTypes, this.allowGenericXml);
--    }
--
--    /**
--     * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String,
--     *      java.lang.String)
--     */
--    public InputSource resolveEntity(String publicId, String systemId)
--            throws SAXException, IOException {
--        if (requestsLeft > -1) {
--            if (requestsLeft == 0) {
--                throw new IOException(
--                        "Number of permitted HTTP requests exceeded.");
--            } else {
--                requestsLeft--;
--            }
--        }
--        HttpGet m = null;
--        try {
--            URL url;
--            try {
--                url = URL.parse(systemId);
--            } catch (GalimatiasParseException e) {
--                IOException ioe = (IOException) new IOException(e.getMessage()).initCause(e);
--                SAXParseException spe = new SAXParseException(e.getMessage(),
--                        publicId, systemId, -1, -1, ioe);
--                if (errorHandler != null) {
--                    errorHandler.fatalError(spe);
--                }
--                throw spe;
--            }
--            String scheme = url.scheme();
--            if (!("http".equals(scheme) || "https".equals(scheme))) {
--                String msg = "Unsupported URI scheme: \u201C" + scheme
--                        + "\u201D.";
--                SAXParseException spe = new SAXParseException(msg, publicId,
--                        systemId, -1, -1, new IOException(msg));
--                if (errorHandler != null) {
--                    errorHandler.fatalError(spe);
--                }
--                throw spe;
--            }
--            systemId = url.toString();
--            try {
--                m = new HttpGet(systemId);
--            } catch (IllegalArgumentException e) {
--                SAXParseException spe = new SAXParseException(
--                        e.getMessage(),
--                        publicId,
--                        systemId,
--                        -1,
--                        -1,
--                        (IOException) new IOException(e.getMessage()).initCause(e));
--                if (errorHandler != null) {
--                    errorHandler.fatalError(spe);
--                }
--                throw spe;
--            }
--            m.setHeader("User-Agent", userAgent);
--            m.setHeader("Accept", buildAccept());
--            m.setHeader("Accept-Encoding", "gzip");
--            log4j.info(systemId);
--            HttpResponse response = client.execute(m);
--            int statusCode = response.getStatusLine().getStatusCode();
--            if (statusCode != 200) {
--                String msg = "HTTP resource not retrievable. The HTTP status from the remote server was: "
--                        + statusCode + ".";
--                SAXParseException spe = new SAXParseException(msg, publicId,
--                        m.getURI().toString(), -1, -1, new IOException(msg));
--                if (errorHandler != null) {
--                    errorHandler.fatalError(spe);
--                }
--                throw spe;
--            }
--            HttpEntity entity = response.getEntity();
--            long len = entity.getContentLength();
--            if (sizeLimit > -1 && len > sizeLimit) {
--                SAXParseException spe = new SAXParseException(
--                        "Resource size exceeds limit.",
--                        publicId,
--                        m.getURI().toString(),
--                        -1,
--                        -1,
--                        new StreamBoundException("Resource size exceeds limit."));
--                if (errorHandler != null) {
--                    errorHandler.fatalError(spe);
--                }
--                throw spe;
--            }
--            TypedInputSource is;
--            org.apache.http.Header ct = response.getFirstHeader("Content-Type");
--            String contentType = null;
--            final String baseUri = m.getURI().toString();
--            if (ct != null) {
--                contentType = ct.getValue();
--            }
--            is = contentTypeParser.buildTypedInputSource(baseUri, publicId,
--                    contentType);
--
--            Header cl = response.getFirstHeader("Content-Language");
--            if (cl != null) {
--                is.setLanguage(cl.getValue().trim());
--            }
--
--            Header xuac = response.getFirstHeader("X-UA-Compatible");
--            if (xuac != null) {
--                String val = xuac.getValue().trim();
--                if (!"ie=edge".equalsIgnoreCase(val)) {
--                    SAXParseException spe = new SAXParseException(
--                            "X-UA-Compatible HTTP header must have the value \u201CIE=edge\u201D,"
--                                    + " was \u201C" + val + "\u201D.",
--                            publicId, systemId, -1, -1);
--                    errorHandler.error(spe);
--                }
--            }
--
--            final HttpGet meth = m;
--            InputStream stream = entity.getContent();
--            if (sizeLimit > -1) {
--                stream = new BoundedInputStream(stream, sizeLimit, baseUri);
--            }
--            Header ce = response.getFirstHeader("Content-Encoding");
--            if (ce != null) {
--                String val = ce.getValue().trim();
--                if ("gzip".equalsIgnoreCase(val)
--                        || "x-gzip".equalsIgnoreCase(val)) {
--                    stream = new GZIPInputStream(stream);
--                    if (sizeLimit > -1) {
--                        stream = new BoundedInputStream(stream, sizeLimit,
--                                baseUri);
--                    }
--                }
--            }
--            is.setByteStream(new ObservableInputStream(stream,
--                    new StreamObserver() {
--                        private final Logger log4j = Logger.getLogger("nu.validator.xml.PrudentEntityResolver.StreamObserver");
--
--                        private boolean released = false;
--
--                        public void closeCalled() {
--                            log4j.debug("closeCalled");
--                            if (!released) {
--                                log4j.debug("closeCalled, not yet released");
--                                released = true;
--                                try {
--                                    meth.releaseConnection();
--                                } catch (Exception e) {
--                                    log4j.debug(
--                                            "closeCalled, releaseConnection", e);
--                                }
--                            }
--                        }
--
--                        public void exceptionOccurred(Exception ex)
--                                throws IOException {
--                            if (!released) {
--                                released = true;
--                                try {
--                                    meth.abort();
--                                } catch (Exception e) {
--                                    log4j.debug("exceptionOccurred, abort", e);
--                                } finally {
--                                    try {
--                                        meth.releaseConnection();
--                                    } catch (Exception e) {
--                                        log4j.debug(
--                                                "exceptionOccurred, releaseConnection",
--                                                e);
--                                    }
--                                }
--                            }
--                            if (ex instanceof SystemIdIOException) {
--                                SystemIdIOException siie = (SystemIdIOException) ex;
--                                throw siie;
--                            } else if (ex instanceof IOException) {
--                                IOException ioe = (IOException) ex;
--                                throw new SystemIdIOException(baseUri,
--                                        ioe.getMessage(), ioe);
--                            } else if (ex instanceof RuntimeException) {
--                                RuntimeException re = (RuntimeException) ex;
--                                throw re;
--                            } else {
--                                throw new RuntimeException(
--                                        "API contract violation. Wrong exception type.",
--                                        ex);
--                            }
--                        }
--
--                        public void finalizerCalled() {
--                            if (!released) {
--                                released = true;
--                                try {
--                                    meth.abort();
--                                } catch (Exception e) {
--                                    log4j.debug("finalizerCalled, abort", e);
--                                } finally {
--                                    try {
--                                        meth.releaseConnection();
--                                    } catch (Exception e) {
--                                        log4j.debug(
--                                                "finalizerCalled, releaseConnection",
--                                                e);
--                                    }
--                                }
--                            }
--                        }
--
--                    }));
--            return is;
--        } catch (IOException e) {
--            if (m != null) {
--                try {
--                    m.abort();
--                } catch (Exception ex) {
--                    log4j.debug("abort", ex);
--                } finally {
--                    try {
--                        m.releaseConnection();
--                    } catch (Exception ex) {
--                        log4j.debug("releaseConnection", ex);
--                    }
--                }
--            }
--            throw e;
--        } catch (SAXException e) {
--            if (m != null) {
--                try {
--                    m.abort();
--                } catch (Exception ex) {
--                    log4j.debug("abort", ex);
--                } finally {
--                    try {
--                        m.releaseConnection();
--                    } catch (Exception ex) {
--                        log4j.debug("releaseConnection", ex);
--                    }
--                }
--            }
--            throw e;
--        } catch (RuntimeException e) {
--            if (m != null) {
--                try {
--                    m.abort();
--                } catch (Exception ex) {
--                    log4j.debug("abort", ex);
--                } finally {
--                    try {
--                        m.releaseConnection();
--                    } catch (Exception ex) {
--                        log4j.debug("releaseConnection", ex);
--                    }
--                }
--            }
--            throw e;
--        }
--    }
--
--    /**
--     * @return Returns the allowRnc.
--     */
--    public boolean isAllowRnc() {
--        return allowRnc;
--    }
--
--    /**
--     * @param allowRnc
--     *            The allowRnc to set.
--     */
--    public void setAllowRnc(boolean allowRnc) {
--        this.allowRnc = allowRnc;
--        this.contentTypeParser.setAllowRnc(allowRnc);
--    }
--
--    /**
--     * @param allowHtml
--     */
--    public void setAllowHtml(boolean allowHtml) {
--        this.allowHtml = allowHtml;
--        this.contentTypeParser.setAllowHtml(allowHtml);
--    }
--
--    /**
--     * Returns the acceptAllKnownXmlTypes.
--     *
--     * @return the acceptAllKnownXmlTypes
--     */
--    public boolean isAcceptAllKnownXmlTypes() {
--        return acceptAllKnownXmlTypes;
--    }
--
--    /**
--     * Sets the acceptAllKnownXmlTypes.
--     *
--     * @param acceptAllKnownXmlTypes
--     *            the acceptAllKnownXmlTypes to set
--     */
--    public void setAcceptAllKnownXmlTypes(boolean acceptAllKnownXmlTypes) {
--        this.acceptAllKnownXmlTypes = acceptAllKnownXmlTypes;
--        this.contentTypeParser.setAcceptAllKnownXmlTypes(acceptAllKnownXmlTypes);
--    }
--
--    /**
--     * Returns the allowGenericXml.
--     *
--     * @return the allowGenericXml
--     */
--    public boolean isAllowGenericXml() {
--        return allowGenericXml;
--    }
--
--    /**
--     * Sets the allowGenericXml.
--     *
--     * @param allowGenericXml
--     *            the allowGenericXml to set
--     */
--    public void setAllowGenericXml(boolean allowGenericXml) {
--        this.allowGenericXml = allowGenericXml;
--        this.contentTypeParser.setAllowGenericXml(allowGenericXml);
--    }
--
--    /**
--     * Returns the allowXhtml.
--     *
--     * @return the allowXhtml
--     */
--    public boolean isAllowXhtml() {
--        return allowXhtml;
--    }
--
--    /**
--     * Sets the allowXhtml.
--     *
--     * @param allowXhtml
--     *            the allowXhtml to set
--     */
--    public void setAllowXhtml(boolean allowXhtml) {
--        this.allowXhtml = allowXhtml;
--        this.contentTypeParser.setAllowXhtml(allowXhtml);
--    }
--
--    private String buildAccept() {
--        return "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
--    }
--
--    /**
--     * Returns the allowHtml.
--     *
--     * @return the allowHtml
--     */
--    public boolean isAllowHtml() {
--        return allowHtml;
--    }
--
--    public boolean isOnlyHtmlAllowed() {
--        return !isAllowGenericXml() && !isAllowRnc() && !isAllowXhtml();
--    }
--}
diff --git a/ide/html.validation/nbproject/project.properties b/ide/html.validation/nbproject/project.properties
index 1ffa48b..1297c3b 100644
--- a/ide/html.validation/nbproject/project.properties
+++ b/ide/html.validation/nbproject/project.properties
@@ -15,18 +15,23 @@
 # specific language governing permissions and limitations
 # under the License.
 
-file.reference.iri-0.5.jar=external/iri.jar
-file.reference.jing-0unknown.jar=external/jing.jar
+file.reference.iri-0.8.jar=external/iri-0.8.jar
+file.reference.jing-0unknown.jar=external/jing-0unknown.jar
 file.reference.log4j-1.2.15.jar=external/log4j-1.2.15.jar
-file.reference.validator-20200626-patched.jar=external/validator.jar
-file.reference.saxon9B-9.1.0.2.jar=external/saxon9B.jar
-file.reference.isorelax-20041111.jar=external/isorelax.jar
-release.external/iri-0.5.jar=modules/ext/iri.jar
+file.reference.validator-20200626-patched.jar=external/validator-20200626-patched.jar
+file.reference.isorelax-20041111.jar=external/isorelax-20041111.jar
+file.reference.salvation-2.7.2.jar=external/salvation-2.7.2.jar
+file.reference.galimatias-0.1.3.jar=external/galimatias-0.1.3.jar
+file.reference.langdetect-1.2.jar=external/langdetect-1.2.jar
+
+release.external/iri-0.8.jar=modules/ext/iri.jar
 release.external/jing-0unknown.jar=modules/ext/jing.jar
 release.external/log4j-1.2.15.jar=modules/ext/log4j-1.2.15.jar
 release.external/validator-20200626-patched.jar=modules/ext/validator.jar
-release.external/saxon9B-9.1.0.2.jar=modules/ext/saxon9B.jar
 release.external/isorelax-20041111.jar=modules/ext/isorelax.jar
+release.external/salvation-2.7.2.jar=modules/ext/salvation.jar
+release.external/galimatias-0.1.3.jar=modules/ext/galimatias.jar
+release.external/langdetect-1.2.jar=modules/ext/langdetect.jar
 
 javac.source=1.8
 javac.compilerargs=-Xlint -Xlint:-serial
diff --git a/ide/html.validation/nbproject/project.xml b/ide/html.validation/nbproject/project.xml
index 8cd5c92..64c8040 100644
--- a/ide/html.validation/nbproject/project.xml
+++ b/ide/html.validation/nbproject/project.xml
@@ -160,16 +160,12 @@
                 <binary-origin>external/jing-0unknown.jar</binary-origin>
             </class-path-extension>
             <class-path-extension>
-                <runtime-relative-path>ext/saxon9B.jar</runtime-relative-path>
-                <binary-origin>external/saxon9B-9.1.0.2.jar</binary-origin>
-            </class-path-extension>
-            <class-path-extension>
                 <runtime-relative-path>ext/log4j-1.2.15.jar</runtime-relative-path>
                 <binary-origin>external/log4j-1.2.15.jar</binary-origin>
             </class-path-extension>
             <class-path-extension>
                 <runtime-relative-path>ext/iri.jar</runtime-relative-path>
-                <binary-origin>external/iri-0.5.jar</binary-origin>
+                <binary-origin>external/iri-0.8.jar</binary-origin>
             </class-path-extension>
             <class-path-extension>
                 <runtime-relative-path>ext/validator.jar</runtime-relative-path>
@@ -179,6 +175,18 @@
                 <runtime-relative-path>ext/isorelax.jar</runtime-relative-path>
                 <binary-origin>external/isorelax-20041111.jar</binary-origin>
             </class-path-extension>
+            <class-path-extension>
+                <runtime-relative-path>ext/salvation.jar</runtime-relative-path>
+                <binary-origin>external/salvation-2.7.2.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                <runtime-relative-path>ext/galimatias.jar</runtime-relative-path>
+                <binary-origin>external/galimatias-0.1.3.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                <runtime-relative-path>ext/langdetect.jar</runtime-relative-path>
+                <binary-origin>external/langdetect-1.2.jar</binary-origin>
+            </class-path-extension>
         </data>
     </configuration>
 </project>
diff --git a/ide/html.validation/test/unit/data/testfiles/testEmbeddedCSS.xhtml b/ide/html.validation/test/unit/data/testfiles/testEmbeddedCSS.xhtml
new file mode 100644
index 0000000..4b91274
--- /dev/null
+++ b/ide/html.validation/test/unit/data/testfiles/testEmbeddedCSS.xhtml
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<html>
+    <head>
+        <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
+        <title>TODO supply a title</title>
+        <style>
+            h1 {
+                font-family: sans-serif;
+            }
+        </style>
+    </head>
+    <body>
+        <p>
+            TODO write content
+        </p>
+    </body>
+</html>
diff --git a/ide/html.validation/test/unit/src/org/netbeans/modules/html/validation/ValidationTransactionTest.java b/ide/html.validation/test/unit/src/org/netbeans/modules/html/validation/ValidationTransactionTest.java
index 830f8f5..9857464 100644
--- a/ide/html.validation/test/unit/src/org/netbeans/modules/html/validation/ValidationTransactionTest.java
+++ b/ide/html.validation/test/unit/src/org/netbeans/modules/html/validation/ValidationTransactionTest.java
@@ -184,6 +184,22 @@
         assertNull(vt.htmlParser);
     }
 
+    // Ensure files with embedded CSS pass
+    public void testEmbeddedCSS() throws SAXException {
+        FileObject fo = getTestFile("testfiles/testEmbeddedCSS.xhtml");
+        Source source = Source.create(fo);
+        String code = source.createSnapshot().getText().toString();
+        SyntaxAnalyzerResult result = SyntaxAnalyzer.create(new HtmlSource(fo)).analyze();
+        assertNotNull(result);
+
+        assertSame(HtmlVersion.HTML5, result.getDetectedHtmlVersion());
+        HtmlVersion version = result.getHtmlVersion();
+        assertSame(HtmlVersion.HTML5, version);
+
+        NbValidationTransaction vt = NbValidationTransaction.create(result.getHtmlVersion());
+        validate(code, true, result.getHtmlVersion(), vt);
+    }
+
     public void testNamespacesFiltering() throws SAXException {
         FileObject fo = getTestFile("testfiles/wicket.xhtml");
         Source source = Source.create(fo);
diff --git a/nbbuild/licenses/MIT-galimatias b/nbbuild/licenses/MIT-galimatias
new file mode 100644
index 0000000..fb38238
--- /dev/null
+++ b/nbbuild/licenses/MIT-galimatias
@@ -0,0 +1,19 @@
+Copyright (c) 2013-2014 Santiago M. Mola <santi@mola.io>
+
+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.
\ No newline at end of file
diff --git a/platform/openide.filesystems.compat8/src/org/openide/filesystems/FileSystemCompat.java b/platform/openide.filesystems.compat8/src/org/openide/filesystems/FileSystemCompat.java
index 0455f9c..460ea8c 100644
--- a/platform/openide.filesystems.compat8/src/org/openide/filesystems/FileSystemCompat.java
+++ b/platform/openide.filesystems.compat8/src/org/openide/filesystems/FileSystemCompat.java
@@ -43,6 +43,9 @@
  */
 @PatchFor(FileSystem.class)
 public abstract class FileSystemCompat {
+    /** system actions for this FS */
+    private static final SystemAction[] NO_SYSTEM_ACTIONS = new SystemAction[0];
+
     /** Property name giving capabilities state. @deprecated No more capabilities. */
     static final String PROP_CAPABILITIES = "capabilities"; // NOI18N    
 
@@ -67,7 +70,14 @@
     *
     * @return array of available actions
     */
-    public abstract SystemAction[] getActions();
+    @SuppressWarnings("ReturnOfCollectionOrArrayField")
+    public SystemAction[] getActions() {
+        // If implementations don't override getActions, an empty array is
+        // returned to satisfy the FileSystem#getActions contract. As the
+        // empty array is immutable, it is save to return a singleton in this
+        // case
+        return NO_SYSTEM_ACTIONS;
+    }
 
     /**
      * Get actions appropriate to a certain file selection.