Initial import of Doclava project

Change-Id: Ia5ae56f1700fce98e0ae6954fa2df617ec0537bb
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..3de947a
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+# Jar file for Doclava doclet and apicheck standalone program
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := \
+	jsilver \
+	guavalib
+	
+LOCAL_CLASSPATH := \
+	$(HOST_JDK_TOOLS_JAR)
+
+LOCAL_MODULE := doclava
+LOCAL_JAR_MANIFEST := src/MANIFEST.mf
+LOCAL_JAVA_RESOURCE_DIRS := res
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..1e28566
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,28 @@
+
+jQuery 1.2.6 - New Wave Javascript
+
+Copyright (c) 2008 John Resig (jquery.com)
+Dual licensed under the MIT (MIT-LICENSE.txt)
+and GPL (GPL-LICENSE.txt) licenses.
+
+Copyright (c) 2009 John Resig, http://jquery.com/
+
+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/build.xml b/build.xml
new file mode 100644
index 0000000..7d1aa27
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,106 @@
+<project name="doclava" default="jar">
+	<property name="jar.dir" value="build/dist/doclava"/>
+	<property name="jar.file" value="${jar.dir}/doclava.jar"/>
+
+	<property environment="env"/>
+	<property name="javahome" value="${env.JAVA_HOME}" />
+	<property name="jsilver" value="lib/jsilver.jar"/>
+	<property name="junit" value="lib/junit-4.8.2.jar"/>
+	
+	<path id="classpath.test">
+		<pathelement location="${junit}" />
+    <pathelement location="${jar.file}" />
+		<pathelement location="build/test" />
+	</path>
+	
+	<target name="compile" description="Compile Java source.">
+		<mkdir dir="build/classes"/>
+
+		<javac srcdir="src"
+         debug="on"
+         destdir="build/classes"
+         source="1.5"
+         target="1.5"
+         extdirs="">
+			<compilerarg value="-Xlint:all"/>
+			<classpath>
+				<pathelement location="${jsilver}"/>
+			</classpath>
+		</javac>
+	</target>
+
+	<target name="jar" depends="compile" description="Build jar.">
+		<mkdir dir="${jar.dir}"/>
+
+		<copy todir="build/classes/assets">
+			<fileset dir="assets"/>
+		</copy>
+
+		<jar jarfile="${jar.file}" manifest="src/MANIFEST.mf">
+			<fileset dir="build/classes"/>
+			<zipfileset src="${jsilver}" />
+		</jar>
+	</target>
+
+	<target name="clean"
+      description="Remove generated files.">
+		<delete dir="build"/>
+	</target>
+
+	<target name="clean-jar" 
+		description="cleans and builds a .jar"
+		depends="clean,jar">
+	</target>
+
+	<target name="compile-test">
+	  <mkdir dir="build/test" />
+		
+		<exec executable="/bin/sh">
+		  <arg value="-c"/>
+		  <arg value="find test/doclava/sample -name '*.java' &gt; build/test/src-list"/>
+		</exec>
+		
+	  <javac srcdir="test" destdir="build/test">
+	  	<classpath refid="classpath.test" />
+	  </javac>
+	</target>
+	
+	<target name="test" depends="jar,compile-test">
+	    <junit>
+	    	<classpath refid="classpath.test" />
+	      <formatter type="brief" usefile="false" />
+
+        <batchtest>
+          <fileset dir="build/test">
+          	<include name="**/*Test.class"/>
+         </fileset>
+        </batchtest>
+	    </junit>
+	 </target>
+
+	<target name="doclava" description="Generate documentation">
+		<taskdef name="doclava" classname="com.google.doclava.DoclavaTask" classpath="${jar.file}"/>
+		
+		 <mkdir dir="build"/>
+		 <exec executable="/bin/sh">
+		   <arg value="-c"/>
+		   <arg value="find ./src -name '*.java' &gt; build/src-list"/>
+		 </exec>
+			
+			
+		<doclava>
+			<arguments>
+	        	-quiet
+	        	-bootclasspath "${javahome}/jre/lib/rt.jar"
+	        	-doclet com.google.doclava.Doclava
+	        	-docletpath ${jar.file}
+	        	-classpath ${jar.file}
+	        	-d build/api
+	 	       	-hdf project.name "Junction"
+	        	-stubs build/stubs
+	        	-apixml build/public_api.xml
+	        	@build/src-list
+	      	</arguments>
+		</doclava>
+	</target>
+</project>
diff --git a/res/assets/customizations/assets/customizations.css b/res/assets/customizations/assets/customizations.css
new file mode 100644
index 0000000..4468a2a
--- /dev/null
+++ b/res/assets/customizations/assets/customizations.css
@@ -0,0 +1,7 @@
+#header {
+  border-bottom: 3px solid #b6223c;
+}
+
+#search_filtered .jd-selected {
+  background-color:#b6223c;
+}
\ No newline at end of file
diff --git a/res/assets/customizations/assets/customizations.js b/res/assets/customizations/assets/customizations.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/res/assets/customizations/assets/customizations.js
diff --git a/res/assets/customizations/customizations.cs b/res/assets/customizations/customizations.cs
new file mode 100644
index 0000000..2ab204c
--- /dev/null
+++ b/res/assets/customizations/customizations.cs
@@ -0,0 +1 @@
+<?cs # placeholder for custom clearsilver code. ?>
\ No newline at end of file
diff --git a/res/assets/templates/assets/android-developer-core.css b/res/assets/templates/assets/android-developer-core.css
new file mode 100644
index 0000000..df11921
--- /dev/null
+++ b/res/assets/templates/assets/android-developer-core.css
@@ -0,0 +1,1195 @@
+/* file: android-developer-core.css
+   author: smain
+   date: september 2008
+   info: core developer styles (developer.android.com)
+*/
+
+
+/* RESET STYLES */
+
+html,body,div,h1,h2,h3,h4,h5,h6,p,img,
+dl,dt,dd,ol,ul,li,table,caption,tbody,
+tfoot,thead,tr,th,td,form,fieldset,
+embed,object,applet {
+  margin: 0;
+  padding: 0;
+  border: 0;
+}
+
+/* BASICS */
+
+html, body {
+  overflow:hidden; /* keeps scrollbar off IE */
+  background-color:#fff;
+}
+
+body {
+  font-family:arial,sans-serif;
+  color:#000;
+  font-size:13px;
+  color:#333;
+  background-image:url(images/bg_fade.jpg);
+  background-repeat:repeat-x;
+}
+
+a, a code {
+  color:#006699;
+}
+
+a:active,
+a:active code {
+  color:#f00;
+} 
+
+a:visited,
+a:visited code {
+  color:#006699;
+}
+
+input, select,
+textarea, option, label {
+  font-family:inherit;
+  font-size:inherit;
+  padding:0;
+  margin:0;
+  vertical-align:middle;
+}
+
+option {
+  padding:0 4px;
+}
+
+p {
+  padding:0;
+  margin:0 0 1em;
+}
+
+code, pre {
+  color:#007000;
+  font-family:monospace;
+  line-height:1em;
+}
+
+var {
+  color:#007000;
+  font-style:italic;
+}
+
+pre {
+  border:1px solid #ccc;
+  background-color:#fafafa;
+  padding:10px;
+  margin:0 0 1em 1em;
+  overflow:auto;
+  line-height:inherit; /* fixes vertical scrolling in webkit */
+}
+
+h1,h2,h3,h4,h5 {
+  margin:1em 0;
+  padding:0;
+}
+
+p,ul,ol,dl,dd,dt,li {
+  line-height:1.3em;
+}
+
+ul,ol {
+  margin:0 0 .8em;
+  padding:0 0 0 2em;
+}
+
+li {
+  padding:0 0 .5em;
+}
+
+dl {
+  margin:0 0 1em 0;
+  padding:0;
+}
+
+dt {
+  margin:0;
+  padding:0;
+}
+
+dd {
+  margin:0 0 1em;
+  padding:0 0 0 2em;
+}
+
+li p {
+  margin:.5em 0 0;
+}
+
+dd p {
+  margin:1em 0 0;
+}
+
+li pre, li table, li img {
+  margin:.5em 0 0 1em;
+}
+
+dd pre,
+#jd-content dd table,
+#jd-content dd img {
+  margin:1em 0 0 1em;
+}
+
+li ul,
+li ol,
+dd ul,
+dd ol {
+  margin:0;
+  padding: 0 0 0 2em;
+}
+
+li li,
+dd li {
+  margin:0;
+  padding:.5em 0 0;
+}
+
+dl dl,
+ol dl,
+ul dl {
+  margin:0 0 1em;
+  padding:0;
+}
+
+table {
+  font-size:1em;
+  margin:0 0 1em;
+  padding:0;
+  border-collapse:collapse;
+  border-width:0;
+  empty-cells:show;
+}
+
+td,th {
+  border:1px solid #ccc;
+  padding:6px 12px;
+  text-align:left;
+  vertical-align:top;
+  background-color:inherit;
+}
+
+th {
+  background-color:#dee8f1;
+}
+
+td > p:last-child {
+  margin:0;
+}
+
+hr.blue {
+  background-color:#DDF0F2;
+  border:none;
+  height:5px;
+  margin:20px 0 10px;
+}
+
+blockquote {
+  margin: 0 0 1em 1em;
+  padding: 0 4em 0 1em;
+  border-left:2px solid #eee;
+}
+/* LAYOUT */
+
+#body-content {
+  /* "Preliminary" watermark for preview releases and interim builds.
+  background:transparent url(images/preliminary.png) repeat scroll 0 0;  */
+  margin:0;
+  position:relative;
+  width:100%;
+}
+
+#header {
+  height: 34px;
+  position:relative;
+  z-index:100;
+  min-width:675px; /* min width for the tabs, before they wrap */
+  padding:0 10px;
+  border-bottom:3px solid #94b922;
+}
+
+#headerLeft{
+  padding: 10px 0 0;
+}
+/*
+#headerLeft img{
+  height:50px;
+  width:180px;
+}
+*/
+#headerRight {
+  position:absolute;
+  right:0;
+  top:0;
+  text-align:right;
+}
+
+/* Tabs in the header */
+
+#header ul {
+  list-style: none;
+  margin: 7px 0 0;
+  padding: 0;
+  height: 29px;
+}
+
+#header li {
+  float: left;
+  margin: 0px 2px 0px 0px;
+  padding:0;
+}
+
+#header li a {
+  text-decoration: none;
+  display: block;
+  background-image: url(images/bg_images_sprite.png);
+  background-position: 0 -58px;
+  background-repeat: no-repeat;
+  color: #666;
+  font-size: 13px;
+  font-weight: bold;
+  width: 94px;
+  height: 29px;
+  text-align: center;
+  margin: 0px;
+}
+
+#header li a:hover {
+  background-image: url(images/bg_images_sprite.png);
+  background-position: 0 -29px;
+  background-repeat: no-repeat;
+}
+
+#header li a span {
+  position:relative;
+  top:7px;
+}
+
+#header li a span+span {
+  display:none;
+}
+
+/* tab highlighting */
+
+.home #home-link a,
+.guide #guide-link a,
+.reference #reference-link a,
+.sdk #sdk-link a,
+.resources #resources-link a,
+.videos #videos-link a {
+  background-image: url(images/bg_images_sprite.png);
+  background-position: 0 0;
+  background-repeat: no-repeat;
+  color: #fff;
+  font-weight: bold;
+  cursor:default;
+}
+
+.home #home-link a:hover,
+.guide #guide-link a:hover,
+.reference #reference-link a:hover,
+.sdk #sdk-link a:hover,
+.resources #resources-link a:hover,
+.videos #videos-link  a:hover {
+  background-image: url(images/bg_images_sprite.png);
+  background-position: 0 0;
+}
+
+#headerLinks {
+  margin:10px 10px 0 0;
+  height:13px;
+  font-size: 11px;
+  vertical-align: top;
+}
+
+#headerLinks a {
+  color: #7FA9B5;
+}
+
+#headerLinks img {
+  vertical-align:middle;
+}
+
+#language {
+  margin:0 10px 0 4px;
+}
+
+#search {
+  height:45px;
+  margin:8px 10px 0 0;
+}
+
+/* MAIN BODY */
+
+#mainBodyFluid {
+  margin: 20px 10px;
+  color:#333;
+}
+
+#mainBodyFixed {
+  margin: 20px 10px;
+  color: #333;
+  width:930px;
+  position:relative;
+}
+
+#mainBodyFixed h3,
+#mainBodyFluid h3 {
+  color:#336666;
+  font-size:1.25em;
+  margin: 0em 0em 0em 0em;
+  padding-bottom:.5em;
+}
+
+#mainBodyFixed h2,
+#mainBodyFluid h2 {
+  color:#336666;
+  font-size:1.25em;
+  margin: 0;
+  padding-bottom:.5em;
+}
+
+#mainBodyFixed h1,
+#mainBodyFluid h1 {
+  color:#435A6E;
+  font-size:1.7em;
+  margin: 1em 0;
+}
+
+#mainBodyFixed .green,
+#mainBodyFluid .green,
+#jd-content .green {
+  color:#7BB026;
+  background-color:none;
+}
+
+#mainBodyLeft {
+  float: left;
+  width: 600px;
+  margin-right: 20px;
+  color: #333;
+  position:relative;
+}
+
+div.indent {
+  margin-left: 40px;
+  margin-right: 70px;
+}
+
+#mainBodyLeft p {
+  color: #333;
+  font-size: 13px;
+}
+
+#mainBodyLeft p.blue {
+  color: #669999;
+}
+
+#mainBodyLeft #communityDiv {
+  float: left;
+  background-image:url(images/bg_community_leftDiv.jpg);
+  background-repeat: no-repeat;
+  width: 581px;
+  height: 347px;
+  padding: 20px 0px 0px 20px;
+}
+
+#mainBodyRight {
+  float: left;
+  width: 300px;
+  color: #333;
+}
+
+#mainBodyRight p {
+  padding-right: 50px;
+  color: #333;
+}
+
+#mainBodyRight table {
+  width: 100%;
+}
+
+#mainBodyRight td {
+  border:0px solid #666;
+  padding:0px 5px;
+  text-align:left;
+}
+
+#mainBodyRight td p {
+  margin:0 0 1em 0;
+}
+
+#mainBodyRight .blueBorderBox {
+  border:5px solid #ddf0f2;
+  padding:18px 18px 18px 18px;
+  text-align:left;
+}
+
+#mainBodyFixed .seperator {
+  background-image:url(images/hr_gray_side.jpg);
+  background-repeat:no-repeat;
+  width: 100%;
+  float: left;
+  clear: both;
+}
+
+#mainBodyBottom {
+  float: left;
+  width: 100%;
+  clear:both;
+  color: #333;
+}
+
+#mainBodyBottom .seperator {
+  background-image:url(images/hr_gray_main.jpg);
+  background-repeat:no-repeat;
+  width: 100%;
+  float: left;
+  clear: both;
+}
+
+/* FOOTER */
+
+#footer {
+  float: left;
+  width:90%;
+  margin: 20px;
+  color: #aaa;
+  font-size: 11px;
+}
+
+#footer a {
+  color: #aaa;
+  font-size: 11px;
+}
+
+#footer a:hover {
+  text-decoration: underline;
+  color:#aaa;
+}
+
+#footerlinks {
+  margin-top:2px;
+}
+
+#footerlinks a,
+#footerlinks a:visited {
+  color:#006699;
+}
+
+/* SEARCH FILTER */
+
+#search_autocomplete {
+  color:#aaa;
+}
+
+#search-button {
+  display:inline;
+}
+
+#search_filtered_div {
+  position:absolute;
+  margin-top:-1px;
+  z-index:101;
+  border:1px solid #BCCDF0;
+  background-color:#fff;
+}
+
+#search_filtered {
+  min-width:100%;
+}
+#search_filtered td{
+  background-color:#fff;
+  border-bottom: 1px solid #669999;
+  line-height:1.5em;
+}
+
+#search_filtered .jd-selected {
+  background-color: #94b922;
+  cursor:pointer;
+}
+#search_filtered .jd-selected,
+#search_filtered .jd-selected a {
+  color:#fff;
+}
+
+.no-display {
+  display: none;
+}
+
+.jd-autocomplete {
+  font-family: Arial, sans-serif;
+  padding-left: 6px;
+  padding-right: 6px;
+  padding-top: 1px;
+  padding-bottom: 1px;
+  font-size: 0.81em;
+  border: none;
+  margin: 0;
+  line-height: 1.05em;
+}
+
+.show-row {
+  display: table-row;
+}
+.hide-row {
+  display: hidden;
+}
+
+/* SEARCH */
+
+/* restrict global search form width */
+#searchForm {
+  width:350px;
+}
+
+#searchTxt {
+  width:200px;
+}
+
+/* disable twiddle and size selectors for left column */
+#leftSearchControl div {
+  width: 100%;
+}
+
+#leftSearchControl .gsc-twiddle {
+  background-image : none;
+}
+
+#leftSearchControl td, #searchForm td {
+  border: 0px solid #000;
+}
+
+#leftSearchControl .gsc-resultsHeader .gsc-title {
+  padding-left : 0px;
+  font-weight : bold;
+  font-size : 13px;
+  color:#006699;
+  display : none;
+}
+
+#leftSearchControl .gsc-resultsHeader div.gsc-results-selector {
+  display : none;
+}
+
+#leftSearchControl .gsc-resultsRoot {
+  padding-top : 6px;
+}
+
+#leftSearchControl div.gs-visibleUrl-long {
+  display : block;
+  color:#006699;
+}
+
+.gsc-webResult div.gs-visibleUrl-short,
+table.gsc-branding,
+.gsc-clear-button {
+  display : none;
+}
+
+.gsc-cursor-box .gsc-cursor div.gsc-cursor-page,
+.gsc-cursor-box .gsc-trailing-more-results a.gsc-trailing-more-results,
+#leftSearchControl a,
+#leftSearchControl a b {
+  color:#006699;
+}
+
+.gsc-resultsHeader {
+  display: none;
+}
+
+/* Disable built in search forms */
+.gsc-control form.gsc-search-box {
+  display : none;
+}
+table.gsc-search-box {
+  margin:6px 0 0 0;
+  border-collapse:collapse;
+}
+
+td.gsc-input {
+  padding:0 2px;
+  width:100%;
+  vertical-align:middle;
+}
+
+input.gsc-input {
+  border:1px solid #BCCDF0;
+  width:99%;
+  padding-left:2px;
+  font-size:.95em;
+}
+
+td.gsc-search-button {
+  text-align: right;
+  padding:0;
+  vertical-align:top;
+}
+
+#search-button {
+  margin:0 0 0 2px;
+  font-size:11px;
+}
+
+/* search result tabs */
+
+#doc-content .gsc-control {
+  position:relative;
+}
+
+#doc-content .gsc-tabsArea {
+  position:relative;
+  white-space:nowrap;
+}
+
+#doc-content .gsc-tabHeader {
+  padding: 3px 6px;
+  position:relative;
+}
+
+#doc-content .gsc-tabHeader.gsc-tabhActive {
+  border-top: 2px solid #94B922;
+}
+
+#doc-content h2#searchTitle {
+  padding:0;
+}
+
+#doc-content .gsc-resultsbox-visible {
+  padding:1em 0 0 6px;
+}
+
+/* CAROUSEL */
+
+#homeMiddle {
+  padding: 0px 0px 0px 0px;
+  float: left;
+  width: 584px;
+  height: 627px;
+  position:relative;
+}
+
+#topAnnouncement {
+  background:url(images/home/bg_home_announcement.png) no-repeat 0 0;
+}
+  
+#homeTitle {
+  padding:15px 15px 0;
+  height:30px;
+}
+
+#homeTitle h2 {
+  padding:0;
+}
+
+#announcement-block {
+  padding:0 15px 0;
+  overflow:hidden;
+  background: url(images/hr_gray_side.jpg) no-repeat 15px 0;
+  zoom:1;
+}
+
+#announcement-block>* {
+  padding:15px 0 0;
+}
+
+#announcement-block img {
+  float:left;
+  margin:0 30px 0 0;
+}
+
+#announcement {
+  float:left;
+  margin:0;
+}
+
+#carousel {
+  background:url(images/home/bg_home_carousel.png) no-repeat 0 0;
+  position:relative;
+  height:400px;
+}
+
+#carouselMain {
+  background: url(images/home/bg_home_carousel_board.png) 0 0 no-repeat;
+  height:auto;
+  padding: 25px 21px 0;
+  overflow:hidden;
+  position:relative;
+  zoom:1; /*IE6*/
+}
+
+#carouselMain img {
+  margin:0;
+}
+
+#carouselMain .bulletinDesc h3 {
+  margin:0;
+  padding:0;
+}
+
+#carouselMain .bulletinDesc p {
+  margin:0;
+  padding:0.7em 0 0;
+}
+
+#carouselWheel {
+  background: url(images/home/bg_home_carousel_wheel.png) 0 0 no-repeat;
+  padding-top:40px;
+  height:150px;
+}
+
+.clearer { clear:both; }
+
+a#arrow-left, a#arrow-right {
+  float:left;
+  width:42px;
+  height:42px;
+  background-image:url(images/home/carousel_buttons_sprite.png);
+  background-repeat:no-repeat;
+}
+a#arrow-left {
+  margin:35px 3px 0 10px;
+}
+a#arrow-right {
+  margin:35px 10px 0 0;
+}
+a.arrow-left-off,
+a#arrow-left.arrow-left-off:hover {
+  background-position:0 0;
+}
+a.arrow-right-off,
+a#arrow-right.arrow-right-off:hover {
+  background-position:-42px 0;
+}
+a#arrow-left:hover {
+  background-position:0 -42px;
+}
+a#arrow-right:hover {
+  background-position:-42px -42px;
+}
+a.arrow-left-on {
+  background-position:0 0;
+}
+a.arrow-right-on {
+  background-position:-42px 0;
+}
+a.arrow-right-off,
+a.arrow-left-off {
+  cursor:default;
+}
+
+.app-list-container {
+  margin:0 20px;
+  position:relative;
+  width:100%;
+}
+
+div#list-clip {
+  height:110px;
+  width:438px;
+  overflow:hidden;
+  position:relative;
+  float:left;
+}
+
+div#app-list {
+  left:0;
+  z-index:1;
+  position:absolute;
+  margin:11px 0 0;
+  _margin-top:13px;
+  width:1000%;
+}
+
+#app-list a {
+  display:block;
+  float:left;
+  height:90px;
+  width:90px;
+  margin:0 24px 0;
+  padding:3px;
+  background:#99cccc;
+  -webkit-border-radius:7px;
+  -moz-border-radius:7px;
+  border-radius:7px;
+  text-decoration:none;
+  text-align:center;
+  font-size:11px;
+  line-height:11px;
+}
+
+#app-list a span {
+  position:relative;
+  top:-4px;
+}
+
+#app-list img {
+  width:90px;
+  height:70px;
+  margin:0;
+}
+
+#app-list a.selected,
+#app-list a:active.selected,
+#app-list a:hover.selected {
+  background:#A4C639;
+  color:#fff;
+  cursor:default;
+  text-decoration:none;
+}
+
+#app-list a:hover,
+#app-list a:active {
+  background:#ff9900;
+}
+
+#app-list a:hover span,
+#app-list a:active span {
+  text-decoration:underline;
+}
+
+#droid-name {
+  padding-top:.5em;
+  color:#666;
+  padding-bottom:.25em;
+}
+
+/*IE6*/
+* html #app-list a { zoom: 1; margin:0 24px 0 15px;}
+
+* html #list-clip {
+  width:430px !important;
+}
+
+/*carousel bulletin layouts*/
+/*460px width*/
+/*185px height*/
+.img-left {
+  float:left;
+  width:230px;
+  overflow:hidden;
+  padding:8px 0 8px 8px;
+}
+.desc-right {
+  float:left;
+  width:270px;
+  padding:10px;
+}
+.img-right {
+  float:right;
+  width:220px;
+  overflow:hidden;
+  padding:8px 8px 8px 0;
+}
+.desc-left {
+  float:right;
+  width:280px;
+  padding:10px;
+  text-align:right;
+}
+.img-top {
+  padding:20px 20px 0;
+}
+.desc-bottom {
+  padding:10px;
+}
+
+
+/* VIDEO PAGE */
+
+#mainBodyLeft.videoPlayer {
+  width:570px;
+}
+
+#mainBodyRight.videoPlayer {
+  width:330px;
+}
+
+/* player */
+
+#videoPlayerBox {
+  background-color: #DAF3FC;
+  border-radius:7px;
+  -moz-border-radius:7px;
+  -webkit-border-radius:7px;
+  width:530px;
+  padding:20px;
+  border:1px solid #d3ecf5;
+  box-shadow:2px 3px 1px #eee;
+  -moz-box-shadow:2px 3px 1px #eee;
+  -webkit-box-shadow:2px 3px 1px #eee;
+}
+
+#videoBorder {
+  background-color: #FFF;
+  min-height:399px;
+  height:auto !important;
+  border:1px solid #ccdada;
+  border-radius:7px 7px 0 0;
+  -moz-border-radius:7px 7px 0 0;
+  -webkit-border-top-left-radius:7px;
+  -webkit-border-top-right-radius:7px;
+}
+
+#videoPlayerTitle {
+  width:500px;
+  padding:15px 15px 0;
+}
+
+#videoPlayerTitle h2 {
+  font-weight:bold;
+  font-size:1.2em;
+  color:#336666;
+  margin:0;
+  padding:0;
+}
+
+#objectWrapper {
+  padding:15px 15px;
+  height:334px;
+  width:500px;
+}
+
+/* playlist tabs */
+
+ul#videoTabs {
+  list-style-type:none;
+  padding:0;
+  clear:both;
+  margin:0;
+  padding: 20px 0 0 15px;
+  zoom:1; /* IE7/8, otherwise top-padding is double */
+}
+
+ul#videoTabs li {
+  display:inline;
+  padding:0;
+  margin:0 3px 0 0;
+  line-height:2em;
+}
+
+ul#videoTabs li a {
+  border-radius:7px 7px 0 0;
+  -moz-border-radius:7px 7px 0 0;
+  -webkit-border-top-left-radius:7px;
+  -webkit-border-top-right-radius:7px;
+  background:#95c0d0;
+  color:#fff;
+  text-decoration:none;
+  padding:.45em 1.5em;
+  font-weight:bold;
+}
+
+ul#videoTabs li.selected a {
+  font-weight:bold;
+  text-decoration:none;
+  color:#555;
+  background:#daf3fc;
+  border-bottom:1px solid #daf3fc;
+}
+
+ul#videoTabs li:hover a {
+  background:#85acba;
+}
+
+ul#videoTabs li.selected:hover a {
+  background:#daf3fc;
+}
+
+/* playlists */
+
+#videos {
+  background:#daf3fc;
+  margin-bottom:1.5em;
+  padding:15px;
+  border-radius:5px;
+  -moz-border-radius:5px;
+  -webkit-border-radius:5px;
+  box-shadow:2px 3px 1px #eee;
+  -moz-box-shadow:2px 3px 1px #eee;
+  -webkit-box-shadow:2px 3px 1px #eee;
+}
+
+#videos div {
+  display:none;
+}
+
+#videos div.selected {
+  display:block;
+}
+
+ul.videoPreviews {
+  list-style:none;
+  padding:0;
+  margin:0;
+  zoom:1; /* IE, otherwise, layout doesn't update when showing 'more' */
+}
+
+ul.videoPreviews li {
+  margin:0 0 5px;
+  padding:0;
+  overflow:hidden;
+  position:relative;
+}
+
+#mainBodyFixed ul.videoPreviews h3 {
+  font-size: 12px;
+  margin:0 0 1em 130px;
+  padding:0;
+  font-weight:bold;
+  color:inherit;
+}
+
+ul.videoPreviews a {
+  margin:1px;
+  padding:10px;
+  text-decoration:none;
+  height:90px;
+  display:block;
+  border-radius:5px;
+  -moz-border-radius:5px;
+  -webkit-border-radius:5px;
+  background-color:transparent;
+}
+
+ul.videoPreviews a:hover {
+  background-color:#FFF;
+  border:none; /* IE8, otherwise, bg doesn't work */
+}
+
+ul.videoPreviews a.selected {
+  background-color: #FF9900;
+}
+
+ul.videoPreviews img {
+  float:left;
+  clear:left;
+  margin:0;
+}
+
+ul.videoPreviews h3 {
+  font-size:12px;
+  font-weight:bold;
+  text-decoration:none;
+  margin:0 0 1em 130px;
+  padding:0;
+}
+
+ul.videoPreviews p {
+  font-size: 12px;
+  text-decoration:none;
+  margin:0 0 1.2em 130px;
+}
+
+ul.videoPreviews p.full {
+  display:none;
+}
+
+ul.videoPreviews span.more {
+  padding:0 0 0 12px;
+  background:url(images/arrow_bluelink_down.png) 0 2px no-repeat;
+}
+
+ul.videoPreviews span.less {
+  padding:0 0 0 12px;
+  background:url(images/arrow_bluelink_up.png) 0 2px no-repeat;
+  display:none;
+}
+
+ul.videoPreviews p.toggle {
+  position:absolute;
+  margin:0;
+  margin-top:-23px; /* instead of bottom:23px, because IE won't do it correctly */
+  left:140px;
+}
+
+ul.videoPreviews p.toggle a {
+  height:auto;
+  margin:0;
+  padding:0;
+  zoom:1; /* IE6, otherwise the margin considers the img on redraws */
+}
+
+ul.videoPreviews p.toggle a:hover {
+  text-decoration:underline;
+  background:transparent; /* IE6, otherwise it inherits white */
+}
+
+/* featured videos */
+
+#mainBodyRight h2 {
+  padding:0 0 5px;
+}
+
+#mainBodyRight ul.videoPreviews {
+  margin:10px 0 0;
+}
+
+#mainBodyRight ul.videoPreviews li {
+  font-size:11px;
+  line-height:13px;
+  margin:0 0 5px;
+  padding:0;
+}
+
+#mainBodyRight ul.videoPreviews h3 {
+  padding:0;
+  margin:0;
+}
+
+#mainBodyRight ul.videoPreviews a {
+  text-decoration:none;
+  height:108px;
+  border:1px solid #FFF;
+}
+
+#mainBodyRight ul.videoPreviews a:hover {
+  border:1px solid #CCDADA;
+}
+
+#mainBodyRight ul.videoPreviews a.selected {
+  border:1px solid #FFF;
+}
+
+#mainBodyRight ul.videoPreviews p {
+  line-height:1.2em;
+  padding:0;
+  margin:4px 0 0 130px;
+}
+
+#mainBodyRight ul.videoPreviews img {
+  margin-top:5px;
+}
+
+/* Pretty printing styles. Used with prettify.js. */
+
+.str { color: #080; }
+.kwd { color: #008; }
+.com { color: #800; }
+.typ { color: #606; }
+.lit { color: #066; }
+.pun { color: #660; }
+.pln { color: #000; }
+dl.tag-list dt code,
+.tag { color: #008; }
+dl.atn-list dt code,
+.atn { color: #828; }
+.atv { color: #080; }
+.dec { color: #606; }
+
+@media print {
+  .str { color: #060; }
+  .kwd { color: #006; font-weight: bold; }
+  .com { color: #600; font-style: italic; }
+  .typ { color: #404; font-weight: bold; }
+  .lit { color: #044; }
+  .pun { color: #440; }
+  .pln { color: #000; }
+  .tag { color: #006; font-weight: bold; }
+  .atn { color: #404; }
+  .atv { color: #060; }
+}
diff --git a/res/assets/templates/assets/android-developer-docs-devguide.css b/res/assets/templates/assets/android-developer-docs-devguide.css
new file mode 100644
index 0000000..d8bd3b3
--- /dev/null
+++ b/res/assets/templates/assets/android-developer-docs-devguide.css
@@ -0,0 +1,19 @@
+
+@import url("android-developer-docs.css");
+
+/* Page title */
+
+#jd-header h1 {
+  padding: 8px 0 0 0;
+}
+
+/* Page content container */
+
+#jd-header table {
+margin: 0 0 1em 1em;
+}
+
+#jd-content table table,
+#jd-content table img {
+  margin:1em 0;
+}
\ No newline at end of file
diff --git a/res/assets/templates/assets/android-developer-docs.css b/res/assets/templates/assets/android-developer-docs.css
new file mode 100644
index 0000000..6662522
--- /dev/null
+++ b/res/assets/templates/assets/android-developer-docs.css
@@ -0,0 +1,1300 @@
+/* file: android-developer-docs.css
+   author: smain
+   date: september 2008
+   info: developer doc styles (developer.android.com)
+*/
+
+@import url("android-developer-core.css");
+
+#title {
+  border-bottom: 4px solid #ccc;
+  display:none;
+}
+
+#title h1 {
+  color:#336666;
+  margin:0;
+  padding: 5px 10px;
+  font-size: 1em;
+  line-height: 15px;
+}
+
+#title h1 .small{
+  color:#000;
+  margin:0;
+  font-size: 13px;
+  padding:0 0 0 15px;
+}
+
+/* SIDE NAVIGATION */
+
+#side-nav {
+  padding:0 6px 0 0;
+  background-color: #fff;
+  font-size:12px;
+}
+
+#side-nav.not-resizable {
+  background:url('images/sidenav-rule.png') no-repeat 243px 0;
+}
+
+#resize-packages-nav {
+/* keeps the resize handle below the h-scroll handle */
+  height:270px;
+  overflow:hidden;
+  max-height:100%;
+}
+
+#packages-nav {
+  height:270px;
+  max-height:inherit;
+  position:relative;
+  overflow:auto;
+}
+
+#classes-nav,
+#devdoc-nav {
+  overflow:auto;
+  position:relative;
+}
+
+#side-nav ul {
+  list-style: none;
+  margin: 0;
+  padding:5px 0;
+}
+
+#side-nav ul ul {
+  margin: .35em 0 0 0;
+  padding: 0;
+}
+
+#side-nav li {
+  padding:0;
+  line-height:16px;
+  white-space:nowrap;
+  zoom:1;
+}
+
+#side-nav li h2 {
+  font-size:12px;
+  font-weight: bold;
+  margin:.5em 0 0 0;
+  padding: 3px 0 1px 9px;
+}
+
+#side-nav li a {
+  text-decoration:none;
+  padding: 0 0 0 18px;
+  zoom:1;
+}
+
+#side-nav li a span+span {
+  display:none;
+}
+
+#side-nav li a:hover {
+  text-decoration:underline;
+}
+
+#side-nav li a+a {
+  padding: 0;
+}
+/*second level (nested) list*/
+#side-nav li li li a {
+  padding: 0 0 0 28px;
+}
+/*third level (nested) list*/
+#side-nav li li li li a {
+  padding: 0 0 0 38px;
+}
+
+#side-nav .selected {
+  background-color: #435a6e;
+  color: #fff;
+  font-weight:bold;
+}
+
+#side-nav .selected a {
+  color: #fff;
+  text-decoration:none;
+}
+
+#side-nav strong {
+  display:block;
+}
+
+#side-nav .toggle-list .toggle-img {
+  margin:0;
+  padding:0;
+  position:absolute;
+  top:0;
+  left:0;
+  height:16px;
+  width:15px;
+  outline-style:none;
+}
+/* second-level toggle */
+#side-nav .toggle-list .toggle-list .toggle-img {
+  left:10px;
+}
+
+#side-nav .closed .toggle-img,
+#side-nav .open .closed .toggle-img {
+  background:url('images/triangle-closed-small.png') 7px 4px no-repeat;
+}
+#side-nav .open .toggle-img {
+  background:url('images/triangle-opened-small.png') 7px 4px no-repeat;
+}
+
+#side-nav .toggle-list {
+  position:relative;
+}
+
+#side-nav .toggle-list ul {
+  margin:0;
+  display:none;
+}
+
+#side-nav .toggle-list div {
+  display:block;
+}
+
+#index-links .selected {
+  background-color: #fff;
+  color: #000;
+  font-weight:normal;
+  text-decoration:none;
+}
+
+#index-links {
+  padding:7px 0 4px 10px;
+}
+
+/* nav tree */
+
+#nav-tree ul {
+  padding:5px 0 1.5em;
+}
+
+#side-nav #nav-tree ul li a,
+#side-nav #nav-tree ul li span.no-children {
+  padding: 0 0 0 0;
+  margin: 0;
+}
+
+#nav-tree .plus {
+  margin: 0 3px 0 0;
+}
+
+#nav-tree ul ul {
+  list-style: none;
+  margin: 0;
+  padding: 0 0 0 0;
+}
+
+#nav-tree ul li {
+  margin: 0;
+  padding: 0 0 0 0;
+  white-space: nowrap;
+}
+
+#nav-tree .children_ul {
+  margin:0;
+}
+
+#nav-tree a.nolink {
+  color: black;
+  text-decoration: none;
+}
+
+#nav-tree span.label {
+  width: 100%;
+}
+
+#nav-tree {
+  overflow-x: auto;
+  overflow-y: scroll;
+}
+
+#nav-swap {
+  font-size:10px;
+  line-height:10px;
+  margin-left:1em;
+  text-decoration:none;
+  display:block;
+  position:absolute;
+  bottom:2px;
+  left:0px;
+}
+
+#tree-link {
+
+}
+
+/* DOCUMENT BODY */
+
+#doc-content {
+  overflow:auto;
+}
+
+#jd-header {
+  background-color: #E2E2E2;
+  padding: 7px 15px;
+}
+
+#jd-header h1 {
+  margin: 0 0 10px;
+  font-size:1.7em;
+}
+
+#jd-header .crumb {
+  font-size:.9em;
+  line-height:1em;
+  color:#777;
+}
+
+#jd-header .crumb a,
+#jd-header .crumb a:visited {
+  text-decoration:none;
+  color:#777;
+}
+
+#jd-header .crumb a:hover {
+  text-decoration:underline;
+}
+
+#jd-header table {
+  margin:0;
+  padding:0;
+}
+
+#jd-header td {
+  border:none;
+  padding:0;
+  vertical-align:top;
+}
+
+#jd-header.guide-header {
+  background-color:#fff;
+  color:#435a6e;
+  height:50px;
+}
+
+#jd-descr {
+  position:relative;
+}
+
+/* summary tables for reference pages */
+.jd-sumtable {
+  margin: .5em 1em 1em 1em;
+  width:95%; /* consistent table widths; within IE's quirks */
+  font-size:.9em;
+}
+
+.jd-sumtable a {
+  text-decoration:none;
+}
+
+.jd-sumtable a:hover {
+  text-decoration:underline;
+}
+
+/* the link inside a sumtable for "Show All/Hide All" */
+.toggle-all {
+  display:block;
+  float:right;
+  font-weight:normal;
+  font-size:0.9em;
+}
+
+/* adjustments for in/direct subclasses tables */
+.jd-sumtable-subclasses {
+  margin: 1em 0 0 0;
+  max-width:968px;
+}
+
+/* extra space between end of method name and open-paren */
+.sympad {
+  margin-right: 2px;
+}
+
+/* right alignment for the return type in sumtable */
+.jd-sumtable .jd-typecol {
+  text-align:right;
+}
+
+/* adjustments for the expando table-in-table */
+.jd-sumtable-expando {
+  margin:.5em 0;
+  padding:0;
+}
+
+/* a div that holds a short description */
+.jd-descrdiv {
+  padding:3px 1em 0 1em;
+  margin:0;
+  border:0;
+}
+
+/* page-top-right container for reference pages (holds
+links to summary tables) */
+#api-info-block {
+  font-size:.8em;
+  padding:6px 10px;
+  font-weight:normal;
+  float:right;
+  text-align:right;
+  color:#999;
+  max-width:70%;
+}
+
+#api-level-toggle {
+  padding:0 0px;
+  font-size:11px;
+}
+
+#api-level-toggle label.disabled {
+  color:#999;
+}
+
+div.api-level {
+  font-size:.8em;
+  font-weight:normal;
+  color:#999;
+  float:right;
+  padding:0 7px 0;
+  margin-top:-25px;
+}
+
+#api-info-block div.api-level {
+  font-size:1.3em;
+  font-weight:bold;
+  float:none;
+  color:#444;
+  padding:0;
+  margin:0;
+}
+
+/* Force link colors for IE6 */
+div.api-level a {
+  color:#999;
+}
+#api-info-block div.api-level a:link {
+  color:#444;
+}
+#api-level-toggle a {
+  color:#999;
+}
+
+div#naMessage {
+  display:none;
+  width:555px;
+  height:0;
+  margin:0 auto;
+}
+
+div#naMessage div {
+  width:450px;
+  position:fixed;
+  margin:50px 0;
+  padding:4em 4em 3em;
+  background:#FFF;
+  background:rgba(255,255,255,0.7);
+  border:1px solid #dddd00;
+}
+/* IE6 can't position fixed */
+* html div#naMessage div { position:absolute; }
+
+div#naMessage strong {
+  font-size:1.1em;
+}
+
+.absent,
+.absent a:link,
+.absent a:visited,
+.absent a:hover,
+.absent * {
+  color:#bbb !important;
+  cursor:default !important;
+  text-decoration:none !important;
+}
+
+#api-level-toggle a,
+.api-level a {
+  color:inherit;
+  text-decoration:none;
+}
+
+#api-level-toggle a:hover,
+.api-level a:hover {
+  color:inherit;
+  text-decoration:underline !important;
+  cursor:pointer !important;
+}
+
+#side-nav li.absent.selected,
+#side-nav li.absent.selected *,
+#side-nav div.label.absent.selected,
+#side-nav div.label.absent.selected * {
+  background-color:#eaeaea !important;
+}
+/* IE6 quirk (won't chain classes, so just keep background blue) */
+* html #side-nav li.selected,
+* html #side-nav li.selected *,
+* html #side-nav div.label.selected,
+* html #side-nav div.label.selected * {
+  background-color: #435a6e !important;
+}
+
+
+.absent h4.jd-details-title,
+.absent h4.jd-details-title * {
+  background-color:#f6f6f6 !important;
+}
+
+.absent img {
+  opacity: .3;
+  filter: alpha(opacity=30);
+  -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";
+}
+
+
+/* applies to a div containing links to summary tables */
+.sum-details-links {
+  padding:0;
+  font-weight:normal;
+}
+
+.sum-details-links a {
+  text-decoration:none;
+}
+
+.sum-details-links a:hover {
+  text-decoration:underline;
+}
+
+
+/* inheritance table */
+.jd-inheritance-table {
+  border-spacing:0;
+  margin:0;
+  padding:0;
+  font-size:.9em;
+}
+.jd-inheritance-table td {
+  border: none;
+  margin: 0;
+  padding: 0;
+}
+.jd-inheritance-table .jd-inheritance-space {
+  font-weight:bold;
+  width:1em;
+}
+.jd-inheritance-table .jd-inheritance-interface-cell {
+  padding-left: 17px;
+}
+
+#jd-content {
+  padding: 18px 15px;
+}
+
+hr {
+  background-color:#ccc;
+  border-color:#fff;
+  margin:2em 0 1em;
+}
+
+/* DOC CLASSES */
+
+#jd-content h1 {
+/*sdk page*/
+  font-size:1.6em;
+  color:#336666;
+  margin:0 0 .5em;
+}
+
+#jd-content h2 {
+  font-size:1.45em;
+  color:#111;
+  border-top:2px solid #ccc;
+  padding: .5em 0 0;
+  margin: 2em 0 1em 0;
+}
+
+#jd-content h3 {
+  font-size:1.2em;
+  color:#222;
+  padding: .75em 0 .65em 0;
+  margin:0;
+}
+
+#jd-content h4 {
+  font-size:1.1em;
+  margin-bottom:.5em;
+  color:#222;
+}
+
+#jd-content .small-header {
+  font-size:1em;
+  color:#000;
+  font-weight:bold;
+  border:none;
+  padding:0;
+  margin:1em 0 .5em;
+  position:inherit;
+}
+
+#jd-content table {
+  margin: 0 0 1em 1em;
+}
+
+#jd-content img {
+  margin: 0 0 1em 1em;
+}
+
+#jd-content li img,
+#jd-content dd img {
+  margin:.5em 0 0 1em;
+}
+
+.nolist {
+  list-style:none;
+  padding:0;
+  margin:0 0 1em 1em;
+}
+
+.nolist li {
+  padding:0 0 2px;
+  margin:0;
+}
+
+h4 .normal {
+  font-size:.9em;
+  font-weight:normal;
+}
+
+.caps {
+  font-variant:small-caps;
+  font-size:1.2em;
+}
+
+dl.tag-list dl.atn-list {
+  padding:0 0 0 2em;
+}
+
+.jd-details {
+/*  border:1px solid #669999;
+  padding:4px; */
+  margin:0 0 1em;
+}
+
+/* API reference: a container for the
+.tagdata blocks that make up the detailed
+description */
+.jd-details-descr {
+  padding:0;
+  margin:.5em .25em;
+}
+
+/* API reference: a block containing
+a detailed description, a params table,
+seealso list, etc */
+.jd-tagdata {
+  margin:.5em 1em;
+}
+
+.jd-tagdata p {
+  margin:0 0 1em 1em;
+}
+
+/* API reference: adjustments to
+the detailed description block */
+.jd-tagdescr {
+  margin:.25em 0 .75em 0;
+  line-height:1em;
+}
+
+.jd-tagdescr p {
+  margin:.5em 0;
+  padding:0;
+
+}
+
+.jd-tagdescr ol,
+.jd-tagdescr ul {
+  margin:0 2.5em;
+  padding:0;
+}
+
+.jd-tagdescr table,
+.jd-tagdescr img {
+  margin:.25em 1em;
+}
+
+.jd-tagdescr li {
+margin:0 0 .25em 0;
+padding:0;
+}
+
+/* API reference: heading marking
+the details section for constants,
+attrs, methods, etc. */
+h4.jd-details-title {
+  font-size:1.15em;
+  background-color: #E2E2E2;
+  margin:1.5em 0 .6em;
+  padding:3px 95px 3px 3px; /* room for api-level */
+}
+
+h4.jd-tagtitle {
+  margin:0;
+}
+
+/* API reference: heading for "Parameters", "See Also", etc.,
+in details sections */
+h5.jd-tagtitle {
+  margin:0 0 .25em 0;
+  font-size:1em;
+}
+
+.jd-tagtable {
+  margin:0;
+}
+
+.jd-tagtable td,
+.jd-tagtable th {
+  border:none;
+  background-color:#fff;
+  vertical-align:top;
+  font-weight:normal;
+  padding:2px 10px;
+}
+
+.jd-tagtable th {
+  font-style:italic;
+}
+
+#jd-content table h2 {
+  background-color: #d6d6d6;
+  font-size: 1.1em;
+  margin:0 0 10px;
+  padding:5px;
+  left:0;
+  width:auto;
+}
+
+div.special {
+  padding: .5em 1em 1em 1em;
+  margin: 0 0 1em;
+  background-color: #DAF3FC;
+  border:1px solid #d3ecf5;
+  border-radius:5px;
+  -moz-border-radius:5px;
+  -webkit-border-radius:5px;
+}
+
+.toggle-content-toggleme {
+  display:none;
+}
+
+.toggle-content-button {
+  font-size:.9em;
+  line-height:.9em;
+  text-decoration:none;
+  position:relative;
+  top:5px;
+}
+
+.toggle-content-button:hover {
+  text-decoration:underline;
+}
+
+div.special p {
+  margin: .5em 0 0 0;
+}
+
+div.special ol {
+  margin: 0;
+}
+
+div.special ol li {
+  margin: 0;
+  padding: 0;
+}
+
+#jd-content div.special h2,
+#jd-content div.special h3 {
+  color:#669999;
+  font-size:1.2em;
+  border:none;
+  margin:0 0 .5em;
+  padding:0;
+}
+
+p.note, p.caution, p.warning {
+  margin: 1em;
+  padding: 0 0 0 .5em;
+  border-left: 4px solid;
+}
+
+p.special-note {
+  background-color:#EBF3DB;
+  padding:10px 20px;
+  margin:0 0 1em;
+}
+
+p.note {
+ border-color: #99aacc;
+}
+
+p.warning {
+  border-color: #aa0033;
+}
+
+p.caution {
+  border-color: #ffcf00;
+}
+
+p.warning b, p.warning strong {
+  font-weight: bold;
+}
+
+li p.note, li p.warning {
+  margin: .5em 0 0 0;
+  padding: .2em .5em .2em .9em;
+}
+
+dl.xml dt {
+  font-variant:small-caps;
+  font-size:1.2em;
+}
+
+dl.xml dl {
+  padding:0;
+}
+
+dl.xml dl dt {
+  font-variant:normal;
+  font-size:1em;
+}
+
+.listhead li {
+  font-weight: bold;
+}
+
+.listhead li *, /*ie*/.listhead li li {
+  font-weight: normal;
+}
+
+ol.no-style,
+ul.no-style {
+  list-style:none;
+  padding-left:1em;
+}
+
+.new {
+  font-size: .78em;
+  font-weight: bold;
+  color: #ff3d3d;
+  text-decoration: none;
+  vertical-align:top;
+  line-height:.9em;
+}
+
+pre.classic {
+  background-color:transparent;
+  border:none;
+  padding:0;
+}
+
+p.img-caption {
+  margin: -0.5em 0 1em 1em; /* matches default img left-margin */
+}
+
+div.figure {
+  float:right;
+  clear:right;
+  margin:1em 0 0 3em;
+  padding:0;
+  background-color:#fff;
+  /* width must be defined w/ an inline style matching the image width */
+}
+
+#jd-content
+div.figure img {
+  margin: 0 0 1em;
+}
+
+div.figure p.img-caption {
+  margin: -0.5em 0 1em 0;
+}
+
+p.table-caption {
+  margin: 0 0 0.5em 1em; /* matches default table left-margin */
+}
+
+/* BEGIN quickview sidebar element styles */
+
+#qv-wrapper {
+  float: right;
+  width:310px; /* +35px padding */
+  background-color:#fff;
+  margin:-48px 0 2px 0;
+  padding:0 0 20px 35px;
+}
+
+#qv {
+  background-color:#fff;
+  border:4px solid #dee8f1;
+  margin:0;
+  padding:0 5px 5px;
+  width:292px; /* +10px padding; +8px border */
+  font-size:.9em;
+}
+
+#qv ol {
+  list-style:none;
+  padding: 0;
+}
+
+#qv ol ol{
+  list-style:none;
+  padding: 0 0 0 12px;
+  margin:0;
+}
+
+#qv ul {
+  padding: 0 10px 0 2em;
+}
+
+#qv li {
+  padding: 0 10px 3px;
+  line-height: 1.2em;
+}
+
+#qv li li {
+  padding: 3px 10px 0;
+}
+
+#qv ul li {
+  padding: 0 10px 0 0;
+}
+
+#qv li.selected a {
+  color:#555;
+  text-decoration:none;
+}
+
+#qv a {
+  color:#cc6600;
+}
+
+#qv p {
+  margin:8px 0 0;
+  padding:0 10px;
+}
+
+#qv-extra #rule {
+  padding: 0 10px;
+  margin: 0;
+}
+
+#qv-sub-rule {
+  padding: 6px 20px;
+  margin: 0;
+}
+
+#qv-sub-rule p {
+  margin: 0;
+}
+
+#jd-content #qv h2 {
+  font-size:1.05em;
+  font-weight:bold;
+  margin:12px 0 .25em 0;
+  padding:0 10px;
+  background-color:transparent;
+  color:#7BB026;
+  border:none;
+  left:0;
+  z-index:1;
+}
+
+/* END quickview sidebar element styles */
+
+/* Begin sidebox sidebar element styles */
+
+.sidebox-wrapper {
+  float:right;
+  clear:right;
+  width:310px; /* +35px padding */
+  background-color:#fff;
+  margin:0;
+  padding:0 0 20px 35px;
+}
+
+.sidebox {
+  border-left:1px solid #dee8f1;
+  background-color:#ffffee;
+  margin:0;
+  padding:8px 12px;
+  font-size:0.9em;
+  width:285px; /* +24px padding; +1px border */
+}
+
+.sidebox p {
+  margin-bottom: .25em;
+}
+
+.sidebox ul {
+  padding: 0 0 0 1.5em;
+}
+
+.sidebox li ul {
+  margin-top:0;
+  margin-bottom:.1em;
+}
+
+.sidebox li {
+padding:0 0 0 0em;
+}
+
+#jd-content .sidebox h2,
+#jd-content .sidebox h3,
+#jd-content .sidebox h4,
+#jd-content .sidebox h5 {
+  border:none;
+  font-size:1em;
+  margin:0;
+  padding:0 0 8px;
+  left:0;
+  z-index:0;
+}
+
+.sidebox hr {
+  background-color:#ccc;
+  border:none;
+}
+
+/* End sidebox sidebar element styles */
+
+/* BEGIN image and caption styles (originally for UI Guidelines docs) */
+
+table.image-caption {
+  padding:0;
+  margin:.5em 0;
+  border:0;
+}
+
+td.image-caption-i {
+  font-size:92%;
+  padding:0 5px;
+  margin:0;
+  border:0;
+}
+
+td.image-caption-i img {
+  padding:0 1em;
+  margin:0;
+}
+
+.image-list {
+  width:24px;
+  text-align:center;
+}
+
+td.image-caption-c {
+  font-size:92%;
+  padding:1em 2px 2px 2px;
+  margin:0;
+  border:0;
+  width:350px;
+}
+
+.grad-rule-top {
+background-image:url(images/grad-rule-qv.png);
+background-repeat:no-repeat;
+padding-top:1em;
+margin-top:0;
+}
+
+.image-caption-nested {
+  margin-top:0;
+  padding:0 0 0 1em;
+}
+
+.image-caption-nested td {
+  padding:0 4px 2px 0;
+  margin:0;
+  border:0;
+}
+
+/* END image and caption styles */
+
+/* table of contents */
+
+ol.toc {
+  margin: 0 0 1em 0;
+  padding: 0;
+  list-style: none;
+  font-size:95%;
+}
+
+ol.toc li {
+  font-weight: bold;
+  margin: 0 0 .5em 1em;
+  padding: 0;
+}
+
+ol.toc li p {
+  font-weight: normal;
+}
+
+ol.toc li ol {
+  margin: 0;
+  padding: 0;
+}
+  
+ol.toc li li {
+  padding: 0;
+  margin: 0 0 0 1em;
+  font-weight: normal;
+  list-style: none;
+}
+
+table ol.toc {
+  margin-left: 0;
+}
+
+.columns td {
+  padding:0 5px;
+  border:none;
+}
+
+/* link table */
+.jd-linktable {
+  margin: 0 0 1em;
+  border-bottom: 1px solid #888;
+}
+.jd-linktable th,
+.jd-linktable td {
+  padding: 3px 5px;
+  vertical-align: top;
+  text-align: left;
+  border:none;
+}
+.jd-linktable tr {
+  background-color: #fff;
+}
+.jd-linktable td {
+  border-top: 1px solid #888;
+  background-color: inherit;
+}
+.jd-linktable td  p {
+  padding: 0 0 5px;
+}
+.jd-linktable .jd-linkcol {
+}
+.jd-linktable .jd-descrcol {
+}
+.jd-linktable .jd-typecol {
+  text-align:right;
+}
+.jd-linktable .jd-valcol {
+}
+.jd-linktable .jd-commentrow {
+  border-top:none;
+  padding-left:25px;
+}
+.jd-deprecated-warning {
+  margin-top: 0;
+  margin-bottom: 10px;
+}
+
+tr.alt-color {
+  background-color: #f6f6f6;
+}
+
+/* expando trigger */
+#jd-content .jd-expando-trigger-img {
+  margin:0;
+}
+
+/* jd-expando */
+.jd-inheritedlinks {
+  padding:0 0 0 13px
+}
+
+/* SDK PAGE */
+table.download tr {
+  background-color:#d9d9d9;
+}
+
+table.download tr.alt-color {
+  background-color:#ededed;
+}
+
+table.download td,
+table.download th {
+  border:2px solid #fff;
+  padding:10px 5px;
+}
+
+table.download th {
+  background-color:#6d8293;
+  color:#fff;
+}
+
+/* INLAY 180 COPY and 240PX EXTENSION */
+/* modified to 43px so that all browsers eliminate the package panel h-scroll */
+.g-tpl-240 .g-unit,
+.g-unit .g-tpl-240 .g-unit,
+.g-unit .g-unit .g-tpl-240 .g-unit {
+  display: block;
+  margin: 0 0 0 243px;
+  width: auto;
+  float: none;
+}
+.g-unit .g-unit .g-tpl-240 .g-first,
+.g-unit .g-tpl-240 .g-first,
+.g-tpl-240 .g-first {
+  display: block;
+  margin: 0;
+  width: 243px;
+  float: left;
+}
+/* 240px alt */
+.g-tpl-240-alt .g-unit,
+.g-unit .g-tpl-240-alt .g-unit,
+.g-unit .g-unit .g-tpl-240-alt .g-unit {
+  display: block;
+  margin: 0 243px 0 0;
+  width: auto;
+  float: none;
+}
+.g-unit .g-unit .g-tpl-240-alt .g-first,
+.g-unit .g-tpl-240-alt .g-first,
+.g-tpl-240-alt .g-first {
+  display: block;
+  margin: 0;
+  width: 243px;
+  float: right;
+}
+
+/* 180px */
+.g-tpl-180 .g-unit,
+.g-unit .g-tpl-180 .g-unit,
+.g-unit .g-unit .g-tpl-180 .g-unit {
+  display: block;
+  margin: 0 0 0 180px;
+  width: auto;
+  float: none;
+}
+.g-unit .g-unit .g-tpl-180 .g-first,
+.g-unit .g-tpl-180 .g-first,
+.g-tpl-180 .g-first {
+  display: block;
+  margin: 0;
+  width: 180px;
+  float: left;
+}
+/* 180px alt */
+.g-tpl-180-alt .g-unit,
+.g-unit .g-tpl-180-alt .g-unit,
+.g-unit .g-unit .g-tpl-180-alt .g-unit {
+  display: block;
+  margin: 0 180px 0 0;
+  width: auto;
+  float: none;
+}
+.g-unit .g-unit .g-tpl-180-alt .g-first,
+.g-unit .g-tpl-180-alt .g-first,
+.g-tpl-180-alt .g-first {
+  display: block;
+  margin: 0;
+  width: 180px;
+  float: right;
+}
+
+  
+/* JQUERY RESIZABLE STYLES */
+.ui-resizable { position: relative; }
+.ui-resizable-handle { position: absolute; display: none; font-size: 0.1px; z-index:1; }
+.ui-resizable .ui-resizable-handle { display: block; }
+body .ui-resizable-disabled .ui-resizable-handle { display: none; }
+body .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-s { cursor: s-resize; height: 6px; width: 100%; bottom: 0px; left: 0px;
+  background: transparent url("images/resizable-s2.gif") repeat scroll center top; }
+.ui-resizable-e { cursor: e-resize; width: 6px; right: 0px; top: 0px; height: 100%;
+  background: transparent url("images/resizable-e2.gif") repeat scroll right center; }
+
+@media print {
+
+  body {
+    overflow:visible;
+  }
+
+  #header {
+    height:60px;
+  }
+
+  #headerLeft {
+    padding:0;
+  }
+
+  #header-tabs,
+  #headerRight,
+  #side-nav,
+  #api-info-block {
+    display:none;
+  }
+
+  #body-content {
+    position:inherit;
+  }
+  
+  #doc-content {
+    margin-left:0 !important;
+    height:auto !important;
+    width:auto !important;
+    overflow:inherit;
+    display:inline;
+  }
+
+  #jd-header {
+    padding:10px 0;
+  }
+
+  #jd-content {
+    padding:15px 0 0;
+  }
+
+  #footer {
+    float:none;
+    margin:2em 0 0;
+  }
+
+  h4.jd-details-title {
+    border-bottom:1px solid #666;
+  }
+
+  pre {
+    /* these allow lines to break (if there's a white space) */
+    overflow: visible;
+    text-wrap: unrestricted;
+    white-space: -moz-pre-wrap; /* Moz */
+    white-space: -pre-wrap; /* Opera 4-6 */
+    white-space: -o-pre-wrap; /* Opera 7 */
+    white-space: pre-wrap; /* CSS3  */
+    word-wrap: break-word; /* IE 5.5+ */
+  }
+
+  h1, h2, h3, h4, h5, h6 {
+    page-break-after: avoid;
+  }
+
+  table, img {
+    page-break-inside: avoid;
+  }
+}
diff --git a/res/assets/templates/assets/android-developer-docs.js b/res/assets/templates/assets/android-developer-docs.js
new file mode 100644
index 0000000..96c256e
--- /dev/null
+++ b/res/assets/templates/assets/android-developer-docs.js
@@ -0,0 +1,593 @@
+var resizePackagesNav;
+var classesNav;
+var devdocNav;
+var sidenav;
+var content;
+var HEADER_HEIGHT = -1;
+var cookie_namespace = 'android_developer';
+var NAV_PREF_TREE = "tree";
+var NAV_PREF_PANELS = "panels";
+var nav_pref;
+var toRoot;
+var isMobile = false; // true if mobile, so we can adjust some layout
+var isIE6 = false; // true if IE6
+
+// TODO: use $(document).ready instead
+function addLoadEvent(newfun) {
+  var current = window.onload;
+  if (typeof window.onload != 'function') {
+    window.onload = newfun;
+  } else {
+    window.onload = function() {
+      current();
+      newfun();
+    }
+  }
+}
+
+var agent = navigator['userAgent'].toLowerCase();
+// If a mobile phone, set flag and do mobile setup
+if ((agent.indexOf("mobile") != -1) ||      // android, iphone, ipod
+    (agent.indexOf("blackberry") != -1) ||
+    (agent.indexOf("webos") != -1) ||
+    (agent.indexOf("mini") != -1)) {        // opera mini browsers
+  isMobile = true;
+  addLoadEvent(mobileSetup);
+// If not a mobile browser, set the onresize event for IE6, and others
+} else if (agent.indexOf("msie 6") != -1) {
+  isIE6 = true;
+  addLoadEvent(function() {
+    window.onresize = resizeAll;
+  });
+} else {
+  addLoadEvent(function() {
+    window.onresize = resizeHeight;
+  });
+}
+
+function mobileSetup() {
+  $("body").css({'overflow':'auto'});
+  $("html").css({'overflow':'auto'});
+  $("#body-content").css({'position':'relative', 'top':'0'});
+  $("#doc-content").css({'overflow':'visible', 'border-left':'3px solid #DDD'});
+  $("#side-nav").css({'padding':'0'});
+  $("#nav-tree").css({'overflow-y': 'auto'});
+}
+
+/* loads the lists.js file to the page.
+Loading this in the head was slowing page load time */
+addLoadEvent( function() {
+  var lists = document.createElement("script");
+  lists.setAttribute("type","text/javascript");
+  lists.setAttribute("src", toRoot+"reference/lists.js");
+  document.getElementsByTagName("head")[0].appendChild(lists);
+} );
+
+addLoadEvent( function() {
+  $("pre:not(.no-pretty-print)").addClass("prettyprint");
+  prettyPrint();
+} );
+
+function setToRoot(root) {
+  toRoot = root;
+  // note: toRoot also used by carousel.js
+}
+
+function restoreWidth(navWidth) {
+  var windowWidth = $(window).width() + "px";
+  content.css({marginLeft:parseInt(navWidth) + 6 + "px"}); //account for 6px-wide handle-bar
+
+  if (isIE6) {
+    content.css({width:parseInt(windowWidth) - parseInt(navWidth) - 6 + "px"}); // necessary in order for scrollbars to be visible
+  }
+
+  sidenav.css({width:navWidth});
+  resizePackagesNav.css({width:navWidth});
+  classesNav.css({width:navWidth});
+  $("#packages-nav").css({width:navWidth});
+}
+
+function restoreHeight(packageHeight) {
+  var windowHeight = ($(window).height() - HEADER_HEIGHT);
+  var swapperHeight = windowHeight - 13;
+  $("#swapper").css({height:swapperHeight + "px"});
+  sidenav.css({height:windowHeight + "px"});
+  content.css({height:windowHeight + "px"});
+  resizePackagesNav.css({maxHeight:swapperHeight + "px", height:packageHeight});
+  classesNav.css({height:swapperHeight - parseInt(packageHeight) + "px"});
+  $("#packages-nav").css({height:parseInt(packageHeight) - 6 + "px"}); //move 6px to give space for the resize handle
+  devdocNav.css({height:sidenav.css("height")});
+  $("#nav-tree").css({height:swapperHeight + "px"});
+}
+
+function readCookie(cookie) {
+  var myCookie = cookie_namespace+"_"+cookie+"=";
+  if (document.cookie) {
+    var index = document.cookie.indexOf(myCookie);
+    if (index != -1) {
+      var valStart = index + myCookie.length;
+      var valEnd = document.cookie.indexOf(";", valStart);
+      if (valEnd == -1) {
+        valEnd = document.cookie.length;
+      }
+      var val = document.cookie.substring(valStart, valEnd);
+      return val;
+    }
+  }
+  return 0;
+}
+
+function writeCookie(cookie, val, section, expiration) {
+  if (val==undefined) return;
+  section = section == null ? "_" : "_"+section+"_";
+  if (expiration == null) {
+    var date = new Date();
+    date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week
+    expiration = date.toGMTString();
+  }
+  document.cookie = cookie_namespace + section + cookie + "=" + val + "; expires=" + expiration+"; path=/";
+}
+
+function getSection() {
+  if (location.href.indexOf("/reference/") != -1) {
+    return "reference";
+  } else if (location.href.indexOf("/guide/") != -1) {
+    return "guide";
+  } else if (location.href.indexOf("/resources/") != -1) {
+    return "resources";
+  }
+  var basePath = getBaseUri(location.pathname);
+  return basePath.substring(1,basePath.indexOf("/",1));
+}
+
+function init() {
+  HEADER_HEIGHT = $("#header").height()+3;
+  $("#side-nav").css({position:"absolute",left:0});
+  content = $("#doc-content");
+  resizePackagesNav = $("#resize-packages-nav");
+  classesNav = $("#classes-nav");
+  sidenav = $("#side-nav");
+  devdocNav = $("#devdoc-nav");
+
+  var cookiePath = getSection() + "_";
+  
+  if (!isMobile) {
+    $("#resize-packages-nav").resizable({handles: "s", resize: function(e, ui) { resizePackagesHeight(); } });
+    $(".side-nav-resizable").resizable({handles: "e", resize: function(e, ui) { resizeWidth(); } });
+    var cookieWidth = readCookie(cookiePath+'width');
+    var cookieHeight = readCookie(cookiePath+'height');
+    if (cookieWidth) {
+      restoreWidth(cookieWidth);
+    } else if ($(".side-nav-resizable").length) {
+      resizeWidth();
+    }
+    if (cookieHeight) {
+      restoreHeight(cookieHeight);
+    } else {
+      resizeHeight();
+    }
+  }
+
+  if (devdocNav.length) { // only dev guide, resources, and sdk
+    tryPopulateResourcesNav();
+    highlightNav(location.href);
+  }
+}
+
+function tryPopulateResourcesNav() {
+  var sampleList = $('#devdoc-nav-sample-list');
+  var articleList = $('#devdoc-nav-article-list');
+  var tutorialList = $('#devdoc-nav-tutorial-list');
+  var topicList = $('#devdoc-nav-topic-list');
+
+  if (!topicList.length || !ANDROID_TAGS || !ANDROID_RESOURCES)
+    return;
+
+  var topics = [];
+  for (var topic in ANDROID_TAGS['topic']) {
+    topics.push({name:topic,title:ANDROID_TAGS['topic'][topic]});
+  }
+  topics.sort(function(x,y){ return (x.title < y.title) ? -1 : 1; });
+  for (var i = 0; i < topics.length; i++) {
+    topicList.append(
+        $('<li>').append(
+          $('<a>')
+            .attr('href', toRoot + "resources/browser.html?tag=" + topics[i].name)
+            .append($('<span>')
+              .addClass('en')
+              .html(topics[i].title)
+            )
+          )
+        );
+  }
+
+  var _renderResourceList = function(tag, listNode) {
+    var resources = [];
+    var tags;
+    var resource;
+    var i, j;
+    for (i = 0; i < ANDROID_RESOURCES.length; i++) {
+      resource = ANDROID_RESOURCES[i];
+      tags = resource.tags || [];
+      var hasTag = false;
+      for (j = 0; j < tags.length; j++)
+        if (tags[j] == tag) {
+          hasTag = true;
+          break;
+        }
+      if (!hasTag)
+        continue;
+      resources.push(resource);
+    }
+    //resources.sort(function(x,y){ return (x.title.en < y.title.en) ? -1 : 1; });
+    for (i = 0; i < resources.length; i++) {
+      resource = resources[i];
+      var listItemNode = $('<li>').append(
+          $('<a>')
+            .attr('href', toRoot + "resources/" + resource.path)
+            .append($('<span>')
+              .addClass('en')
+              .html(resource.title.en)
+            )
+          );
+      tags = resource.tags || [];
+      for (j = 0; j < tags.length; j++) {
+        if (tags[j] == 'new') {
+          listItemNode.get(0).innerHTML += '&nbsp;<span class="new">new!</span>';
+          break;
+        }
+      }
+      listNode.append(listItemNode);
+    }
+  };
+
+  _renderResourceList('sample', sampleList);
+  _renderResourceList('article', articleList);
+  _renderResourceList('tutorial', tutorialList);
+}
+
+function highlightNav(fullPageName) {
+  var lastSlashPos = fullPageName.lastIndexOf("/");
+  var firstSlashPos;
+  if (fullPageName.indexOf("/guide/") != -1) {
+      firstSlashPos = fullPageName.indexOf("/guide/");
+    } else if (fullPageName.indexOf("/sdk/") != -1) {
+      firstSlashPos = fullPageName.indexOf("/sdk/");
+    } else {
+      firstSlashPos = fullPageName.indexOf("/resources/");
+    }
+  if (lastSlashPos == (fullPageName.length - 1)) { // if the url ends in slash (add 'index.html')
+    fullPageName = fullPageName + "index.html";
+  }
+  // First check if the exact URL, with query string and all, is in the navigation menu
+  var pathPageName = fullPageName.substr(firstSlashPos);
+  var link = $("#devdoc-nav a[href$='"+ pathPageName+"']");
+  if (link.length == 0) {
+    var htmlPos = fullPageName.lastIndexOf(".html", fullPageName.length);
+    pathPageName = fullPageName.slice(firstSlashPos, htmlPos + 5); // +5 advances past ".html"
+    link = $("#devdoc-nav a[href$='"+ pathPageName+"']");
+    if ((link.length == 0) && ((fullPageName.indexOf("/guide/") != -1) || (fullPageName.indexOf("/resources/") != -1))) {
+      // if there's no match, then let's backstep through the directory until we find an index.html page
+      // that matches our ancestor directories (only for dev guide and resources)
+      lastBackstep = pathPageName.lastIndexOf("/");
+      while (link.length == 0) {
+        backstepDirectory = pathPageName.lastIndexOf("/", lastBackstep);
+        link = $("#devdoc-nav a[href$='"+ pathPageName.slice(0, backstepDirectory + 1)+"index.html']");
+        lastBackstep = pathPageName.lastIndexOf("/", lastBackstep - 1);
+        if (lastBackstep == 0) break;
+      }
+    }
+  }
+
+  // add 'selected' to the <li> or <div> that wraps this <a>
+  link.parent().addClass('selected');
+
+  // if we're in a toggleable root link (<li class=toggle-list><div><a>)
+  if (link.parent().parent().hasClass('toggle-list')) {
+    toggle(link.parent().parent(), false); // open our own list
+    // then also check if we're in a third-level nested list that's toggleable
+    if (link.parent().parent().parent().is(':hidden')) {
+      toggle(link.parent().parent().parent().parent(), false); // open the super parent list
+    }
+  }
+  // if we're in a normal nav link (<li><a>) and the parent <ul> is hidden
+  else if (link.parent().parent().is(':hidden')) {
+    toggle(link.parent().parent().parent(), false); // open the parent list
+    // then also check if the parent list is also nested in a hidden list
+    if (link.parent().parent().parent().parent().is(':hidden')) {
+      toggle(link.parent().parent().parent().parent().parent(), false); // open the super parent list
+    }
+  }
+}
+
+/* Resize the height of the nav panels in the reference,
+ * and save the new size to a cookie */
+function resizePackagesHeight() {
+  var windowHeight = ($(window).height() - HEADER_HEIGHT);
+  var swapperHeight = windowHeight - 13; // move 13px for swapper link at the bottom
+  resizePackagesNav.css({maxHeight:swapperHeight + "px"});
+  classesNav.css({height:swapperHeight - parseInt(resizePackagesNav.css("height")) + "px"});
+
+  $("#swapper").css({height:swapperHeight + "px"});
+  $("#packages-nav").css({height:parseInt(resizePackagesNav.css("height")) - 6 + "px"}); //move 6px for handle
+
+  var section = getSection();
+  writeCookie("height", resizePackagesNav.css("height"), section, null);
+}
+
+/* Resize the height of the side-nav and doc-content divs,
+ * which creates the frame effect */
+function resizeHeight() {
+  var docContent = $("#doc-content");
+
+  // Get the window height and always resize the doc-content and side-nav divs
+  var windowHeight = ($(window).height() - HEADER_HEIGHT);
+  docContent.css({height:windowHeight + "px"});
+  $("#side-nav").css({height:windowHeight + "px"});
+
+  var href = location.href;
+  // If in the reference docs, also resize the "swapper", "classes-nav", and "nav-tree"  divs
+  if (href.indexOf("/reference/") != -1) {
+    var swapperHeight = windowHeight - 13;
+    $("#swapper").css({height:swapperHeight + "px"});
+    $("#classes-nav").css({height:swapperHeight - parseInt(resizePackagesNav.css("height")) + "px"});
+    $("#nav-tree").css({height:swapperHeight + "px"});
+
+  // If in the dev guide docs, also resize the "devdoc-nav" div
+  } else if (href.indexOf("/guide/") != -1) {
+    $("#devdoc-nav").css({height:sidenav.css("height")});
+  } else if (href.indexOf("/resources/") != -1) {
+    $("#devdoc-nav").css({height:sidenav.css("height")});
+  }
+
+  // Hide the "Go to top" link if there's no vertical scroll
+  if ( parseInt($("#jd-content").css("height")) <= parseInt(docContent.css("height")) ) {
+    $("a[href='#top']").css({'display':'none'});
+  } else {
+    $("a[href='#top']").css({'display':'inline'});
+  }
+}
+
+/* Resize the width of the "side-nav" and the left margin of the "doc-content" div,
+ * which creates the resizable side bar */
+function resizeWidth() {
+  var windowWidth = $(window).width() + "px";
+  if (sidenav.length) {
+    var sidenavWidth = sidenav.css("width");
+  } else {
+    var sidenavWidth = 0;
+  }
+  content.css({marginLeft:parseInt(sidenavWidth) + 6 + "px"}); //account for 6px-wide handle-bar
+
+  if (isIE6) {
+    content.css({width:parseInt(windowWidth) - parseInt(sidenavWidth) - 6 + "px"}); // necessary in order to for scrollbars to be visible
+  }
+
+  resizePackagesNav.css({width:sidenavWidth});
+  classesNav.css({width:sidenavWidth});
+  $("#packages-nav").css({width:sidenavWidth});
+
+  if ($(".side-nav-resizable").length) { // Must check if the nav is resizable because IE6 calls resizeWidth() from resizeAll() for all pages
+    var section = getSection();
+    writeCookie("width", sidenavWidth, section, null);
+  }
+}
+
+/* For IE6 only,
+ * because it can't properly perform auto width for "doc-content" div,
+ * avoiding this for all browsers provides better performance */
+function resizeAll() {
+  resizeHeight();
+  resizeWidth();
+}
+
+function getBaseUri(uri) {
+  var intlUrl = (uri.substring(0,6) == "/intl/");
+  if (intlUrl) {
+    base = uri.substring(uri.indexOf('intl/')+5,uri.length);
+    base = base.substring(base.indexOf('/')+1, base.length);
+      //alert("intl, returning base url: /" + base);
+    return ("/" + base);
+  } else {
+      //alert("not intl, returning uri as found.");
+    return uri;
+  }
+}
+
+function requestAppendHL(uri) {
+//append "?hl=<lang> to an outgoing request (such as to blog)
+  var lang = getLangPref();
+  if (lang) {
+    var q = 'hl=' + lang;
+    uri += '?' + q;
+    window.location = uri;
+    return false;
+  } else {
+    return true;
+  }
+}
+
+function loadLast(cookiePath) {
+  var location = window.location.href;
+  if (location.indexOf("/"+cookiePath+"/") != -1) {
+    return true;
+  }
+  var lastPage = readCookie(cookiePath + "_lastpage");
+  if (lastPage) {
+    window.location = lastPage;
+    return false;
+  }
+  return true;
+}
+
+$(window).unload(function(){
+  var path = getBaseUri(location.pathname);
+  if (path.indexOf("/reference/") != -1) {
+    writeCookie("lastpage", path, "reference", null);
+  } else if (path.indexOf("/guide/") != -1) {
+    writeCookie("lastpage", path, "guide", null);
+  } else if (path.indexOf("/resources/") != -1) {
+    writeCookie("lastpage", path, "resources", null);
+  }
+});
+
+function toggle(obj, slide) {
+  var ul = $("ul:first", obj);
+  var li = ul.parent();
+  if (li.hasClass("closed")) {
+    if (slide) {
+      ul.slideDown("fast");
+    } else {
+      ul.show();
+    }
+    li.removeClass("closed");
+    li.addClass("open");
+    $(".toggle-img", li).attr("title", "hide pages");
+  } else {
+    ul.slideUp("fast");
+    li.removeClass("open");
+    li.addClass("closed");
+    $(".toggle-img", li).attr("title", "show pages");
+  }
+}
+
+function buildToggleLists() {
+  $(".toggle-list").each(
+    function(i) {
+      $("div:first", this).append("<a class='toggle-img' href='#' title='show pages' onClick='toggle(this.parentNode.parentNode, true); return false;'></a>");
+      $(this).addClass("closed");
+    });
+}
+
+function getNavPref() {
+  var v = readCookie('reference_nav');
+  if (v != NAV_PREF_TREE) {
+    v = NAV_PREF_PANELS;
+  }
+  return v;
+}
+
+function chooseDefaultNav() {
+  nav_pref = getNavPref();
+  if (nav_pref == NAV_PREF_TREE) {
+    $("#nav-panels").toggle();
+    $("#panel-link").toggle();
+    $("#nav-tree").toggle();
+    $("#tree-link").toggle();
+  }
+}
+
+function swapNav() {
+  if (nav_pref == NAV_PREF_TREE) {
+    nav_pref = NAV_PREF_PANELS;
+  } else {
+    nav_pref = NAV_PREF_TREE;
+    init_default_navtree(toRoot);
+  }
+  var date = new Date();
+  date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
+  writeCookie("nav", nav_pref, "reference", date.toGMTString());
+
+  $("#nav-panels").toggle();
+  $("#panel-link").toggle();
+  $("#nav-tree").toggle();
+  $("#tree-link").toggle();
+
+  if ($("#nav-tree").is(':visible')) scrollIntoView("nav-tree");
+  else {
+    scrollIntoView("packages-nav");
+    scrollIntoView("classes-nav");
+  }
+}
+
+function scrollIntoView(nav) {
+  var navObj = $("#"+nav);
+  if (navObj.is(':visible')) {
+    var selected = $(".selected", navObj);
+    if (selected.length == 0) return;
+    if (selected.is("div")) selected = selected.parent();
+
+    var scrolling = document.getElementById(nav);
+    var navHeight = navObj.height();
+    var offsetTop = selected.position().top;
+    if (selected.parent().parent().is(".toggle-list")) offsetTop += selected.parent().parent().position().top;
+    if(offsetTop > navHeight - 92) {
+      scrolling.scrollTop = offsetTop - navHeight + 92;
+    }
+  }
+}
+
+function changeTabLang(lang) {
+  var nodes = $("#header-tabs").find("."+lang);
+  for (i=0; i < nodes.length; i++) { // for each node in this language
+    var node = $(nodes[i]);
+    node.siblings().css("display","none"); // hide all siblings
+    if (node.not(":empty").length != 0) { //if this languages node has a translation, show it
+      node.css("display","inline");
+    } else { //otherwise, show English instead
+      node.css("display","none");
+      node.siblings().filter(".en").css("display","inline");
+    }
+  }
+}
+
+function changeNavLang(lang) {
+  var nodes = $("#side-nav").find("."+lang);
+  for (i=0; i < nodes.length; i++) { // for each node in this language
+    var node = $(nodes[i]);
+    node.siblings().css("display","none"); // hide all siblings
+    if (node.not(":empty").length != 0) { // if this languages node has a translation, show it
+      node.css("display","inline");
+    } else { // otherwise, show English instead
+      node.css("display","none");
+      node.siblings().filter(".en").css("display","inline");
+    }
+  }
+}
+
+function changeDocLang(lang) {
+  changeTabLang(lang);
+  changeNavLang(lang);
+}
+
+function changeLangPref(lang, refresh) {
+  var date = new Date();
+  expires = date.toGMTString(date.setTime(date.getTime()+(10*365*24*60*60*1000))); // keep this for 50 years
+  //alert("expires: " + expires)
+  writeCookie("pref_lang", lang, null, expires);
+  //changeDocLang(lang);
+  if (refresh) {
+    l = getBaseUri(location.pathname);
+    window.location = l;
+  }
+}
+
+function loadLangPref() {
+  var lang = readCookie("pref_lang");
+  if (lang != 0) {
+    $("#language").find("option[value='"+lang+"']").attr("selected",true);
+  }
+}
+
+function getLangPref() {
+  var lang = $("#language").find(":selected").attr("value");
+  if (!lang) {
+    lang = readCookie("pref_lang");
+  }
+  return (lang != 0) ? lang : 'en';
+}
+
+
+function toggleContent(obj) {
+  var button = $(obj);
+  var div = $(obj.parentNode);
+  var toggleMe = $(".toggle-content-toggleme",div);
+  if (button.hasClass("show")) {
+    toggleMe.slideDown();
+    button.removeClass("show").addClass("hide");
+  } else {
+    toggleMe.slideUp();
+    button.removeClass("hide").addClass("show");
+  }
+  $("span", button).toggle();
+}
diff --git a/res/assets/templates/assets/android-developer-reference.js b/res/assets/templates/assets/android-developer-reference.js
new file mode 100644
index 0000000..f945d6a
--- /dev/null
+++ b/res/assets/templates/assets/android-developer-reference.js
@@ -0,0 +1,392 @@
+
+/* API LEVEL TOGGLE */
+<?cs if:reference.apilevels ?>
+addLoadEvent(changeApiLevel);
+<?cs /if ?>
+
+var API_LEVEL_ENABLED_COOKIE = "api_level_enabled";
+var API_LEVEL_COOKIE = "api_level";
+var minLevel = 1;
+
+function toggleApiLevelSelector(checkbox) {
+  var date = new Date();
+  date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
+  var expiration = date.toGMTString();
+  if (checkbox.checked) {
+    $("#apiLevelSelector").removeAttr("disabled");
+    $("#api-level-toggle label").removeClass("disabled");
+    writeCookie(API_LEVEL_ENABLED_COOKIE, 1, null, expiration);
+  } else {
+    $("#apiLevelSelector").attr("disabled","disabled");
+    $("#api-level-toggle label").addClass("disabled");
+    writeCookie(API_LEVEL_ENABLED_COOKIE, 0, null, expiration);
+  }
+  changeApiLevel();
+}
+
+function buildApiLevelSelector() {
+  var maxLevel = SINCE_DATA.length;
+  var userApiLevelEnabled = readCookie(API_LEVEL_ENABLED_COOKIE);
+  var userApiLevel = readCookie(API_LEVEL_COOKIE);
+  userApiLevel = userApiLevel == 0 ? maxLevel : userApiLevel; // If there's no cookie (zero), use the max by default
+
+  if (userApiLevelEnabled == 0) {
+    $("#apiLevelSelector").attr("disabled","disabled");
+  } else {
+    $("#apiLevelCheckbox").attr("checked","checked");
+    $("#api-level-toggle label").removeClass("disabled");
+  }
+  
+  minLevel = $("body").attr("class");
+  var select = $("#apiLevelSelector").html("").change(changeApiLevel);
+  for (var i = maxLevel-1; i >= 0; i--) {
+    var option = $("<option />").attr("value",""+SINCE_DATA[i]).append(""+SINCE_DATA[i]);
+  //  if (SINCE_DATA[i] < minLevel) option.addClass("absent"); // always false for strings (codenames)
+    select.append(option);
+  }
+  
+  // get the DOM element and use setAttribute cuz IE6 fails when using jquery .attr('selected',true)
+  var selectedLevelItem = $("#apiLevelSelector option[value='"+userApiLevel+"']").get(0);
+  selectedLevelItem.setAttribute('selected',true);
+}
+
+function changeApiLevel() {
+  var maxLevel = SINCE_DATA.length;
+  var userApiLevelEnabled = readCookie(API_LEVEL_ENABLED_COOKIE);
+  var selectedLevel = maxLevel;
+  
+  if (userApiLevelEnabled == 0) {
+    toggleVisisbleApis(selectedLevel, "body");
+  } else {
+    selectedLevel = $("#apiLevelSelector option:selected").val();
+    toggleVisisbleApis(selectedLevel, "body");
+    
+    var date = new Date();
+    date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
+    var expiration = date.toGMTString();
+    writeCookie(API_LEVEL_COOKIE, selectedLevel, null, expiration);
+  }
+  
+  if (selectedLevel < minLevel) {
+    var thing = ($("#jd-header").html().indexOf("package") != -1) ? "package" : "class";
+    $("#naMessage").show().html("<div><p><strong>This " + thing + " is not available with API Level " + selectedLevel + ".</strong></p>"
+                              + "<p>To use this " + thing + ", your application must specify API Level " + minLevel + " or higher in its manifest "
+                              + "and be compiled against a version of the Android library that supports an equal or higher API Level. To reveal this "
+                              + "document, change the value of the API Level filter above.</p>"
+                              + "<p><a href='" +toRoot+ "guide/appendix/api-levels.html'>What is the API Level?</a></p></div>");
+  } else {
+    $("#naMessage").hide();
+  }
+}
+
+function toggleVisisbleApis(selectedLevel, context) {
+  var apis = $(".api",context);
+  apis.each(function(i) {
+    var obj = $(this);
+    var className = obj.attr("class");
+    var apiLevelIndex = className.lastIndexOf("-")+1;
+    var apiLevelEndIndex = className.indexOf(" ", apiLevelIndex);
+    apiLevelEndIndex = apiLevelEndIndex != -1 ? apiLevelEndIndex : className.length;
+    var apiLevel = className.substring(apiLevelIndex, apiLevelEndIndex);
+    if (apiLevel > selectedLevel) obj.addClass("absent").attr("title","Requires API Level "+apiLevel+" or higher");
+    else obj.removeClass("absent").removeAttr("title");
+  });
+}
+
+/* NAVTREE */
+
+function new_node(me, mom, text, link, children_data, api_level)
+{
+  var node = new Object();
+  node.children = Array();
+  node.children_data = children_data;
+  node.depth = mom.depth + 1;
+
+  node.li = document.createElement("li");
+  mom.get_children_ul().appendChild(node.li);
+
+  node.label_div = document.createElement("div");
+  node.label_div.className = "label";
+  if (api_level != null) {
+    $(node.label_div).addClass("api");
+    $(node.label_div).addClass("api-level-"+api_level);
+  }
+  node.li.appendChild(node.label_div);
+  node.label_div.style.paddingLeft = 10*node.depth + "px";
+
+  if (children_data == null) {
+    // 12 is the width of the triangle and padding extra space
+    node.label_div.style.paddingLeft = ((10*node.depth)+12) + "px";
+  } else {
+    node.label_div.style.paddingLeft = 10*node.depth + "px";
+    node.expand_toggle = document.createElement("a");
+    node.expand_toggle.href = "javascript:void(0)";
+    node.expand_toggle.onclick = function() {
+          if (node.expanded) {
+            $(node.get_children_ul()).slideUp("fast");
+            node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png";
+            node.expanded = false;
+          } else {
+            expand_node(me, node);
+          }
+       };
+    node.label_div.appendChild(node.expand_toggle);
+
+    node.plus_img = document.createElement("img");
+    node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png";
+    node.plus_img.className = "plus";
+    node.plus_img.border = "0";
+    node.expand_toggle.appendChild(node.plus_img);
+
+    node.expanded = false;
+  }
+
+  var a = document.createElement("a");
+  node.label_div.appendChild(a);
+  node.label = document.createTextNode(text);
+  a.appendChild(node.label);
+  if (link) {
+    a.href = me.toroot + link;
+  } else {
+    if (children_data != null) {
+      a.className = "nolink";
+      a.href = "javascript:void(0)";
+      a.onclick = node.expand_toggle.onclick;
+      // This next line shouldn't be necessary.  I'll buy a beer for the first
+      // person who figures out how to remove this line and have the link
+      // toggle shut on the first try. --joeo@android.com
+      node.expanded = false;
+    }
+  }
+  
+
+  node.children_ul = null;
+  node.get_children_ul = function() {
+      if (!node.children_ul) {
+        node.children_ul = document.createElement("ul");
+        node.children_ul.className = "children_ul";
+        node.children_ul.style.display = "none";
+        node.li.appendChild(node.children_ul);
+      }
+      return node.children_ul;
+    };
+
+  return node;
+}
+
+function expand_node(me, node)
+{
+  if (node.children_data && !node.expanded) {
+    if (node.children_visited) {
+      $(node.get_children_ul()).slideDown("fast");
+    } else {
+      get_node(me, node);
+      if ($(node.label_div).hasClass("absent")) $(node.get_children_ul()).addClass("absent");
+      $(node.get_children_ul()).slideDown("fast");
+    }
+    node.plus_img.src = me.toroot + "assets/images/triangle-opened-small.png";
+    node.expanded = true;
+    
+    // perform api level toggling because new nodes are new to the DOM
+    var selectedLevel = $("#apiLevelSelector option:selected").val();
+    toggleVisisbleApis(selectedLevel, "#side-nav");
+  }
+}
+
+function get_node(me, mom)
+{
+  mom.children_visited = true;
+  for (var i in mom.children_data) {
+    var node_data = mom.children_data[i];
+    mom.children[i] = new_node(me, mom, node_data[0], node_data[1],
+        node_data[2], node_data[3]);
+  }
+}
+
+function this_page_relative(toroot)
+{
+  var full = document.location.pathname;
+  var file = "";
+  if (toroot.substr(0, 1) == "/") {
+    if (full.substr(0, toroot.length) == toroot) {
+      return full.substr(toroot.length);
+    } else {
+      // the file isn't under toroot.  Fail.
+      return null;
+    }
+  } else {
+    if (toroot != "./") {
+      toroot = "./" + toroot;
+    }
+    do {
+      if (toroot.substr(toroot.length-3, 3) == "../" || toroot == "./") {
+        var pos = full.lastIndexOf("/");
+        file = full.substr(pos) + file;
+        full = full.substr(0, pos);
+        toroot = toroot.substr(0, toroot.length-3);
+      }
+    } while (toroot != "" && toroot != "/");
+    return file.substr(1);
+  }
+}
+
+function find_page(url, data)
+{
+  var nodes = data;
+  var result = null;
+  for (var i in nodes) {
+    var d = nodes[i];
+    if (d[1] == url) {
+      return new Array(i);
+    }
+    else if (d[2] != null) {
+      result = find_page(url, d[2]);
+      if (result != null) {
+        return (new Array(i).concat(result));
+      }
+    }
+  }
+  return null;
+}
+
+function load_navtree_data(toroot) {
+  var navtreeData = document.createElement("script");
+  navtreeData.setAttribute("type","text/javascript");
+  navtreeData.setAttribute("src", toroot+"navtree_data.js");
+  $("head").append($(navtreeData));
+}
+
+function init_default_navtree(toroot) {
+  init_navtree("nav-tree", toroot, NAVTREE_DATA);
+  
+  // perform api level toggling because because the whole tree is new to the DOM
+  var selectedLevel = $("#apiLevelSelector option:selected").val();
+  toggleVisisbleApis(selectedLevel, "#side-nav");
+}
+
+function init_navtree(navtree_id, toroot, root_nodes)
+{
+  var me = new Object();
+  me.toroot = toroot;
+  me.node = new Object();
+
+  me.node.li = document.getElementById(navtree_id);
+  me.node.children_data = root_nodes;
+  me.node.children = new Array();
+  me.node.children_ul = document.createElement("ul");
+  me.node.get_children_ul = function() { return me.node.children_ul; };
+  //me.node.children_ul.className = "children_ul";
+  me.node.li.appendChild(me.node.children_ul);
+  me.node.depth = 0;
+
+  get_node(me, me.node);
+
+  me.this_page = this_page_relative(toroot);
+  me.breadcrumbs = find_page(me.this_page, root_nodes);
+  if (me.breadcrumbs != null && me.breadcrumbs.length != 0) {
+    var mom = me.node;
+    for (var i in me.breadcrumbs) {
+      var j = me.breadcrumbs[i];
+      mom = mom.children[j];
+      expand_node(me, mom);
+    }
+    mom.label_div.className = mom.label_div.className + " selected";
+    addLoadEvent(function() {
+      scrollIntoView("nav-tree");
+      });
+  }
+}
+
+/* TOGGLE INHERITED MEMBERS */
+
+/* Toggle an inherited class (arrow toggle)
+ * @param linkObj  The link that was clicked.
+ * @param expand  'true' to ensure it's expanded. 'false' to ensure it's closed.
+ *                'null' to simply toggle.
+ */
+function toggleInherited(linkObj, expand) {
+    var base = linkObj.getAttribute("id");
+    var list = document.getElementById(base + "-list");
+    var summary = document.getElementById(base + "-summary");
+    var trigger = document.getElementById(base + "-trigger");
+    var a = $(linkObj);
+    if ( (expand == null && a.hasClass("closed")) || expand ) {
+        list.style.display = "none";
+        summary.style.display = "block";
+        trigger.src = toRoot + "assets/images/triangle-opened.png";
+        a.removeClass("closed");
+        a.addClass("opened");
+    } else if ( (expand == null && a.hasClass("opened")) || (expand == false) ) {
+        list.style.display = "block";
+        summary.style.display = "none";
+        trigger.src = toRoot + "assets/images/triangle-closed.png";
+        a.removeClass("opened");
+        a.addClass("closed");
+    }
+    return false;
+}
+
+/* Toggle all inherited classes in a single table (e.g. all inherited methods)
+ * @param linkObj  The link that was clicked.
+ * @param expand  'true' to ensure it's expanded. 'false' to ensure it's closed.
+ *                'null' to simply toggle.
+ */
+function toggleAllInherited(linkObj, expand) {
+  var a = $(linkObj);
+  var table = $(a.parent().parent().parent()); // ugly way to get table/tbody
+  var expandos = $(".jd-expando-trigger", table);
+  if ( (expand == null && a.text() == "[Expand]") || expand ) {
+    expandos.each(function(i) {
+      toggleInherited(this, true);
+    });
+    a.text("[Collapse]");
+  } else if ( (expand == null && a.text() == "[Collapse]") || (expand == false) ) {
+    expandos.each(function(i) {
+      toggleInherited(this, false);
+    });
+    a.text("[Expand]");
+  }
+  return false;
+}
+
+/* Toggle all inherited members in the class (link in the class title)
+ */
+function toggleAllClassInherited() {
+  var a = $("#toggleAllClassInherited"); // get toggle link from class title
+  var toggles = $(".toggle-all", $("#doc-content"));
+  if (a.text() == "[Expand All]") {
+    toggles.each(function(i) {
+      toggleAllInherited(this, true);
+    });
+    a.text("[Collapse All]");
+  } else {
+    toggles.each(function(i) {
+      toggleAllInherited(this, false);
+    });
+    a.text("[Expand All]");
+  }
+  return false;
+}
+
+/* Expand all inherited members in the class. Used when initiating page search */
+function ensureAllInheritedExpanded() {
+  var toggles = $(".toggle-all", $("#doc-content"));
+  toggles.each(function(i) {
+    toggleAllInherited(this, true);
+  });
+  $("#toggleAllClassInherited").text("[Collapse All]");
+}
+
+
+/* HANDLE KEY EVENTS
+ * - Listen for Ctrl+F (Cmd on Mac) and expand all inherited members (to aid page search)
+ */
+var agent = navigator['userAgent'].toLowerCase();
+var mac = agent.indexOf("macintosh") != -1;
+
+$(document).keydown( function(e) {
+var control = mac ? e.metaKey && !e.ctrlKey : e.ctrlKey; // get ctrl key
+  if (control && e.which == 70) {  // 70 is "F"
+    ensureAllInheritedExpanded();
+  }
+});
\ No newline at end of file
diff --git a/res/assets/templates/assets/images/bg_fade.jpg b/res/assets/templates/assets/images/bg_fade.jpg
new file mode 100755
index 0000000..c6c70b6
--- /dev/null
+++ b/res/assets/templates/assets/images/bg_fade.jpg
Binary files differ
diff --git a/res/assets/templates/assets/images/bg_logo.png b/res/assets/templates/assets/images/bg_logo.png
new file mode 100755
index 0000000..8c57fc4
--- /dev/null
+++ b/res/assets/templates/assets/images/bg_logo.png
Binary files differ
diff --git a/res/assets/templates/assets/images/body-gradient-tab.png b/res/assets/templates/assets/images/body-gradient-tab.png
new file mode 100644
index 0000000..5223ac3
--- /dev/null
+++ b/res/assets/templates/assets/images/body-gradient-tab.png
Binary files differ
diff --git a/res/assets/templates/assets/images/body-gradient.png b/res/assets/templates/assets/images/body-gradient.png
new file mode 100755
index 0000000..9d59855
--- /dev/null
+++ b/res/assets/templates/assets/images/body-gradient.png
Binary files differ
diff --git a/res/assets/templates/assets/images/grad-rule-qv.png b/res/assets/templates/assets/images/grad-rule-qv.png
new file mode 100644
index 0000000..bae2d18
--- /dev/null
+++ b/res/assets/templates/assets/images/grad-rule-qv.png
Binary files differ
diff --git a/res/assets/templates/assets/images/hr_gray_main.jpg b/res/assets/templates/assets/images/hr_gray_main.jpg
new file mode 100755
index 0000000..f7a0a2f
--- /dev/null
+++ b/res/assets/templates/assets/images/hr_gray_main.jpg
Binary files differ
diff --git a/res/assets/templates/assets/images/hr_gray_side.jpg b/res/assets/templates/assets/images/hr_gray_side.jpg
new file mode 100755
index 0000000..6667476
--- /dev/null
+++ b/res/assets/templates/assets/images/hr_gray_side.jpg
Binary files differ
diff --git a/res/assets/templates/assets/images/left_off.jpg b/res/assets/templates/assets/images/left_off.jpg
new file mode 100755
index 0000000..fd32a64
--- /dev/null
+++ b/res/assets/templates/assets/images/left_off.jpg
Binary files differ
diff --git a/res/assets/templates/assets/images/left_on.jpg b/res/assets/templates/assets/images/left_on.jpg
new file mode 100755
index 0000000..143184b
--- /dev/null
+++ b/res/assets/templates/assets/images/left_on.jpg
Binary files differ
diff --git a/res/assets/templates/assets/images/preliminary.png b/res/assets/templates/assets/images/preliminary.png
new file mode 100644
index 0000000..fe0da3d
--- /dev/null
+++ b/res/assets/templates/assets/images/preliminary.png
Binary files differ
diff --git a/res/assets/templates/assets/images/resizable-e.gif b/res/assets/templates/assets/images/resizable-e.gif
new file mode 100755
index 0000000..f748097
--- /dev/null
+++ b/res/assets/templates/assets/images/resizable-e.gif
Binary files differ
diff --git a/res/assets/templates/assets/images/resizable-e2.gif b/res/assets/templates/assets/images/resizable-e2.gif
new file mode 100755
index 0000000..e45d0c5
--- /dev/null
+++ b/res/assets/templates/assets/images/resizable-e2.gif
Binary files differ
diff --git a/res/assets/templates/assets/images/resizable-eg.gif b/res/assets/templates/assets/images/resizable-eg.gif
new file mode 100755
index 0000000..6196616
--- /dev/null
+++ b/res/assets/templates/assets/images/resizable-eg.gif
Binary files differ
diff --git a/res/assets/templates/assets/images/resizable-s.gif b/res/assets/templates/assets/images/resizable-s.gif
new file mode 100755
index 0000000..7f6a4eb
--- /dev/null
+++ b/res/assets/templates/assets/images/resizable-s.gif
Binary files differ
diff --git a/res/assets/templates/assets/images/resizable-s2.gif b/res/assets/templates/assets/images/resizable-s2.gif
new file mode 100755
index 0000000..99e869c
--- /dev/null
+++ b/res/assets/templates/assets/images/resizable-s2.gif
Binary files differ
diff --git a/res/assets/templates/assets/images/resizable-sg.gif b/res/assets/templates/assets/images/resizable-sg.gif
new file mode 100755
index 0000000..b4bea10
--- /dev/null
+++ b/res/assets/templates/assets/images/resizable-sg.gif
Binary files differ
diff --git a/res/assets/templates/assets/images/right_off.jpg b/res/assets/templates/assets/images/right_off.jpg
new file mode 100755
index 0000000..17d2efe
--- /dev/null
+++ b/res/assets/templates/assets/images/right_off.jpg
Binary files differ
diff --git a/res/assets/templates/assets/images/right_on.jpg b/res/assets/templates/assets/images/right_on.jpg
new file mode 100755
index 0000000..baa2af1
--- /dev/null
+++ b/res/assets/templates/assets/images/right_on.jpg
Binary files differ
diff --git a/res/assets/templates/assets/images/sidenav-rule.png b/res/assets/templates/assets/images/sidenav-rule.png
new file mode 100644
index 0000000..eab9920
--- /dev/null
+++ b/res/assets/templates/assets/images/sidenav-rule.png
Binary files differ
diff --git a/res/assets/templates/assets/images/spacer.gif b/res/assets/templates/assets/images/spacer.gif
new file mode 100755
index 0000000..f96b355
--- /dev/null
+++ b/res/assets/templates/assets/images/spacer.gif
Binary files differ
diff --git a/res/assets/templates/assets/images/triangle-closed-small.png b/res/assets/templates/assets/images/triangle-closed-small.png
new file mode 100644
index 0000000..002364a
--- /dev/null
+++ b/res/assets/templates/assets/images/triangle-closed-small.png
Binary files differ
diff --git a/res/assets/templates/assets/images/triangle-closed.png b/res/assets/templates/assets/images/triangle-closed.png
new file mode 100644
index 0000000..a34a055
--- /dev/null
+++ b/res/assets/templates/assets/images/triangle-closed.png
Binary files differ
diff --git a/res/assets/templates/assets/images/triangle-opened-small.png b/res/assets/templates/assets/images/triangle-opened-small.png
new file mode 100644
index 0000000..e1eb784
--- /dev/null
+++ b/res/assets/templates/assets/images/triangle-opened-small.png
Binary files differ
diff --git a/res/assets/templates/assets/images/triangle-opened.png b/res/assets/templates/assets/images/triangle-opened.png
new file mode 100644
index 0000000..a709604
--- /dev/null
+++ b/res/assets/templates/assets/images/triangle-opened.png
Binary files differ
diff --git a/res/assets/templates/assets/jquery-history.js b/res/assets/templates/assets/jquery-history.js
new file mode 100644
index 0000000..ef96ec3
--- /dev/null
+++ b/res/assets/templates/assets/jquery-history.js
@@ -0,0 +1,78 @@
+/**
+ * jQuery history event v0.1
+ * Copyright (c) 2008 Tom Rodenberg <tarodenberg gmail com>
+ * Licensed under the GPL (http://www.gnu.org/licenses/gpl.html) license.
+ */
+(function($) {
+    var currentHash, previousNav, timer, hashTrim = /^.*#/;
+
+    var msie = {
+        iframe: null,
+        getDoc: function() {
+            return msie.iframe.contentWindow.document;
+        },
+        getHash: function() {
+            return msie.getDoc().location.hash;
+        },
+        setHash: function(hash) {
+            var d = msie.getDoc();
+            d.open();
+            d.close();
+            d.location.hash = hash;
+        }
+    };
+
+    var historycheck = function() {
+        var hash = msie.iframe ? msie.getHash() : location.hash;
+        if (hash != currentHash) {
+            currentHash = hash;
+            if (msie.iframe) {
+                location.hash = currentHash;
+            }
+            var current = $.history.getCurrent();
+            $.event.trigger('history', [current, previousNav]);
+            previousNav = current;
+        }
+    };
+
+    $.history = {
+        add: function(hash) {
+            hash = '#' + hash.replace(hashTrim, '');
+            if (currentHash != hash) {
+                var previous = $.history.getCurrent();
+                location.hash = currentHash = hash;
+                if (msie.iframe) {
+                    msie.setHash(currentHash);
+                }
+                $.event.trigger('historyadd', [$.history.getCurrent(), previous]);
+            }
+            if (!timer) {
+                timer = setInterval(historycheck, 100);
+            }
+        },
+        getCurrent: function() {
+            if (currentHash) {
+              return currentHash.replace(hashTrim, '');
+            } else { 
+              return ""; 
+            }
+        }
+    };
+
+    $.fn.history = function(fn) {
+        $(this).bind('history', fn);
+    };
+
+    $.fn.historyadd = function(fn) {
+        $(this).bind('historyadd', fn);
+    };
+
+    $(function() {
+        currentHash = location.hash;
+        if ($.browser.msie) {
+            msie.iframe = $('<iframe style="display:none" src="javascript:false;"></iframe>').prependTo('body')[0];
+            msie.setHash(currentHash);
+            currentHash = msie.getHash();
+        }
+    });
+})(jQuery);
diff --git a/res/assets/templates/assets/jquery-resizable.min.js b/res/assets/templates/assets/jquery-resizable.min.js
new file mode 100755
index 0000000..67186fe
--- /dev/null
+++ b/res/assets/templates/assets/jquery-resizable.min.js
@@ -0,0 +1,40 @@
+/*
+ * jQuery JavaScript Library v1.3.2
+ * http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ *
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
+ * Revision: 6246
+ */
+(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){var I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}});
+/*
+ * Sizzle CSS Selector Engine - v0.9.3
+ *  Copyright 2009, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML='   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();
+/*
+ * jQuery UI 1.7.2
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI
+ */
+jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.7.2",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m<n.length;m++){if(j.options[n[m][0]]){n[m][1].apply(j.element,k)}}}},contains:function(k,j){return document.compareDocumentPosition?k.compareDocumentPosition(j)&16:k!==j&&k.contains(j)},hasScroll:function(m,k){if(c(m).css("overflow")=="hidden"){return false}var j=(k&&k=="left")?"scrollLeft":"scrollTop",l=false;if(m[j]>0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")});return i.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function(k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);;/* * jQuery UI Resizable 1.7.2
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Resizables
+ *
+ * Depends:
+ *	ui.core.js
+ */
+(function(c){c.widget("ui.resizable",c.extend({},c.ui.mouse,{_init:function(){var e=this,j=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(j.aspectRatio),aspectRatio:j.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:j.helper||j.ghost||j.animate?j.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){if(/relative/.test(this.element.css("position"))&&c.browser.opera){this.element.css({position:"relative",top:"auto",left:"auto"})}this.element.wrap(c('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f<k.length;f++){var h=c.trim(k[f]),d="ui-resizable-"+h;var g=c('<div class="ui-resizable-handle '+d+'"></div>');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.parent().append(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).end().remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement)},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return this.options.disabled||!!f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidth<k.width),l=a(k.height)&&h.maxHeight&&(h.maxHeight<k.height),g=a(k.width)&&h.minWidth&&(h.minWidth>k.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e<this._proportionallyResizeElements.length;e++){var g=this._proportionallyResizeElements[e];if(!this.borderDif){var d=[g.css("borderTopWidth"),g.css("borderRightWidth"),g.css("borderBottomWidth"),g.css("borderLeftWidth")],h=[g.css("paddingTop"),g.css("paddingRight"),g.css("paddingBottom"),g.css("paddingLeft")];this.borderDif=c.map(d,function(k,m){var l=parseInt(k,10)||0,n=parseInt(h[m],10)||0;return l+n})}if(c.browser.msie&&!(!(c(f).is(":hidden")||c(f).parents(":hidden").length))){continue}g.css({height:(f.height()-this.borderDif[0]-this.borderDif[2])||0,width:(f.width()-this.borderDif[1]-this.borderDif[3])||0})}},_renderProxy:function(){var e=this.element,h=this.options;this.elementOffset=e.offset();if(this._helper){this.helper=this.helper||c('<div style="overflow:hidden;"></div>');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));c.extend(c.ui.resizable,{version:"1.7.2",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),g=d.options;_store=function(h){c(h).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(g.alsoResize)=="object"&&!g.alsoResize.parentNode){if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];_store(g.alsoResize)}else{c.each(g.alsoResize,function(h,i){_store(h)})}}else{_store(g.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0)){s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);;
diff --git a/res/assets/templates/assets/microtemplate.js b/res/assets/templates/assets/microtemplate.js
new file mode 100644
index 0000000..ada1235
--- /dev/null
+++ b/res/assets/templates/assets/microtemplate.js
@@ -0,0 +1,35 @@
+// Simple JavaScript Templating
+// John Resig - http://ejohn.org/ - MIT Licensed
+(function(){
+  var cache = {};
+
+  this.tmpl = function tmpl(str, data){
+    // Figure out if we're getting a template, or if we need to
+    // load the template - and be sure to cache the result.
+    var fn = !/\W/.test(str) ?
+      cache[str] = cache[str] ||
+        tmpl(document.getElementById(str).innerHTML) :
+
+      // Generate a reusable function that will serve as a template
+      // generator (and which will be cached).
+      new Function("obj",
+        "var p=[],print=function(){p.push.apply(p,arguments);};" +
+
+        // Introduce the data as local variables using with(){}
+        "with(obj){p.push('" +
+
+        // Convert the template into pure JavaScript
+        str
+          .replace(/[\r\t\n]/g, " ")
+          .split("<%").join("\t")
+          .replace(/((^|%>)[^\t]*)'/g, "$1\r")
+          .replace(/\t=(.*?)%>/g, "',$1,'")
+          .split("\t").join("');")
+          .split("%>").join("p.push('")
+          .split("\r").join("\\'")
+      + "');}return p.join('');");
+
+    // Provide some basic currying to the user
+    return data ? fn( data ) : fn;
+  };
+})();
\ No newline at end of file
diff --git a/res/assets/templates/assets/prettify.js b/res/assets/templates/assets/prettify.js
new file mode 100644
index 0000000..076f9d0
--- /dev/null
+++ b/res/assets/templates/assets/prettify.js
@@ -0,0 +1,33 @@
+(function(){
+var o=true,r=null,z=false;window.PR_SHOULD_USE_CONTINUATION=o;window.PR_TAB_WIDTH=8;window.PR_normalizedHtml=window.PR=window.prettyPrintOne=window.prettyPrint=void 0;window._pr_isIE6=function(){var N=navigator&&navigator.userAgent&&/\bMSIE 6\./.test(navigator.userAgent);window._pr_isIE6=function(){return N};return N};
+var aa="!",ba="!=",ca="!==",F="#",da="%",ea="%=",G="&",fa="&&",ja="&&=",ka="&=",H="(",la="*",ma="*=",na="+=",oa=",",pa="-=",qa="->",ra="/",sa="/=",ta=":",ua="::",va=";",I="<",wa="<<",xa="<<=",ya="<=",za="=",Aa="==",Ba="===",J=">",Ca=">=",Da=">>",Ea=">>=",Fa=">>>",Ga=">>>=",Ha="?",Ia="@",L="[",M="^",Ta="^=",Ua="^^",Va="^^=",Wa="{",O="|",Xa="|=",Ya="||",Za="||=",$a="~",ab="break",bb="case",cb="continue",db="delete",eb="do",fb="else",gb="finally",hb="instanceof",ib="return",jb="throw",kb="try",lb="typeof",
+mb="(?:^^|[+-]",nb="\\$1",ob=")\\s*",pb="&amp;",qb="&lt;",rb="&gt;",sb="&quot;",tb="&#",ub="x",vb="'",wb='"',xb=" ",yb="XMP",zb="</",Ab='="',P="",Q="\\",Bb="b",Cb="t",Db="n",Eb="v",Fb="f",Gb="r",Hb="u",Ib="0",Jb="1",Kb="2",Lb="3",Mb="4",Nb="5",Ob="6",Pb="7",Qb="\\x0",Rb="\\x",Sb="-",Tb="]",Ub="\\\\u[0-9A-Fa-f]{4}|\\\\x[0-9A-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\s\\S]|-|[^-\\\\]",R="g",Vb="\\B",Wb="\\b",Xb="\\D",Yb="\\d",Zb="\\S",$b="\\s",ac="\\W",bc="\\w",cc="(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)",
+dc="(?:",ec=")",fc="gi",gc="PRE",hc='<!DOCTYPE foo PUBLIC "foo bar">\n<foo />',ic="\t",jc="\n",kc="[^<]+|<!--[\\s\\S]*?--\>|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>|</?[a-zA-Z][^>]*>|<",lc="nocode",mc=' $1="$2$3$4"',S="pln",nc="string",T="lang-",oc="src",U="str",pc="'\"",qc="'\"`",rc="\"'",V="com",sc="lang-regex",tc="(/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/)",uc="kwd",vc="^(?:",wc=")\\b",xc=" \r\n\t\u00a0",yc="lit",zc="typ",Ac="0123456789",Y="pun",Bc="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try alignof align_union asm axiom bool concept concept_map const_cast constexpr decltype dynamic_cast explicit export friend inline late_check mutable namespace nullptr reinterpret_cast static_assert static_cast template typeid typename typeof using virtual wchar_t where break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient as base by checked decimal delegate descending event fixed foreach from group implicit in interface internal into is lock object out override orderby params partial readonly ref sbyte sealed stackalloc string select uint ulong unchecked unsafe ushort var break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try debugger eval export function get null set undefined var with Infinity NaN caller delete die do dump elsif eval exit foreach for goto if import last local my next no our print package redo require sub undef unless until use wantarray while BEGIN END break continue do else for if return while and as assert class def del elif except exec finally from global import in is lambda nonlocal not or pass print raise try with yield False True None break continue do else for if return while alias and begin case class def defined elsif end ensure false in module next nil not or redo rescue retry self super then true undef unless until when yield BEGIN END break continue do else for if return while case done elif esac eval fi function in local set then until ",
+Cc="</span>",Dc='<span class="',Ec='">',Fc="$1&nbsp;",Gc="&nbsp;<br />",Hc="<br />",Ic="console",Jc="cannot override language handler %s",Kc="default-markup",Lc="default-code",Mc="dec",Z="lang-js",$="lang-css",Nc="lang-in.tag",Oc="htm",Pc="html",Qc="mxml",Rc="xhtml",Sc="xml",Tc="xsl",Uc=" \t\r\n",Vc="atv",Wc="tag",Xc="atn",Yc="lang-uq.val",Zc="in.tag",$c="uq.val",ad="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try alignof align_union asm axiom bool concept concept_map const_cast constexpr decltype dynamic_cast explicit export friend inline late_check mutable namespace nullptr reinterpret_cast static_assert static_cast template typeid typename typeof using virtual wchar_t where ",
+bd="c",cd="cc",dd="cpp",ed="cxx",fd="cyc",gd="m",hd="null true false",id="json",jd="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient as base by checked decimal delegate descending event fixed foreach from group implicit in interface internal into is lock object out override orderby params partial readonly ref sbyte sealed stackalloc string select uint ulong unchecked unsafe ushort var ",
+kd="cs",ld="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient ",md="java",nd="break continue do else for if return while case done elif esac eval fi function in local set then until ",
+od="bsh",pd="csh",qd="sh",rd="break continue do else for if return while and as assert class def del elif except exec finally from global import in is lambda nonlocal not or pass print raise try with yield False True None ",sd="cv",td="py",ud="caller delete die do dump elsif eval exit foreach for goto if import last local my next no our print package redo require sub undef unless until use wantarray while BEGIN END ",vd="perl",wd="pl",xd="pm",yd="break continue do else for if return while alias and begin case class def defined elsif end ensure false in module next nil not or redo rescue retry self super then true undef unless until when yield BEGIN END ",
+zd="rb",Ad="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try debugger eval export function get null set undefined var with Infinity NaN ",Bd="js",Cd="regex",Dd="pre",Ed="code",Fd="xmp",Gd="prettyprint",Hd="class",Id="br",Jd="\r";
+(function(){var N=function(){for(var a=[aa,ba,ca,F,da,ea,G,fa,ja,ka,H,la,ma,na,oa,pa,qa,ra,sa,ta,ua,va,I,wa,xa,ya,za,Aa,Ba,J,Ca,Da,Ea,Fa,Ga,Ha,Ia,L,M,Ta,Ua,Va,Wa,O,Xa,Ya,Za,$a,ab,bb,cb,db,eb,fb,gb,hb,ib,jb,kb,lb],b=mb,c=0;c<a.length;++c)b+=O+a[c].replace(/([^=<>:&a-z])/g,nb);b+=ob;return b}(),Ja=/&/g,Ka=/</g,La=/>/g,Kd=/\"/g;function Ld(a){return a.replace(Ja,pb).replace(Ka,qb).replace(La,rb).replace(Kd,sb)}function ga(a){return a.replace(Ja,pb).replace(Ka,qb).replace(La,rb)}var Md=/&lt;/g,Nd=/&gt;/g,
+Od=/&apos;/g,Pd=/&quot;/g,Qd=/&amp;/g,Rd=/&nbsp;/g;function Sd(a){var b=a.indexOf(G);if(b<0)return a;for(--b;(b=a.indexOf(tb,b+1))>=0;){var c=a.indexOf(va,b);if(c>=0){var d=a.substring(b+3,c),g=10;if(d&&d.charAt(0)===ub){d=d.substring(1);g=16}var i=parseInt(d,g);isNaN(i)||(a=a.substring(0,b)+String.fromCharCode(i)+a.substring(c+1))}}return a.replace(Md,I).replace(Nd,J).replace(Od,vb).replace(Pd,wb).replace(Qd,G).replace(Rd,xb)}function Ma(a){return yb===a.tagName}function W(a,b){switch(a.nodeType){case 1:var c=
+a.tagName.toLowerCase();b.push(I,c);for(var d=0;d<a.attributes.length;++d){var g=a.attributes[d];if(g.specified){b.push(xb);W(g,b)}}b.push(J);for(var i=a.firstChild;i;i=i.nextSibling)W(i,b);if(a.firstChild||!/^(?:br|link|img)$/.test(c))b.push(zb,c,J);break;case 2:b.push(a.name.toLowerCase(),Ab,Ld(a.value),wb);break;case 3:case 4:b.push(ga(a.nodeValue));break}}function Na(a){for(var b=0,c=z,d=z,g=0,i=a.length;g<i;++g){var m=a[g];if(m.ignoreCase)d=o;else if(/[a-z]/i.test(m.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,
+P))){c=o;d=z;break}}function l(j){if(j.charAt(0)!==Q)return j.charCodeAt(0);switch(j.charAt(1)){case Bb:return 8;case Cb:return 9;case Db:return 10;case Eb:return 11;case Fb:return 12;case Gb:return 13;case Hb:case ub:return parseInt(j.substring(2),16)||j.charCodeAt(1);case Ib:case Jb:case Kb:case Lb:case Mb:case Nb:case Ob:case Pb:return parseInt(j.substring(1),8);default:return j.charCodeAt(1)}}function n(j){if(j<32)return(j<16?Qb:Rb)+j.toString(16);var f=String.fromCharCode(j);if(f===Q||f===Sb||
+f===L||f===Tb)f=Q+f;return f}function q(j){for(var f=j.substring(1,j.length-1).match(new RegExp(Ub,R)),s=[],k=[],h=f[0]===M,e=h?1:0,p=f.length;e<p;++e){var t=f[e];switch(t){case Vb:case Wb:case Xb:case Yb:case Zb:case $b:case ac:case bc:s.push(t);continue}var u=l(t),x;if(e+2<p&&Sb===f[e+1]){x=l(f[e+2]);e+=2}else x=u;k.push([u,x]);if(!(x<65||u>122)){x<65||u>90||k.push([Math.max(65,u)|32,Math.min(x,90)|32]);x<97||u>122||k.push([Math.max(97,u)&-33,Math.min(x,122)&-33])}}k.sort(function(Oa,Pa){return Oa[0]-
+Pa[0]||Pa[1]-Oa[1]});var B=[],E=[NaN,NaN];for(e=0;e<k.length;++e){var A=k[e];if(A[0]<=E[1]+1)E[1]=Math.max(E[1],A[1]);else B.push(E=A)}var D=[L];h&&D.push(M);D.push.apply(D,s);for(e=0;e<B.length;++e){A=B[e];D.push(n(A[0]));if(A[1]>A[0]){A[1]+1>A[0]&&D.push(Sb);D.push(n(A[1]))}}D.push(Tb);return D.join(P)}function v(j){var f=j.source.match(new RegExp(cc,R)),s=f.length,k=[],h,e=0;for(h=0;e<s;++e){var p=f[e];if(p===H)++h;else if(Q===p.charAt(0)){var t=+p.substring(1);if(t&&t<=h)k[t]=-1}}for(e=1;e<k.length;++e)if(-1===
+k[e])k[e]=++b;for(h=e=0;e<s;++e){p=f[e];if(p===H){++h;if(k[h]===undefined)f[e]=dc}else if(Q===p.charAt(0))if((t=+p.substring(1))&&t<=h)f[e]=Q+k[h]}for(h=e=0;e<s;++e)if(M===f[e]&&M!==f[e+1])f[e]=P;if(j.ignoreCase&&c)for(e=0;e<s;++e){p=f[e];var u=p.charAt(0);if(p.length>=2&&u===L)f[e]=q(p);else if(u!==Q)f[e]=p.replace(/[a-zA-Z]/g,function(x){var B=x.charCodeAt(0);return L+String.fromCharCode(B&-33,B|32)+Tb})}return f.join(P)}var w=[];g=0;for(i=a.length;g<i;++g){m=a[g];if(m.global||m.multiline)throw new Error(P+
+m);w.push(dc+v(m)+ec)}return new RegExp(w.join(O),d?fc:R)}var ha=r;function Td(a){if(r===ha){var b=document.createElement(gc);b.appendChild(document.createTextNode(hc));ha=!/</.test(b.innerHTML)}if(ha){var c=a.innerHTML;if(Ma(a))c=ga(c);return c}for(var d=[],g=a.firstChild;g;g=g.nextSibling)W(g,d);return d.join(P)}function Ud(a){var b=0;return function(c){for(var d=r,g=0,i=0,m=c.length;i<m;++i){var l=c.charAt(i);switch(l){case ic:d||(d=[]);d.push(c.substring(g,i));var n=a-b%a;for(b+=n;n>=0;n-="                ".length)d.push("                ".substring(0,
+n));g=i+1;break;case jc:b=0;break;default:++b}}if(!d)return c;d.push(c.substring(g));return d.join(P)}}var Vd=new RegExp(kc,R),Wd=/^<\!--/,Xd=/^<\[CDATA\[/,Yd=/^<br\b/i,Qa=/^<(\/?)([a-zA-Z]+)/;function Zd(a){var b=a.match(Vd),c=[],d=0,g=[];if(b)for(var i=0,m=b.length;i<m;++i){var l=b[i];if(l.length>1&&l.charAt(0)===I){if(!Wd.test(l))if(Xd.test(l)){c.push(l.substring(9,l.length-3));d+=l.length-12}else if(Yd.test(l)){c.push(jc);++d}else if(l.indexOf(lc)>=0&&$d(l)){var n=l.match(Qa)[2],q=1,v;v=i+1;a:for(;v<
+m;++v){var w=b[v].match(Qa);if(w&&w[2]===n)if(w[1]===ra){if(--q===0)break a}else++q}if(v<m){g.push(d,b.slice(i,v+1).join(P));i=v}else g.push(d,l)}else g.push(d,l)}else{var j=Sd(l);c.push(j);d+=j.length}}return{source:c.join(P),tags:g}}function $d(a){return!!a.replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,mc).match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/)}function ia(a,b,c,d){if(b){var g={source:b,b:a};c(g);d.push.apply(d,g.c)}}function K(a,b){var c={},d;(function(){for(var m=a.concat(b),
+l=[],n={},q=0,v=m.length;q<v;++q){var w=m[q],j=w[3];if(j)for(var f=j.length;--f>=0;)c[j.charAt(f)]=w;var s=w[1],k=P+s;if(!n.hasOwnProperty(k)){l.push(s);n[k]=r}}l.push(/[\0-\uffff]/);d=Na(l)})();var g=b.length,i=function(m){for(var l=m.source,n=m.b,q=[n,S],v=0,w=l.match(d)||[],j={},f=0,s=w.length;f<s;++f){var k=w[f],h=j[k],e,p;if(typeof h===nc)p=z;else{var t=c[k.charAt(0)];if(t){e=k.match(t[1]);h=t[0]}else{for(var u=0;u<g;++u){t=b[u];if(e=k.match(t[1])){h=t[0];break}}e||(h=S)}if((p=h.length>=5&&T===
+h.substring(0,5))&&!(e&&e[1])){p=z;h=oc}p||(j[k]=h)}var x=v;v+=k.length;if(p){var B=e[1],E=k.indexOf(B),A=E+B.length,D=h.substring(5);ia(n+x,k.substring(0,E),i,q);ia(n+x+E,B,Ra(D,B),q);ia(n+x+A,k.substring(A),i,q)}else q.push(n+x,h)}m.c=q};return i}function C(a){var b=[],c=[];if(a.tripleQuotedStrings)b.push([U,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,r,pc]);
+else a.multiLineStrings?b.push([U,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,r,qc]):b.push([U,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,r,rc]);if(a.hashComments)a.cStyleComments?b.push([V,/^#(?:[^\r\n\/]|\/(?!\*)|\/\*[^\r\n]*?\*\/)*/,r,F]):b.push([V,/^#[^\r\n]*/,r,F]);if(a.cStyleComments){c.push([V,/^\/\/[^\r\n]*/,r]);c.push([V,/^\/\*[\s\S]*?(?:\*\/|$)/,r])}a.regexLiterals&&c.push([sc,new RegExp(M+N+tc)]);var d=
+a.keywords.replace(/^\s+|\s+$/g,P);d.length&&c.push([uc,new RegExp(vc+d.replace(/\s+/g,O)+wc),r]);b.push([S,/^\s+/,r,xc]);c.push([yc,/^@[a-z_$][a-z_$@0-9]*/i,r,Ia],[zc,/^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/,r],[S,/^[a-z_$][a-z_$@0-9]*/i,r],[yc,/^(?:0x[a-f0-9]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+\-]?\d+)?)[a-z]*/i,r,Ac],[Y,/^.[^\s\w\.$@\'\"\`\/\#]*/,r]);return K(b,c)}var ae=C({keywords:Bc,hashComments:o,cStyleComments:o,multiLineStrings:o,regexLiterals:o});function be(a){var b=a.source,c=a.f,d=a.c,
+g=[],i=0,m=r,l=r,n=0,q=0,v=Ud(window.PR_TAB_WIDTH),w=/([\r\n ]) /g,j=/(^| ) /gm,f=/\r\n?|\n/g,s=/[ \r\n]$/,k=o;function h(p){if(p>i){if(m&&m!==l){g.push(Cc);m=r}if(!m&&l){m=l;g.push(Dc,m,Ec)}var t=ga(v(b.substring(i,p))).replace(k?j:w,Fc);k=s.test(t);var u=window._pr_isIE6()?Gc:Hc;g.push(t.replace(f,u));i=p}}for(;1;){var e;if(e=n<c.length?q<d.length?c[n]<=d[q]:o:z){h(c[n]);if(m){g.push(Cc);m=r}g.push(c[n+1]);n+=2}else if(q<d.length){h(d[q]);l=d[q+1];q+=2}else break}h(b.length);m&&g.push(Cc);a.a=g.join(P)}
+var X={};function y(a,b){for(var c=b.length;--c>=0;){var d=b[c];if(X.hasOwnProperty(d))Ic in window&&console.i(Jc,d);else X[d]=a}}function Ra(a,b){a&&X.hasOwnProperty(a)||(a=/^\s*</.test(b)?Kc:Lc);return X[a]}y(ae,[Lc]);y(K([],[[S,/^[^<?]+/],[Mc,/^<!\w[^>]*(?:>|$)/],[V,/^<\!--[\s\S]*?(?:-\->|$)/],[T,/^<\?([\s\S]+?)(?:\?>|$)/],[T,/^<%([\s\S]+?)(?:%>|$)/],[Y,/^(?:<[%?]|[%?]>)/],[T,/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],[Z,/^<script\b[^>]*>([\s\S]+?)<\/script\b[^>]*>/i],[$,/^<style\b[^>]*>([\s\S]+?)<\/style\b[^>]*>/i],
+[Nc,/^(<\/?[a-z][^<>]*>)/i]]),[Kc,Oc,Pc,Qc,Rc,Sc,Tc]);y(K([[S,/^[\s]+/,r,Uc],[Vc,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,r,rc]],[[Wc,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[Xc,/^(?!style\b|on)[a-z](?:[\w:-]*\w)?/],[Yc,/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[Y,/^[=<>\/]+/],[Z,/^on\w+\s*=\s*\"([^\"]+)\"/i],[Z,/^on\w+\s*=\s*\'([^\']+)\'/i],[Z,/^on\w+\s*=\s*([^\"\'>\s]+)/i],[$,/^sty\w+\s*=\s*\"([^\"]+)\"/i],[$,/^sty\w+\s*=\s*\'([^\']+)\'/i],[$,/^sty\w+\s*=\s*([^\"\'>\s]+)/i]]),[Zc]);y(K([],[[Vc,/^[\s\S]+/]]),
+[$c]);y(C({keywords:ad,hashComments:o,cStyleComments:o}),[bd,cd,dd,ed,fd,gd]);y(C({keywords:hd}),[id]);y(C({keywords:jd,hashComments:o,cStyleComments:o}),[kd]);y(C({keywords:ld,cStyleComments:o}),[md]);y(C({keywords:nd,hashComments:o,multiLineStrings:o}),[od,pd,qd]);y(C({keywords:rd,hashComments:o,multiLineStrings:o,tripleQuotedStrings:o}),[sd,td]);y(C({keywords:ud,hashComments:o,multiLineStrings:o,regexLiterals:o}),[vd,wd,xd]);y(C({keywords:yd,hashComments:o,multiLineStrings:o,regexLiterals:o}),
+[zd]);y(C({keywords:Ad,cStyleComments:o,regexLiterals:o}),[Bd]);y(K([],[[U,/^[\s\S]+/]]),[Cd]);function Sa(a){var b=a.e,c=a.d;a.a=b;try{var d=Zd(b),g=d.source;a.source=g;a.b=0;a.f=d.tags;Ra(c,g)(a);be(a)}catch(i){if(Ic in window){console.log(i);console.h()}}}function ce(a,b){var c={e:a,d:b};Sa(c);return c.a}function de(a){for(var b=window._pr_isIE6(),c=[document.getElementsByTagName(Dd),document.getElementsByTagName(Ed),document.getElementsByTagName(Fd)],d=[],g=0;g<c.length;++g)for(var i=0,m=c[g].length;i<
+m;++i)d.push(c[g][i]);c=r;var l=Date;l.now||(l={now:function(){return(new Date).getTime()}});var n=0,q;function v(){for(var j=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;n<d.length&&l.now()<j;n++){var f=d[n];if(f.className&&f.className.indexOf(Gd)>=0){var s=f.className.match(/\blang-(\w+)\b/);if(s)s=s[1];for(var k=z,h=f.parentNode;h;h=h.parentNode)if((h.tagName===Dd||h.tagName===Ed||h.tagName===Fd)&&h.className&&h.className.indexOf(Gd)>=0){k=o;break}if(!k){var e=Td(f);e=e.replace(/(?:\r\n?|\n)$/,
+P);q={e:e,d:s,g:f};Sa(q);w()}}}if(n<d.length)setTimeout(v,250);else a&&a()}function w(){var j=q.a;if(j){var f=q.g;if(Ma(f)){for(var s=document.createElement(gc),k=0;k<f.attributes.length;++k){var h=f.attributes[k];if(h.specified){var e=h.name.toLowerCase();if(e===Hd)s.className=h.value;else s.setAttribute(h.name,h.value)}}s.innerHTML=j;f.parentNode.replaceChild(s,f);f=s}else f.innerHTML=j;if(b&&f.tagName===gc)for(var p=f.getElementsByTagName(Id),t=p.length;--t>=0;){var u=p[t];u.parentNode.replaceChild(document.createTextNode(Jd),
+u)}}}v()}window.PR_normalizedHtml=W;window.prettyPrintOne=ce;window.prettyPrint=de;window.PR={combinePrefixPatterns:Na,createSimpleLexer:K,registerLangHandler:y,sourceDecorator:C,PR_ATTRIB_NAME:Xc,PR_ATTRIB_VALUE:Vc,PR_COMMENT:V,PR_DECLARATION:Mc,PR_KEYWORD:uc,PR_LITERAL:yc,PR_NOCODE:lc,PR_PLAIN:S,PR_PUNCTUATION:Y,PR_SOURCE:oc,PR_STRING:U,PR_TAG:Wc,PR_TYPE:zc}})();
+})()
diff --git a/res/assets/templates/assets/search_autocomplete.js b/res/assets/templates/assets/search_autocomplete.js
new file mode 100644
index 0000000..dd4552f
--- /dev/null
+++ b/res/assets/templates/assets/search_autocomplete.js
@@ -0,0 +1,266 @@
+var gSelectedIndex = -1;
+var gSelectedID = -1;
+var gMatches = new Array();
+var gLastText = "";
+var ROW_COUNT = 20;
+var gInitialized = false;
+var DEFAULT_TEXT = "search developer docs";
+
+function set_row_selected(row, selected)
+{
+    var c1 = row.cells[0];
+  //  var c2 = row.cells[1];
+    if (selected) {
+        c1.className = "jd-autocomplete jd-selected";
+  //      c2.className = "jd-autocomplete jd-selected jd-linktype";
+    } else {
+        c1.className = "jd-autocomplete";
+  //      c2.className = "jd-autocomplete jd-linktype";
+    }
+}
+
+function set_row_values(toroot, row, match)
+{
+    var link = row.cells[0].childNodes[0];
+    link.innerHTML = match.__hilabel || match.label;
+    link.href = toroot + match.link
+  //  row.cells[1].innerHTML = match.type;
+}
+
+function sync_selection_table(toroot)
+{
+    var filtered = document.getElementById("search_filtered");
+    var r; //TR DOM object
+    var i; //TR iterator
+    gSelectedID = -1;
+
+    filtered.onmouseover = function() { 
+        if(gSelectedIndex >= 0) {
+          set_row_selected(this.rows[gSelectedIndex], false);
+          gSelectedIndex = -1;
+        }
+    }
+
+    //initialize the table; draw it for the first time (but not visible).
+    if (!gInitialized) {
+        for (i=0; i<ROW_COUNT; i++) {
+            var r = filtered.insertRow(-1);
+            var c1 = r.insertCell(-1);
+        //    var c2 = r.insertCell(-1);
+            c1.className = "jd-autocomplete";
+         //   c2.className = "jd-autocomplete jd-linktype";
+            var link = document.createElement("a");
+            c1.onmousedown = function() {
+                window.location = this.firstChild.getAttribute("href");
+            }
+            c1.onmouseover = function() {
+                this.className = this.className + " jd-selected";
+            }
+            c1.onmouseout = function() {
+                this.className = "jd-autocomplete";
+            }
+            c1.appendChild(link);
+        }
+  /*      var r = filtered.insertRow(-1);
+        var c1 = r.insertCell(-1);
+        c1.className = "jd-autocomplete jd-linktype";
+        c1.colSpan = 2; */
+        gInitialized = true;
+    }
+
+    //if we have results, make the table visible and initialize result info
+    if (gMatches.length > 0) {
+        document.getElementById("search_filtered_div").className = "showing";
+        var N = gMatches.length < ROW_COUNT ? gMatches.length : ROW_COUNT;
+        for (i=0; i<N; i++) {
+            r = filtered.rows[i];
+            r.className = "show-row";
+            set_row_values(toroot, r, gMatches[i]);
+            set_row_selected(r, i == gSelectedIndex);
+            if (i == gSelectedIndex) {
+                gSelectedID = gMatches[i].id;
+            }
+        }
+        //start hiding rows that are no longer matches
+        for (; i<ROW_COUNT; i++) {
+            r = filtered.rows[i];
+            r.className = "no-display";
+        }
+        //if there are more results we're not showing, so say so.
+/*      if (gMatches.length > ROW_COUNT) {
+            r = filtered.rows[ROW_COUNT];
+            r.className = "show-row";
+            c1 = r.cells[0];
+            c1.innerHTML = "plus " + (gMatches.length-ROW_COUNT) + " more"; 
+        } else {
+            filtered.rows[ROW_COUNT].className = "hide-row";
+        }*/
+    //if we have no results, hide the table
+    } else {
+        document.getElementById("search_filtered_div").className = "no-display";
+    }
+}
+
+function search_changed(e, kd, toroot)
+{
+    var search = document.getElementById("search_autocomplete");
+    var text = search.value.replace(/(^ +)|( +$)/g, '');
+
+    // 13 = enter
+    if (e.keyCode == 13) {
+        document.getElementById("search_filtered_div").className = "no-display";
+        if (kd && gSelectedIndex >= 0) {
+            window.location = toroot + gMatches[gSelectedIndex].link;
+            return false;
+        } else if (gSelectedIndex < 0) {
+            return true;
+        }
+    }
+    // 38 -- arrow up
+    else if (kd && (e.keyCode == 38)) {
+        if (gSelectedIndex >= 0) {
+            gSelectedIndex--;
+        }
+        sync_selection_table(toroot);
+        return false;
+    }
+    // 40 -- arrow down
+    else if (kd && (e.keyCode == 40)) {
+        if (gSelectedIndex < gMatches.length-1
+                        && gSelectedIndex < ROW_COUNT-1) {
+            gSelectedIndex++;
+        }
+        sync_selection_table(toroot);
+        return false;
+    }
+    else if (!kd) {
+        gMatches = new Array();
+        matchedCount = 0;
+        gSelectedIndex = -1;
+        for (var i=0; i<DATA.length; i++) {
+            var s = DATA[i];
+            if (text.length != 0 &&
+                  s.label.toLowerCase().indexOf(text.toLowerCase()) != -1) {
+                gMatches[matchedCount] = s;
+                matchedCount++;
+            }
+        }
+        rank_autocomplete_results(text);
+        for (var i=0; i<gMatches.length; i++) {
+            var s = gMatches[i];
+            if (gSelectedID == s.id) {
+                gSelectedIndex = i;
+            }
+        }
+        highlight_autocomplete_result_labels(text);
+        sync_selection_table(toroot);
+        return true; // allow the event to bubble up to the search api
+    }
+}
+
+function rank_autocomplete_results(query) {
+    query = query || '';
+    if (!gMatches || !gMatches.length)
+      return;
+
+    // helper function that gets the last occurence index of the given regex
+    // in the given string, or -1 if not found
+    var _lastSearch = function(s, re) {
+      if (s == '')
+        return -1;
+      var l = -1;
+      var tmp;
+      while ((tmp = s.search(re)) >= 0) {
+        if (l < 0) l = 0;
+        l += tmp;
+        s = s.substr(tmp + 1);
+      }
+      return l;
+    };
+
+    // helper function that counts the occurrences of a given character in
+    // a given string
+    var _countChar = function(s, c) {
+      var n = 0;
+      for (var i=0; i<s.length; i++)
+        if (s.charAt(i) == c) ++n;
+      return n;
+    };
+
+    var queryLower = query.toLowerCase();
+    var queryAlnum = (queryLower.match(/\w+/) || [''])[0];
+    var partPrefixAlnumRE = new RegExp('\\b' + queryAlnum);
+    var partExactAlnumRE = new RegExp('\\b' + queryAlnum + '\\b');
+
+    var _resultScoreFn = function(result) {
+        // scores are calculated based on exact and prefix matches,
+        // and then number of path separators (dots) from the last
+        // match (i.e. favoring classes and deep package names)
+        var score = 1.0;
+        var labelLower = result.label.toLowerCase();
+        var t;
+        t = _lastSearch(labelLower, partExactAlnumRE);
+        if (t >= 0) {
+            // exact part match
+            var partsAfter = _countChar(labelLower.substr(t + 1), '.');
+            score *= 200 / (partsAfter + 1);
+        } else {
+            t = _lastSearch(labelLower, partPrefixAlnumRE);
+            if (t >= 0) {
+                // part prefix match
+                var partsAfter = _countChar(labelLower.substr(t + 1), '.');
+                score *= 20 / (partsAfter + 1);
+            }
+        }
+
+        return score;
+    };
+
+    for (var i=0; i<gMatches.length; i++) {
+        gMatches[i].__resultScore = _resultScoreFn(gMatches[i]);
+    }
+
+    gMatches.sort(function(a,b){
+        var n = b.__resultScore - a.__resultScore;
+        if (n == 0) // lexicographical sort if scores are the same
+            n = (a.label < b.label) ? -1 : 1;
+        return n;
+    });
+}
+
+function highlight_autocomplete_result_labels(query) {
+    query = query || '';
+    if (!gMatches || !gMatches.length)
+      return;
+
+    var queryLower = query.toLowerCase();
+    var queryAlnumDot = (queryLower.match(/[\w\.]+/) || [''])[0];
+    var queryRE = new RegExp(
+        '(' + queryAlnumDot.replace(/\./g, '\\.') + ')', 'ig');
+    for (var i=0; i<gMatches.length; i++) {
+        gMatches[i].__hilabel = gMatches[i].label.replace(
+            queryRE, '<b>$1</b>');
+    }
+}
+
+function search_focus_changed(obj, focused)
+{
+    if (focused) {
+        if(obj.value == DEFAULT_TEXT){
+            obj.value = "";
+            obj.style.color="#000000";
+        }
+    } else {
+        if(obj.value == ""){
+          obj.value = DEFAULT_TEXT;
+          obj.style.color="#aaaaaa";
+        }
+        document.getElementById("search_filtered_div").className = "no-display";
+    }
+}
+
+function submit_search() {
+  var query = document.getElementById('search_autocomplete').value;
+  document.location = toRoot + 'search.html#q=' + query + '&t=0';
+  return false;
+}
diff --git a/res/assets/templates/assets/style.css b/res/assets/templates/assets/style.css
new file mode 100644
index 0000000..5ad1118
--- /dev/null
+++ b/res/assets/templates/assets/style.css
@@ -0,0 +1,316 @@
+.jd-toptitle {
+    padding-left: 6px;
+    margin-bottom: 30px;
+    font-size: 160%;
+    font-weight: bold;
+}
+
+div#jd-content table {
+    border: none;
+}
+
+div#jd-content td, div#jd-content th {
+    font-size: small;
+}
+
+div#jd-content table.jd-linktable {
+    margin-top: 3px;
+    border-spacing: 0;
+}
+
+div#jd-content p.jd-deprecated-warning {
+    margin-top: 0;
+    margin-bottom: 10px;
+}
+
+div#jd-content table.jd-linktable th {
+    vertical-align: top;
+    text-align: left;
+    padding-top: 2px;
+    padding-bottom: 2px;
+    padding-left: 7px;
+    padding-right: 7px;
+    border: none;
+    border-top: 1px solid #d2d7d0;
+    background-color: #F7FCF4;
+}
+
+div#jd-content table.jd-linktable td {
+    border: none;
+}
+
+div#jd-content table.jd-linktable td  p {
+    padding: 0;
+    margin: 0;
+    line-height: 110%;
+}
+
+div#jd-content table.jd-linktable .jd-linkcol {
+    vertical-align: top;
+    padding-top: 3px;
+    padding-bottom: 0;
+    padding-left: 7px;
+    padding-right: 7px;
+    border-top: 1px solid #d2d7d0;
+    background-color: #E5F1E0;
+    line-height: 110%;
+}
+
+div#jd-content table.jd-linktable .jd-descrcol {
+    vertical-align: top;
+    padding-top: 3px;
+    padding-bottom: 0;
+    padding-left: 7px;
+    padding-right: 7px;
+    border-top: 1px solid #d2d7d0;
+    background-color: #F7FCF4;
+    line-height: 110%;
+}
+
+div#jd-content table.jd-linktable .jd-descrcol p {
+    padding: 0;
+    margin: 0;
+    line-height: 110%;
+}
+
+div#jd-content table.jd-linktable .jd-valcol {
+    vertical-align: top;
+    padding-top: 3px;
+    padding-bottom: 0;
+    padding-left: 7px;
+    padding-right: 7px;
+    border-top: 1px solid #d2d7d0;
+    background-color: #E5F1E0;
+    line-height: 110%;
+}
+
+div#jd-content table.jd-linktable .jd-commentrow {
+    vertical-align: top;
+    padding-top: 3px;
+    padding-bottom: 4px;
+    padding-left: 7px;
+    padding-right: 7px;
+    background-color: #F7FCF4;
+    line-height: 110%;
+}
+
+div#jd-content div.jd-inheritedlinks {
+    vertical-align: top;
+    margin-top: 9px;
+    padding-left: 7px;
+    padding-right: 7px;
+    background-color: #F7FCF4;
+    line-height: 110%;
+}
+
+div#jd-content .jd-page_title-prefix {
+    padding-top: 2em;
+    margin-bottom: -14pt;
+}
+
+div#jd-content {
+    margin-left: 0;
+    margin-right: 10px;
+    margin-bottom: 0;
+}
+
+div#jd-content h1 {
+    padding-left: 10px;
+}
+
+div#jd-content h2 {
+    padding-left: 10px;
+}
+
+div#jd-content h4 {
+    margin-top: 9px;
+    margin-bottom: 1px;
+}
+
+div#jd-content .jd-descr h5 {
+    margin-bottom: 8px;
+}
+
+div#jd-content .sidebox h3 {
+    margin: 1em 0 0 0;
+}
+
+div#jd-content .jd-letterlist {
+    margin-top: 20px;
+    margin-bottom: 0;
+}
+
+div#jd-content .jd-lettertable {
+    margin-top: 15px;
+    margin-right: 10px;
+}
+div#jd-content .jd-letterentries {
+	list-style: none;
+	margin-left: 0;
+}
+div#jd-content .jd-letterentrycomments {
+    color: gray;
+}
+
+div#jd-content table.jd-inheritance-table {
+    margin-top: 0;
+    margin-left: 10px;
+    margin-right: 10px;
+    border-spacing: 0;
+}
+
+div#jd-content table.jd-inheritance-table td {
+    border: none;
+    margin: 0;
+    padding: 0;
+    background-color: white;
+}
+
+div#jd-content table.jd-inheritance-table .jd-inheritance-space {
+    width: 10px;
+}
+
+div#jd-content table.jd-inheritance-table .jd-inheritance-interface-cell {
+    padding-left: 17px;
+}
+
+div#jd-content h4.jd-details-title {
+    margin: 0;
+    background-color: #E5F1E0;
+    padding: 2px;
+    padding-left: 10px;
+    padding-right: 10px;
+    margin-top: 15px;
+}
+
+div#jd-content .jd-details {
+    margin-top: 0;
+    margin-left: -10px;
+}
+
+div#jd-content .jd-details-descr {
+    line-height: 120%;
+    padding-left: 10px;
+    padding-top: 10px;
+    padding-right: 20px;
+}
+
+div#jd-content .jd-descr h5,
+div#jd-content .jd-details h5 {
+    font-style: normal;
+    text-decoration: none;
+    font-size: 120%;
+}
+
+div#jd-content .jd-more {
+}
+
+div#jd-content .jd-descr {
+    padding-top: 0;
+}
+
+div#jd-content .jd-tagdata {
+    margin-top: 6px;
+    margin-bottom: 6px;
+}
+
+div#jd-content .jd-tagtitle {
+    margin-top: 0px;
+}
+
+div#jd-content .jd-tagtable {
+    margin-top: 10px;
+    border-spacing: 0;
+}
+
+div#jd-content .jd-tagtable th {
+    background: white;
+    padding-left: 10px;
+    padding-right: 10px;
+line-height: 120%;
+}
+
+div#jd-content .jd-tagtable th,
+div#jd-content .jd-tagtable td {
+line-height: 120%;
+    border: none;
+    margin: 0;
+    text-align: left;
+    padding-top: 0px;
+    padding-bottom: 5px;
+}
+
+div#jd-content .Code,code,pre,samp,var {
+    color: #004000;
+}
+
+div#jd-content pre.Code {
+    padding-left: 20px;
+}
+
+/* XXX I would really like to apply font-size: 9pt only if var/samp
+   is NOT inside of a .jd-descr div. */
+div#jd-content .jd-descr code,var,samp {
+    padding-left: 0px;
+}
+
+#search_autocomplete {
+    font-size: 80%;
+}
+
+div#jd-searchbox table.jd-autocomplete-table-hidden {
+    display: none;
+}
+
+div#jd-searchbox table.jd-autocomplete-table-showing {
+    z-index: 10;
+    border: 1px solid #3366cc;
+    position: relative;
+    top: -14px;
+    left: 5px;
+    background-color: white;
+}
+
+div#jd-searchbox td.jd-autocomplete {
+    font-family: Arial, sans-serif;
+    padding-left: 6px;
+    padding-right: 6px;
+    padding-top: 1px;
+    padding-bottom: 1px;
+    font-size: 80%;
+    border: none;
+    margin: 0;
+    line-height: 105%;
+}
+
+div#jd-searchbox td.jd-selected {
+    background-color: #E5F1E0;
+}
+
+div#jd-searchbox td.jd-linktype {
+    color: #999999;
+}
+
+div#jd-content .jd-expando-trigger {
+    margin-left: -8px;
+    margin-right: 0px;
+    border: none;
+}
+
+div#jd-build-id {
+    color: #666;
+    width: 100%;
+    text-align: right;
+    padding-right: 5px;
+    padding-bottom: 3px;
+}
+
+@media print {
+    #jd-searchbox, .jd-nav {
+        display: none;
+    }
+    div#jd-content {
+        margin-top: 0px;
+    }
+}
+
diff --git a/res/assets/templates/assets/triangle-none.gif b/res/assets/templates/assets/triangle-none.gif
new file mode 100644
index 0000000..0c7b469
--- /dev/null
+++ b/res/assets/templates/assets/triangle-none.gif
Binary files differ
diff --git a/res/assets/templates/class.cs b/res/assets/templates/class.cs
new file mode 100644
index 0000000..e0eb95b
--- /dev/null
+++ b/res/assets/templates/class.cs
@@ -0,0 +1,648 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<body class="<?cs var:class.since ?>">
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="api-info-block">
+
+<?cs # are there inherited members ?>
+<?cs each:cl=class.inherited ?>
+  <?cs if:subcount(cl.methods) ?>
+   <?cs set:inhmethods = #1 ?>
+  <?cs /if ?>
+  <?cs if:subcount(cl.constants) ?>
+   <?cs set:inhconstants = #1 ?>
+  <?cs /if ?>
+  <?cs if:subcount(cl.fields) ?>
+   <?cs set:inhfields = #1 ?>
+  <?cs /if ?>
+  <?cs if:subcount(cl.attrs) ?>
+   <?cs set:inhattrs = #1 ?>
+  <?cs /if ?>
+<?cs /each ?>
+
+<div class="sum-details-links">
+<?cs if:inhattrs || inhconstants || inhfields || inhmethods || (!class.subclasses.hidden &&
+     (subcount(class.subclasses.direct) || subcount(class.subclasses.indirect))) ?>
+Summary:
+<?cs if:subcount(class.inners) ?>
+  <a href="#nestedclasses">Nested Classes</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.attrs) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#lattrs">XML Attrs</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:inhattrs ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhattrs">Inherited XML Attrs</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.enumConstants) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#enumconstants">Enums</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.constants) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#constants">Constants</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:inhconstants ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhconstants">Inherited Constants</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.fields) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#lfields">Fields</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:inhfields ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhfields">Inherited Fields</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.ctors.public) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#pubctors">Ctors</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.ctors.protected) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#proctors">Protected Ctors</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.methods.public) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#pubmethods">Methods</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.methods.protected) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#promethods">Protected Methods</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:inhmethods ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhmethods">Inherited Methods</a>
+<?cs /if ?>
+&#124; <a href="#" onclick="return toggleAllClassInherited()" id="toggleAllClassInherited">[Expand All]</a>
+<?cs /if ?>
+</div><!-- end sum-details-links -->
+<div class="api-level">
+  <?cs call:since_tags(class) ?>
+  <?cs call:federated_refs(class) ?>
+</div>
+</div><!-- end api-info-block -->
+
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ======== START OF CLASS DATA ======== -->
+
+<div id="jd-header">
+    <?cs var:class.scope ?>
+    <?cs var:class.static ?> 
+    <?cs var:class.final ?> 
+    <?cs var:class.abstract ?>
+    <?cs var:class.kind ?>
+<h1><?cs var:class.name ?></h1>
+
+<?cs set:colspan = subcount(class.inheritance) ?>
+<?cs each:supr = class.inheritance ?>
+  <?cs if:colspan == 2 ?>
+    extends <?cs call:type_link(supr.short_class) ?><br/>
+  <?cs /if ?>
+  <?cs if:last(supr) && subcount(supr.interfaces) ?>
+      implements 
+      <?cs each:t=supr.interfaces ?>
+        <?cs call:type_link(t) ?> 
+      <?cs /each ?>
+  <?cs /if ?>
+  <?cs set:colspan = colspan-1 ?>
+<?cs /each ?>
+
+</div><!-- end header -->
+
+<div id="naMessage"></div>
+
+<div id="jd-content" class="api apilevel-<?cs var:class.since ?>">
+<table class="jd-inheritance-table">
+<?cs set:colspan = subcount(class.inheritance) ?>
+<?cs each:supr = class.inheritance ?>
+    <tr>
+        <?cs loop:i = 1, (subcount(class.inheritance)-colspan), 1 ?>
+            <td class="jd-inheritance-space">&nbsp;<?cs if:(subcount(class.inheritance)-colspan) == i ?>&nbsp;&nbsp;&#x21b3;<?cs /if ?></td>
+        <?cs /loop ?> 	
+        <td colspan="<?cs var:colspan ?>" class="jd-inheritance-class-cell"><?cs
+            if:colspan == 1
+                ?><?cs call:class_name(class.qualifiedType) ?><?cs 
+            else 
+                ?><?cs call:type_link(supr.class) ?><?cs
+            /if ?></td>
+    </tr>
+    <?cs set:colspan = colspan-1 ?>
+<?cs /each ?>
+</table>
+
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+
+<?cs if:subcount(class.subclasses.direct) && !class.subclasses.hidden ?>
+<table class="jd-sumtable jd-sumtable-subclasses"><tr><td colspan="12" style="border:none;margin:0;padding:0;">
+<?cs call:expando_trigger("subclasses-direct", "closed") ?>Known Direct Subclasses
+<?cs call:expandable_class_list("subclasses-direct", class.subclasses.direct, "list") ?>
+</td></tr></table>
+<?cs /if ?>
+
+<?cs if:subcount(class.subclasses.indirect) && !class.subclasses.hidden ?>
+<table class="jd-sumtable jd-sumtable-subclasses"><tr><td colspan="12" style="border:none;margin:0;padding:0;">
+<?cs call:expando_trigger("subclasses-indirect", "closed") ?>Known Indirect Subclasses
+<?cs call:expandable_class_list("subclasses-indirect", class.subclasses.indirect, "list") ?>
+</td></tr></table>
+<?cs /if ?>
+
+<div class="jd-descr">
+<?cs call:deprecated_warning(class) ?>
+<?cs if:subcount(class.descr) ?>
+<h2>Class Overview</h2>
+<p><?cs call:tag_list(class.descr) ?></p>
+<?cs /if ?>
+
+<?cs call:see_also_tags(class.seeAlso) ?>
+
+</div><!-- jd-descr -->
+
+
+<?cs # summary macros ?>
+
+<?cs def:write_method_summary(methods, included) ?>
+<?cs set:count = #1 ?>
+<?cs each:method = methods ?>
+	 <?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
+    <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:method.since ?>" >
+        <td class="jd-typecol"><nobr>
+            <?cs var:method.abstract ?>
+            <?cs var:method.synchronized ?>
+            <?cs var:method.final ?>
+            <?cs var:method.static ?>
+            <?cs call:type_link(method.generic) ?>
+            <?cs call:type_link(method.returnType) ?></nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><?cs call:cond_link(method.name, toroot, method.href, included) ?></span>(<?cs call:parameter_list(method.params) ?>)</nobr>
+        <?cs if:subcount(method.shortDescr) || subcount(method.deprecated) ?>
+        <div class="jd-descrdiv"><?cs call:short_descr(method) ?></div>
+  <?cs /if ?>
+  </td></tr>
+<?cs set:count = count + #1 ?>
+<?cs /each ?>
+<?cs /def ?>
+
+<?cs def:write_field_summary(fields, included) ?>
+<?cs set:count = #1 ?>
+    <?cs each:field=fields ?>
+      <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:field.since ?>" >
+          <td class="jd-typecol"><nobr>
+          <?cs var:field.scope ?>
+          <?cs var:field.static ?>
+          <?cs var:field.final ?>
+          <?cs call:type_link(field.type) ?></nobr></td>
+          <td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, included) ?></td>
+          <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?></td>
+      </tr>
+      <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+<?cs /def ?>
+
+<?cs def:write_constant_summary(fields, included) ?>
+<?cs set:count = #1 ?>
+    <?cs each:field=fields ?>
+    <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:field.since ?>" >
+        <td class="jd-typecol"><?cs call:type_link(field.type) ?></td>
+        <td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, included) ?></td>
+        <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?></td>
+    </tr>
+    <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+<?cs /def ?>
+
+<?cs def:write_attr_summary(attrs, included) ?>
+<?cs set:count = #1 ?>
+    <tr>
+        <td><nobr><em>Attribute Name</em></nobr></td>
+        <td><nobr><em>Related Method</em></nobr></td>
+        <td><nobr><em>Description</em></nobr></td>
+    </tr>
+    <?cs each:attr=attrs ?>
+    <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:attr.since ?>" >
+        <td class="jd-linkcol"><?cs if:included ?><a href="<?cs var:toroot ?><?cs var:attr.href ?>"><?cs /if ?><?cs var:attr.name ?><?cs if:included ?></a><?cs /if ?></td>
+        <td class="jd-linkcol"><?cs each:m=attr.methods ?>
+            <?cs call:cond_link(m.name, toroot, m.href, included) ?>
+            <?cs /each ?>
+        </td>
+        <td class="jd-descrcol" width="100%"><?cs call:short_descr(attr) ?>&nbsp;</td>
+    </tr>
+    <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+<?cs /def ?>
+
+<?cs def:write_inners_summary(classes) ?>
+<?cs set:count = #1 ?>
+  <?cs each:cl=class.inners ?>
+    <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.since ?>" >
+      <td class="jd-typecol"><nobr>
+        <?cs var:cl.scope ?>
+        <?cs var:cl.static ?> 
+        <?cs var:cl.final ?> 
+        <?cs var:cl.abstract ?>
+        <?cs var:cl.kind ?></nobr></td>
+      <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
+      <td class="jd-descrcol" width="100%"><?cs call:short_descr(cl) ?>&nbsp;</td>
+    </tr>
+    <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+<?cs /def ?>
+
+<?cs # end macros ?>
+
+<div class="jd-descr">
+<?cs # make sure there's a summary view to display ?>
+<?cs if:subcount(class.inners)
+     || subcount(class.attrs)
+     || inhattrs
+     || subcount(class.enumConstants)
+     || subcount(class.constants)
+     || inhconstants
+     || subcount(class.fields)
+     || inhfields
+     || subcount(class.ctors.public)
+     || subcount(class.ctors.protected)
+     || subcount(class.methods.public)
+     || subcount(class.methods.protected)
+     || inhmethods ?>
+<h2>Summary</h2>
+
+<?cs if:subcount(class.inners) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+<table id="nestedclasses" class="jd-sumtable"><tr><th colspan="12">Nested Classes</th></tr>
+<?cs call:write_inners_summary(class.inners) ?>
+<?cs /if ?>
+
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<?cs if:subcount(class.attrs) ?>
+<!-- =========== FIELD SUMMARY =========== -->
+<table id="lattrs" class="jd-sumtable"><tr><th colspan="12">XML Attributes</th></tr>
+<?cs call:write_attr_summary(class.attrs, 1) ?>
+<?cs /if ?>
+
+<?cs # if there are inherited attrs, write the table ?>
+<?cs if:inhattrs ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- =========== FIELD SUMMARY =========== -->
+<table id="inhattrs" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited XML Attributes</div></th></tr>
+<?cs each:cl=class.inherited ?>
+<?cs if:subcount(cl.attrs) ?>
+<tr class="api apilevel-<?cs var:cl.since ?>" >
+<td colspan="12">
+<?cs call:expando_trigger("inherited-attrs-"+cl.qualified, "closed") ?>From <?cs var:cl.kind ?>
+<?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
+<div id="inherited-attrs-<?cs var:cl.qualified ?>">
+  <div id="inherited-attrs-<?cs var:cl.qualified ?>-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-attrs-<?cs var:cl.qualified ?>-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    <?cs call:write_attr_summary(cl.attrs, cl.included) ?></table>
+  </div>
+</div>
+</td></tr>
+<?cs /if ?>
+<?cs /each ?>
+</table>
+<?cs /if ?>
+
+<?cs if:subcount(class.enumConstants) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- =========== ENUM CONSTANT SUMMARY =========== -->
+<table id="enumconstants" class="jd-sumtable"><tr><th colspan="12">Enum Values</th></tr>
+<?cs set:count = #1 ?>
+    <?cs each:field=class.enumConstants ?>
+    <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:field.since ?>" >
+        <td class="jd-descrcol"><?cs call:type_link(field.type) ?>&nbsp;</td>
+        <td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, cl.included) ?>&nbsp;</td>
+        <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?>&nbsp;</td>
+    </tr>
+    <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+<?cs /if ?>
+
+<?cs if:subcount(class.constants) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- =========== ENUM CONSTANT SUMMARY =========== -->
+<table id="constants" class="jd-sumtable"><tr><th colspan="12">Constants</th></tr>
+<?cs call:write_constant_summary(class.constants, 1) ?>
+</table>
+<?cs /if ?>
+
+<?cs # if there are inherited constants, write the table ?>
+<?cs if:inhconstants ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- =========== ENUM CONSTANT SUMMARY =========== -->
+<table id="inhconstants" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Constants</div></th></tr>
+<?cs each:cl=class.inherited ?>
+<?cs if:subcount(cl.constants) ?>
+<tr class="api apilevel-<?cs var:cl.since ?>" >
+<td colspan="12">
+<?cs call:expando_trigger("inherited-constants-"+cl.qualified, "closed") ?>From <?cs var:cl.kind ?>
+<?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
+<div id="inherited-constants-<?cs var:cl.qualified ?>">
+  <div id="inherited-constants-<?cs var:cl.qualified ?>-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-constants-<?cs var:cl.qualified ?>-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    <?cs call:write_constant_summary(cl.constants, cl.included) ?></table>
+  </div>
+</div>
+</td></tr>
+<?cs /if ?>
+<?cs /each ?>
+</table>
+<?cs /if ?>
+
+<?cs if:subcount(class.fields) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- =========== FIELD SUMMARY =========== -->
+<table id="lfields" class="jd-sumtable"><tr><th colspan="12">Fields</th></tr>
+<?cs call:write_field_summary(class.fields, 1) ?>
+</table>
+<?cs /if ?>
+
+<?cs # if there are inherited fields, write the table ?>
+<?cs if:inhfields ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- =========== FIELD SUMMARY =========== -->
+<table id="inhfields" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Fields</div></th></tr>
+<?cs each:cl=class.inherited ?>
+<?cs if:subcount(cl.fields) ?>
+<tr class="api apilevel-<?cs var:cl.since ?>" >
+<td colspan="12">
+<?cs call:expando_trigger("inherited-fields-"+cl.qualified, "closed") ?>From <?cs var:cl.kind ?>
+<?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
+<div id="inherited-fields-<?cs var:cl.qualified ?>">
+  <div id="inherited-fields-<?cs var:cl.qualified ?>-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-fields-<?cs var:cl.qualified ?>-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    <?cs call:write_field_summary(cl.fields, cl.included) ?></table>
+  </div>
+</div>
+</td></tr>
+<?cs /if ?>
+<?cs /each ?>
+</table>
+<?cs /if ?>
+
+<?cs if:subcount(class.ctors.public) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<table id="pubctors" class="jd-sumtable"><tr><th colspan="12">Public Constructors</th></tr>
+<?cs call:write_method_summary(class.ctors.public, 1) ?>
+</table>
+<?cs /if ?>
+
+<?cs if:subcount(class.ctors.protected) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<table id="proctors" class="jd-sumtable"><tr><th colspan="12">Protected Constructors</th></tr>
+<?cs call:write_method_summary(class.ctors.protected, 1) ?>
+</table>
+<?cs /if ?>
+
+<?cs if:subcount(class.methods.public) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="pubmethods" class="jd-sumtable"><tr><th colspan="12">Public Methods</th></tr>
+<?cs call:write_method_summary(class.methods.public, 1) ?>
+</table>
+<?cs /if ?>
+
+<?cs if:subcount(class.methods.protected) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="promethods" class="jd-sumtable"><tr><th colspan="12">Protected Methods</th></tr>
+<?cs call:write_method_summary(class.methods.protected, 1) ?>
+</table>
+<?cs /if ?>
+
+<?cs # if there are inherited methods, write the table ?>
+<?cs if:inhmethods ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="inhmethods" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Methods</div></th></tr>
+<?cs each:cl=class.inherited ?>
+<?cs if:subcount(cl.methods) ?>
+<tr class="api apilevel-<?cs var:cl.since ?>" >
+<td colspan="12"><?cs call:expando_trigger("inherited-methods-"+cl.qualified, "closed") ?>
+From <?cs var:cl.kind ?>
+<?cs if:cl.included ?>
+  <a href="<?cs var:toroot ?><?cs var:cl.link ?>"><?cs var:cl.qualified ?></a>
+<?cs elif:cl.federated ?>
+  <a href="<?cs var:cl.link ?>"><?cs var:cl.qualified ?></a>
+<?cs else ?>
+  <?cs var:cl.qualified ?>
+<?cs /if ?>
+<div id="inherited-methods-<?cs var:cl.qualified ?>">
+  <div id="inherited-methods-<?cs var:cl.qualified ?>-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-<?cs var:cl.qualified ?>-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    <?cs call:write_method_summary(cl.methods, cl.included) ?></table>
+  </div>
+</div>
+</td></tr>
+<?cs /if ?>
+<?cs /each ?>
+</table>
+<?cs /if ?>
+<?cs /if ?>
+</div><!-- jd-descr (summary) -->
+
+<!-- Details -->
+
+<?cs def:write_field_details(fields) ?>
+<?cs each:field=fields ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<?cs # the A tag in the next line must remain where it is, so that Eclipse can parse the docs ?>
+<A NAME="<?cs var:field.anchor ?>"></A>
+<?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
+<div class="jd-details api apilevel-<?cs var:field.since ?>"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <?cs var:field.scope ?> 
+        <?cs var:field.static ?> 
+        <?cs var:field.final ?> 
+        <?cs call:type_link(field.type) ?>
+      </span>
+        <?cs var:field.name ?>
+    </h4>
+      <div class="api-level">
+        <?cs call:since_tags(field) ?>
+        <?cs call:federated_refs(field) ?>
+      </div>
+    <div class="jd-details-descr">
+      <?cs call:description(field) ?>
+    <?cs if:subcount(field.constantValue) ?>
+        <div class="jd-tagdata">
+        <span class="jd-tagtitle">Constant Value: </span>
+        <span>
+            <?cs if:field.constantValue.isString ?>
+                <?cs var:field.constantValue.str ?>
+            <?cs else ?>
+                <?cs var:field.constantValue.dec ?>
+                (<?cs var:field.constantValue.hex ?>)
+            <?cs /if ?>
+        </span>
+        </div>
+    <?cs /if ?>
+    </div>
+</div>
+<?cs /each ?>
+<?cs /def ?>
+
+<?cs def:write_method_details(methods) ?>
+<?cs each:method=methods ?>
+<?cs # the A tag in the next line must remain where it is, so that Eclipse can parse the docs ?>
+<A NAME="<?cs var:method.anchor ?>"></A>
+<?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
+<div class="jd-details api apilevel-<?cs var:method.since ?>"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <?cs var:method.scope ?> 
+        <?cs var:method.static ?> 
+        <?cs var:method.final ?> 
+        <?cs var:method.abstract ?> 
+        <?cs var:method.synchronized ?> 
+        <?cs call:type_link(method.returnType) ?>
+      </span>
+      <span class="sympad"><?cs var:method.name ?></span>
+      <span class="normal">(<?cs call:parameter_list(method.params) ?>)</span>
+    </h4>
+      <div class="api-level">
+        <div><?cs call:since_tags(method) ?></div>
+        <?cs call:federated_refs(method) ?>
+      </div>
+    <div class="jd-details-descr">
+      <?cs call:description(method) ?>
+    </div>
+</div>
+<?cs /each ?>
+<?cs /def ?>
+
+<?cs def:write_attr_details(attrs) ?>
+<?cs each:attr=attrs ?>
+<?cs # the A tag in the next line must remain where it is, so that Eclipse can parse the docs ?>
+<A NAME="<?cs var:attr.anchor ?>"></A>
+<?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
+<div class="jd-details api apilevel-<?cs var:attr.since ?>"> 
+    <h4 class="jd-details-title"><?cs var:attr.name ?>
+    </h4>
+      <div class="api-level">
+        <?cs call:since_tags(attr) ?>
+      </div>
+    <div class="jd-details-descr">
+        <?cs call:description(attr) ?>
+
+        <div class="jd-tagdata">
+            <h5 class="jd-tagtitle">Related Methods</h5>
+            <ul class="nolist">
+            <?cs each:m=attr.methods ?>
+                <li><a href="<?cs var:toroot ?><?cs var:m.href ?>"><?cs var:m.name ?></a></li>
+            <?cs /each ?>
+            </ul>
+        </div>
+    </div>
+</div>
+<?cs /each ?>
+<?cs /def ?>
+
+
+<!-- XML Attributes -->
+<?cs if:subcount(class.attrs) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= FIELD DETAIL ======== -->
+<h2>XML Attributes</h2>
+<?cs call:write_attr_details(class.attrs) ?>
+<?cs /if ?>
+
+<!-- Enum Values -->
+<?cs if:subcount(class.enumConstants) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= ENUM CONSTANTS DETAIL ======== -->
+<h2>Enum Values</h2>
+<?cs call:write_field_details(class.enumConstants) ?>
+<?cs /if ?>
+
+<!-- Constants -->
+<?cs if:subcount(class.constants) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= ENUM CONSTANTS DETAIL ======== -->
+<h2>Constants</h2>
+<?cs call:write_field_details(class.constants) ?>
+<?cs /if ?>
+
+<!-- Fields -->
+<?cs if:subcount(class.fields) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= FIELD DETAIL ======== -->
+<h2>Fields</h2>
+<?cs call:write_field_details(class.fields) ?>
+<?cs /if ?>
+
+<!-- Public ctors -->
+<?cs if:subcount(class.ctors.public) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<h2>Public Constructors</h2>
+<?cs call:write_method_details(class.ctors.public) ?>
+<?cs /if ?>
+
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<!-- Protected ctors -->
+<?cs if:subcount(class.ctors.protected) ?>
+<h2>Protected Constructors</h2>
+<?cs call:write_method_details(class.ctors.protected) ?>
+<?cs /if ?>
+
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= METHOD DETAIL ======== -->
+<!-- Public methdos -->
+<?cs if:subcount(class.methods.public) ?>
+<h2>Public Methods</h2>
+<?cs call:write_method_details(class.methods.public) ?>
+<?cs /if ?>
+
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= METHOD DETAIL ======== -->
+<?cs if:subcount(class.methods.protected) ?>
+<h2>Protected Methods</h2>
+<?cs call:write_method_details(class.methods.protected) ?>
+<?cs /if ?>
+
+<?cs # the next two lines must be exactly like this to be parsed by eclipse ?>
+<!-- ========= END OF CLASS DATA ========= -->
+<A NAME="navbar_top"></A>
+
+<?cs include:"footer.cs" ?>
+</div> <!-- jd-content -->
+
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/res/assets/templates/classes.cs b/res/assets/templates/classes.cs
new file mode 100644
index 0000000..5a8315f
--- /dev/null
+++ b/res/assets/templates/classes.cs
@@ -0,0 +1,41 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="jd-header">
+<h1><?cs var:page.title ?></h1>
+</div>
+
+<div id="jd-content">
+
+<div class="jd-letterlist"><?cs each:letter=docs.classes ?>
+    <a href="#letter_<?cs name:letter ?>"><?cs name:letter ?></a><?cs /each?>
+</div>
+
+<?cs each:letter=docs.classes ?>
+<?cs set:count = #1 ?>
+<h2 id="letter_<?cs name:letter ?>"><?cs name:letter ?></h2>
+<table class="jd-sumtable">
+    <?cs set:cur_row = #0 ?>
+    <?cs each:cl = letter ?>
+        <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.since ?>" >
+            <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
+            <td class="jd-descrcol" width="100%"><?cs call:short_descr(cl) ?>&nbsp;</td>
+        </tr>
+    <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+</table>
+<?cs /each ?>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/res/assets/templates/components.cs b/res/assets/templates/components.cs
new file mode 100644
index 0000000..6ec1e81
--- /dev/null
+++ b/res/assets/templates/components.cs
@@ -0,0 +1,10 @@
+<?cs # This default template file is meant to be replaced. ?>
+<?cs # Use the -tempatedir arg to javadoc to set your own directory with a replacement for this file in it. ?>
+
+<?cs include:"components/search_box.cs" ?>
+<?cs include:"components/api_filter.cs" ?>
+
+<?cs include:"components/masthead.cs" ?>
+<?cs include:"components/left_nav.cs" ?>
+
+<?cs include:"customizations.cs" ?>
\ No newline at end of file
diff --git a/res/assets/templates/components/api_filter.cs b/res/assets/templates/components/api_filter.cs
new file mode 100644
index 0000000..9fb8a8d
--- /dev/null
+++ b/res/assets/templates/components/api_filter.cs
@@ -0,0 +1,19 @@
+<?cs # The default API filter selector that goes in the header ?><?cs
+def:default_api_filter() ?>
+  <div id="api-level-toggle">
+    <input type="checkbox" id="apiLevelCheckbox" onclick="toggleApiLevelSelector(this)" />
+    <label for="apiLevelCheckbox" class="disabled">Filter by API Level: </label>
+    <select id="apiLevelSelector">
+      <!-- option elements added by buildApiLevelSelector() -->
+    </select>
+  </div>
+  <script>
+    var SINCE_DATA = [ <?cs 
+      each:since = since ?>'<?cs 
+        var:since.name ?>'<?cs 
+        if:!last(since) ?>, <?cs /if ?><?cs
+      /each 
+    ?> ];
+    buildApiLevelSelector();
+  </script>
+<?cs /def ?>
\ No newline at end of file
diff --git a/res/assets/templates/components/left_nav.cs b/res/assets/templates/components/left_nav.cs
new file mode 100644
index 0000000..35525da
--- /dev/null
+++ b/res/assets/templates/components/left_nav.cs
@@ -0,0 +1,68 @@
+<?cs # The default side navigation for the reference docs ?><?cs 
+def:custom_left_nav() ?>
+  <div class="g-section g-tpl-240" id="body-content">
+    <div class="g-unit g-first side-nav-resizable" id="side-nav">
+      <div id="swapper">
+        <div id="nav-panels">
+          <div id="resize-packages-nav">
+            <div id="packages-nav">
+              <div id="index-links"><nobr>
+                <a href="<?cs var:toroot ?>reference/packages.html" <?cs if:(page.title == "Package Index") ?>class="selected"<?cs /if ?> >Package Index</a> | 
+                <a href="<?cs var:toroot ?>reference/classes.html" <?cs if:(page.title == "Class Index") ?>class="selected"<?cs /if ?>>Class Index</a></nobr>
+              </div>
+              <ul>
+                <?cs call:package_link_list(docs.packages) ?>
+              </ul><br/>
+            </div> <!-- end packages -->
+          </div> <!-- end resize-packages -->
+          <div id="classes-nav"><?cs 
+            if:subcount(class.package) ?>
+            <ul>
+              <?cs call:list("Interfaces", class.package.interfaces) ?>
+              <?cs call:list("Classes", class.package.classes) ?>
+              <?cs call:list("Enums", class.package.enums) ?>
+              <?cs call:list("Exceptions", class.package.exceptions) ?>
+              <?cs call:list("Errors", class.package.errors) ?>
+            </ul><?cs 
+            elif:subcount(package) ?>
+            <ul>
+              <?cs call:class_link_list("Interfaces", package.interfaces) ?>
+              <?cs call:class_link_list("Classes", package.classes) ?>
+              <?cs call:class_link_list("Enums", package.enums) ?>
+              <?cs call:class_link_list("Exceptions", package.exceptions) ?>
+              <?cs call:class_link_list("Errors", package.errors) ?>
+            </ul><?cs 
+            else ?>
+              <script>
+                /*addLoadEvent(maxPackageHeight);*/
+              </script>
+              <p style="padding:10px">Select a package to view its members</p><?cs 
+            /if ?><br/>
+          </div><!-- end classes -->
+        </div><!-- end nav-panels -->
+        <div id="nav-tree" style="display:none">
+          <div id="index-links"><nobr>
+            <a href="<?cs var:toroot ?>reference/packages.html" <?cs if:(page.title == "Package Index") ?>class="selected"<?cs /if ?> >Package Index</a> | 
+            <a href="<?cs var:toroot ?>reference/classes.html" <?cs if:(page.title == "Class Index") ?>class="selected"<?cs /if ?>>Class Index</a></nobr>
+          </div>
+        </div><!-- end nav-tree -->
+      </div><!-- end swapper -->
+    </div> <!-- end side-nav -->
+    <script>
+      if (!isMobile) {
+        $("<a href='#' id='nav-swap' onclick='swapNav();return false;' style='font-size:10px;line-height:9px;margin-left:1em;text-decoration:none;'><span id='tree-link'>Use Tree Navigation</span><span id='panel-link' style='display:none'>Use Panel Navigation</span></a>").appendTo("#side-nav");
+        chooseDefaultNav();
+        if ($("#nav-tree").is(':visible')) {
+          init_default_navtree("<?cs var:toroot ?>");
+        } else {
+          addLoadEvent(function() {
+            scrollIntoView("packages-nav");
+            scrollIntoView("classes-nav");
+          });
+        }
+        $("#swapper").css({borderBottom:"2px solid #aaa"});
+      } else {
+        swapNav(); // tree view should be used on mobile
+      }
+    </script><?cs 
+/def ?>
\ No newline at end of file
diff --git a/res/assets/templates/components/masthead.cs b/res/assets/templates/components/masthead.cs
new file mode 100644
index 0000000..944fc14
--- /dev/null
+++ b/res/assets/templates/components/masthead.cs
@@ -0,0 +1,12 @@
+<?cs def:custom_masthead() ?>
+<div id="header">
+    <div id="headerLeft">
+      <?cs if:reference && reference.apilevels ?>
+        <?cs call:default_api_filter() ?>
+      <?cs /if ?>
+    </div>
+    <div id="headerRight">
+        <?cs call:default_search_box() ?>
+    </div><!-- headerRight -->
+</div><!-- header -->
+<?cs /def ?>
\ No newline at end of file
diff --git a/res/assets/templates/components/search_box.cs b/res/assets/templates/components/search_box.cs
new file mode 100644
index 0000000..51628d6
--- /dev/null
+++ b/res/assets/templates/components/search_box.cs
@@ -0,0 +1,33 @@
+<?cs # The default search box that goes in the header ?><?cs 
+def:default_search_box() ?>
+  <div id="search" >
+      <div id="searchForm">
+          <form accept-charset="utf-8" class="gsc-search-box" 
+                onsubmit="return submit_search()">
+            <table class="gsc-search-box" cellpadding="0" cellspacing="0"><tbody>
+                <tr>
+                  <td class="gsc-input">
+                    <input id="search_autocomplete" class="gsc-input" type="text" size="33" autocomplete="off"
+                      title="search developer docs" name="q"
+                      value="search developer docs"
+                      onFocus="search_focus_changed(this, true)"
+                      onBlur="search_focus_changed(this, false)"
+                      onkeydown="return search_changed(event, true, '<?cs var:toroot?>')"
+                      onkeyup="return search_changed(event, false, '<?cs var:toroot?>')" />
+                  <div id="search_filtered_div" class="no-display">
+                      <table id="search_filtered" cellspacing=0>
+                      </table>
+                  </div>
+                  </td>
+                  <td class="gsc-search-button">
+                    <input type="submit" value="Search" title="search" id="search-button" class="gsc-search-button" />
+                  </td>
+                  <td class="gsc-clear-button">
+                    <div title="clear results" class="gsc-clear-button">&nbsp;</div>
+                  </td>
+                </tr></tbody>
+              </table>
+          </form>
+      </div><!-- searchForm -->
+  </div><!-- search --><?cs 
+/def ?>
\ No newline at end of file
diff --git a/res/assets/templates/data.hdf b/res/assets/templates/data.hdf
new file mode 100644
index 0000000..9411b78
--- /dev/null
+++ b/res/assets/templates/data.hdf
@@ -0,0 +1,4 @@
+template {
+    which = normal
+}
+
diff --git a/res/assets/templates/diff.cs b/res/assets/templates/diff.cs
new file mode 100644
index 0000000..5cce9c7
--- /dev/null
+++ b/res/assets/templates/diff.cs
@@ -0,0 +1,188 @@
+
+<style>
+
+.package-label {
+
+}
+
+.class-label {
+  padding-left: 40px;
+}
+
+.method-label {
+  padding-left: 80px;
+}
+
+.package-entry {
+  background-color: #778899;
+}
+
+.class-entry {
+  background-color: #a9a9a9;
+}
+
+.method-entry {
+  background-color: #dcdcdc;
+}
+
+.collapsed {
+  
+}
+
+.handle {
+  width: 25px;
+  background-repeat: no-repeat;
+}
+
+.handle-opened {
+  background-image: url("<?cs var:triangle.opened ?>");
+}
+
+.handle-closed {
+  background-image: url("<?cs var:triangle.closed?>");
+}
+
+.tbody {
+  padding: 0;
+  margin: 0;
+}
+
+#hierarchy {
+  border-collapse:collapse;
+}
+
+</style>
+
+<script type="text/javascript"
+    src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
+    
+<script type="text/javascript">
+function collapsePackage(tr) {
+  var table = $("#hierarchy")[0];
+  
+  if (!$(tr).hasClass("collapsable")) {
+    return;
+  }
+  
+  if ($(tr).hasClass("collapsed")) {
+    $(tr).removeClass("collapsed");
+    $(tr).children(".handle").addClass("handle-opened");
+    $(tr).children(".handle").removeClass("handle-closed");
+    if (tr.rowIndex + 1 < table.rows.length) {
+      var tbody = table.rows[tr.rowIndex + 1].parentNode;
+      $(tbody).show();
+    }
+  } else {
+    $(tr).addClass("collapsed");
+    $(tr).children(".handle").removeClass("handle-opened");
+    $(tr).children(".handle").addClass("handle-closed");
+    if (tr.rowIndex + 1 < table.rows.length
+        && $(table.rows[tr.rowIndex + 1]).hasClass("class-entry")) {
+      var tbody = table.rows[tr.rowIndex + 1].parentNode;
+      $(tbody).hide();
+    }
+  }
+}
+
+function collapseClass(tr) {
+  var table = $("#hierarchy")[0];
+  
+  if (!$(tr).hasClass("collapsable")) {
+    return;
+  }
+  
+  if ($(tr).hasClass("collapsed")) {
+    $(tr).removeClass("collapsed");
+    $(tr).children(".handle").addClass("handle-opened");
+    $(tr).children(".handle").removeClass("handle-closed");
+    var i = tr.rowIndex + 1;
+    while (i < table.rows.length && $(table.rows[i]).hasClass("method-entry")) {
+      $(table.rows[i++]).show();
+    }
+  } else {
+    $(tr).addClass("collapsed");
+    $(tr).children(".handle").removeClass("handle-opened");
+    $(tr).children(".handle").addClass("handle-closed");
+    var i = tr.rowIndex + 1;
+    while (i < table.rows.length && $(table.rows[i]).hasClass("method-entry")) {
+      $(table.rows[i++]).hide();
+    }
+  }
+}
+  
+$(function() {  
+  $(".package-entry").click(function() {
+    collapsePackage(this);
+  });
+  
+  $(".class-entry").click(function() {
+    collapseClass(this);
+  });
+});
+</script>
+
+<table border="0" id="hierarchy">
+<tr>
+<th> </th>
+<?cs each:site = sites ?>
+<th><?cs var:site.name ?></th>
+<?cs /each ?>
+</tr>
+<?cs each:package = packages ?>
+  <?cs if:subcount(package.classes) ?>
+    <tr class="package-entry collapsable">
+    <td class="handle handle-opened">&nbsp;</td>
+  <?cs else ?>
+    <tr class="package-entry">
+    <td class="handle">&nbsp;</td>
+  <?cs /if ?>
+  <td class="package-label"><?cs var:package.name ?></td>
+  <?cs each:site = package.sites ?>
+    <td>
+    <?cs if:site.hasPackage ?>
+    <a href="<?cs var:site.link ?>">Link</a>
+    <?cs else ?>
+    N/A
+    <?cs /if ?>
+    </td>
+  <?cs /each ?>
+  </tr>
+  <tbody class="package-contents">
+  <?cs each:class = package.classes ?>
+    <?cs if:subcount(class.methods) ?>
+      <tr class="class-entry collapsable">
+      <td class="handle handle-opened">&nbsp;</td>
+    <?cs else ?>
+      <tr class="class-entry">
+      <td class="handle">&nbsp;</td>
+    <?cs /if ?>
+      <td class="class-label"><?cs var:class.qualifiedName ?></td>
+      <?cs each:site = class.sites ?>
+        <td>
+        <?cs if:site.hasClass ?>
+        <a href="<?cs var:site.link ?>">Link</a>
+        <?cs else ?>
+        N/A
+        <?cs /if ?>
+        </td>
+      <?cs /each ?>
+    </tr>
+    <?cs each:method = class.methods ?>
+    <tr class="method-entry">
+      <td class="handle">&nbsp;</td>
+      <td class="method-label"><?cs var:method.signature ?></td>
+      <?cs each:site = method.sites ?>
+        <td>
+        <?cs if:site.hasMethod ?>
+        <a href="<?cs var:site.link ?>">Link</a>
+        <?cs else ?>
+        N/A
+        <?cs /if ?>
+        </td>
+      <?cs /each ?>
+    </tr>
+    <?cs /each ?><?cs # methods ?>
+  <?cs /each ?><?cs # classes ?>
+  </tbody>
+<?cs /each ?><?cs # packages ?>
+</table>
\ No newline at end of file
diff --git a/res/assets/templates/docpage.cs b/res/assets/templates/docpage.cs
new file mode 100644
index 0000000..9d85c6f
--- /dev/null
+++ b/res/assets/templates/docpage.cs
@@ -0,0 +1,41 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<body class="gc-documentation">
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content"><a name="top"></a>
+
+<div id="jd-header" class="guide-header">
+  <span class="crumb">
+    <?cs if:parent.link ?>
+      <a href="<?cs var:parent.link ?>"><?cs var:parent.title ?></a> >
+    <?cs else ?>&nbsp;
+    <?cs /if ?>
+  </span>
+<h1><?cs var:page.title ?></h1>
+</div>
+
+  <div id="jd-content">
+
+    <div class="jd-descr">
+    <?cs call:tag_list(root.descr) ?>
+    </div>
+
+  <a href="#top" style="float:right">&uarr; Go to top</a>
+  <?cs if:parent.link ?>
+    <p><a href="<?cs var:parent.link ?>">&larr; Back to <?cs var:parent.title ?></a></p>
+  <?cs /if ?>
+  </div>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
+
+
+
diff --git a/res/assets/templates/doctype.cs b/res/assets/templates/doctype.cs
new file mode 100644
index 0000000..763b073
--- /dev/null
+++ b/res/assets/templates/doctype.cs
@@ -0,0 +1 @@
+<!DOCTYPE html>
\ No newline at end of file
diff --git a/res/assets/templates/footer.cs b/res/assets/templates/footer.cs
new file mode 100644
index 0000000..ce6caa4
--- /dev/null
+++ b/res/assets/templates/footer.cs
@@ -0,0 +1,3 @@
+<div id="footer">
+
+</div> <!-- end footer -->
diff --git a/res/assets/templates/head_tag.cs b/res/assets/templates/head_tag.cs
new file mode 100644
index 0000000..3014f43
--- /dev/null
+++ b/res/assets/templates/head_tag.cs
@@ -0,0 +1,37 @@
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel="shortcut icon" type="image/x-icon" href="<?cs var:toroot ?>favicon.ico" />
+<title>
+<?cs if:page.title ?>
+  <?cs var:page.title ?> |
+<?cs /if ?>
+<?cs if:project.name ?>
+  <?cs var:project.name ?>
+<?cs else ?>Doclava
+<?cs /if ?>
+</title>
+<link href="<?cs var:toroot ?>assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="<?cs var:toroot ?>assets/customizations.css" rel="stylesheet" type="text/css" />
+<script src="<?cs var:toroot ?>assets/search_autocomplete.js" type="text/javascript"></script>
+<script src="<?cs var:toroot ?>assets/jquery-resizable.min.js" type="text/javascript"></script>
+<script src="<?cs var:toroot ?>assets/android-developer-docs.js" type="text/javascript"></script>
+<script src="<?cs var:toroot ?>assets/prettify.js" type="text/javascript"></script>
+<script type="text/javascript">
+  setToRoot("<?cs var:toroot ?>");
+</script><?cs 
+if:reference ?>
+<script src="<?cs var:toroot ?>assets/android-developer-reference.js" type="text/javascript"></script>
+<script src="<?cs var:toroot ?>navtree_data.js" type="text/javascript"></script><?cs 
+/if ?>
+<script src="<?cs var:toroot ?>assets/customizations.js" type="text/javascript"></script>
+<noscript>
+  <style type="text/css">
+    html,body{overflow:auto;}
+    #body-content{position:relative; top:0;}
+    #doc-content{overflow:visible;border-left:3px solid #666;}
+    #side-nav{padding:0;}
+    #side-nav .toggle-list ul {display:block;}
+    #resize-packages-nav{border-bottom:3px solid #666;}
+  </style>
+</noscript>
+</head>
diff --git a/res/assets/templates/header.cs b/res/assets/templates/header.cs
new file mode 100644
index 0000000..e8301be
--- /dev/null
+++ b/res/assets/templates/header.cs
@@ -0,0 +1,3 @@
+<?cs call:custom_masthead() ?>
+<?cs call:custom_left_nav() ?>
+
diff --git a/res/assets/templates/hierarchy.cs b/res/assets/templates/hierarchy.cs
new file mode 100644
index 0000000..a607ffd
--- /dev/null
+++ b/res/assets/templates/hierarchy.cs
@@ -0,0 +1,68 @@
+<?cs include:"macros.cs" ?>
+<html>
+<style>
+    .jd-hierarchy-spacer {
+        width: 15px;
+    }
+    .jd-hierarchy-data {
+        text-align: left;
+        vertical-align: top;
+    }
+</style>
+<?cs include:"head_tag.cs" ?>
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="jd-header">
+<h1><?cs var:page.title ?></h1>
+</div>
+
+<div id="jd-content">
+
+<div style="margin-left: 20px; margin-right: 20px;">
+
+<?cs def:hierarchy_list(classes) ?>
+<?cs each:cl = classes ?>
+<tr>
+    <?cs loop:x=#0,cl.indent,#1 ?><td class="jd-hierarchy-spacer"></td><?cs /loop ?>
+    <td class="jd-hierarchy-data" colspan="<?cs var:cl.colspan ?>">
+    <?cs if:cl.exists ?>
+        <?cs call:type_link(cl.class) ?>
+    <?cs else ?>
+        <?cs var:cl.value ?>
+    <?cs /if ?>
+    </td>
+    <td class="jd-hierarchy-data">
+    <?cs each:iface = cl.interfaces ?>
+        <?cs if:iface.exists ?>
+            <?cs call:type_link(iface.class) ?>
+        <?cs else ?>
+            <?cs var:iface.value ?>
+        <?cs /if ?> &nbsp;&nbsp;
+    <?cs /each ?>
+    &nbsp;
+    </td>
+</tr>
+<?cs call:hierarchy_list(cl.derived) ?>
+<?cs /each ?>
+<?cs /def ?>
+
+
+<table border="0" cellpadding="0" cellspacing="1">
+<th class="jd-hierarchy-data" colspan="<?cs var:colspan ?>">Class</th>
+<th class="jd-hierarchy-data">Interfaces</th>
+<?cs call:hierarchy_list(classes) ?>
+</table>
+
+</div>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
+
diff --git a/res/assets/templates/index.cs b/res/assets/templates/index.cs
new file mode 100644
index 0000000..15a6a59
--- /dev/null
+++ b/res/assets/templates/index.cs
@@ -0,0 +1,8 @@
+<html>
+<head>
+<meta http-equiv="refresh" content="0;url=packages.html">
+</head>
+<body>
+<?cs include:"analytics.cs" ?>
+</body>
+</html>
\ No newline at end of file
diff --git a/res/assets/templates/keywords.cs b/res/assets/templates/keywords.cs
new file mode 100644
index 0000000..0c8d4e3
--- /dev/null
+++ b/res/assets/templates/keywords.cs
@@ -0,0 +1,37 @@
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="jd-header">
+<h1><?cs var:page.title ?></h1>
+</div>
+
+<div id="jd-content">
+
+<div class="jd-letterlist"><?cs each:letter=keywords ?>
+    <a href="#letter_<?cs name:letter ?>"><?cs name:letter ?></a><?cs /each?>
+</div>
+
+<?cs each:letter=keywords ?>
+<a name="letter_<?cs name:letter ?>"></a>
+<h2><?cs name:letter ?></h2>
+<ul class="jd-letterentries">
+<?cs each:entry=letter
+?>  <li><a href="<?cs var:toroot ?><?cs var:entry.href ?>"><?cs var:entry.label
+        ?></a>&nbsp;<font class="jd-letterentrycomments">(<?cs var:entry.comment ?>)</font></li>
+<?cs /each
+?></ul>
+
+<?cs /each ?>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/res/assets/templates/lists.cs b/res/assets/templates/lists.cs
new file mode 100644
index 0000000..0af32b2
--- /dev/null
+++ b/res/assets/templates/lists.cs
@@ -0,0 +1,5 @@
+var DATA = [
+<?cs each:page = docs.pages
+?>      { id:<?cs var: page.id ?>, label:"<?cs var:page.label ?>", link:"<?cs var:page.link ?>", type:"<?cs var:page.type ?>" }<?cs if:!last(page) ?>,<?cs /if ?>
+<?cs /each ?>
+    ];
diff --git a/res/assets/templates/macros.cs b/res/assets/templates/macros.cs
new file mode 100644
index 0000000..265130e
--- /dev/null
+++ b/res/assets/templates/macros.cs
@@ -0,0 +1,293 @@
+<?cs # A link to a package ?><?cs 
+def:package_link(pkg) ?>
+  <a href="<?cs var:toroot ?><?cs var:pkg.link ?>"><?cs var:pkg.name ?></a><?cs 
+/def ?>
+
+<?cs # A link to a type, or not if it's a primitive type
+        link: whether to create a link at the top level, always creates links in
+              recursive invocations.
+        Expects the following fields:
+            .name
+            .link
+            .isPrimitive
+            .superBounds.N.(more links)   (... super ... & ...)
+            .extendsBounds.N.(more links) (... extends ... & ...)
+            .typeArguments.N.(more links) (< ... >)
+?><?cs 
+def:type_link_impl(type, link) ?><?cs 
+  if:type.link && link=="true" ?><?cs
+    if:type.federated ?><a href="<?cs var:type.link ?>"><?cs
+      var:type.label ?></a><?cs 
+    else ?><a href="<?cs var:toroot ?><?cs var:type.link ?>"><?cs var:type.label ?></a><?cs
+    /if ?><?cs
+  else ?><?cs var:type.label ?><?cs
+  /if ?><?cs if:subcount(type.extendsBounds) ?><?cs
+      each:t=type.extendsBounds ?><?cs
+          if:first(t) ?>&nbsp;extends&nbsp;<?cs else ?>&nbsp;&amp;&nbsp;<?cs /if ?><?cs
+          call:type_link_impl(t, "true") ?><?cs
+      /each ?><?cs
+  /if ?><?cs
+  if:subcount(type.superBounds) ?><?cs
+      each:t=type.superBounds ?><?cs
+          if:first(t) ?>&nbsp;super&nbsp;<?cs else ?>&nbsp;&amp;&nbsp;<?cs /if ?><?cs
+          call:type_link_impl(t, "true") ?><?cs
+      /each ?><?cs
+  /if ?><?cs
+  if:subcount(type.typeArguments)
+      ?>&lt;<?cs each:t=type.typeArguments ?><?cs call:type_link_impl(t, "true") ?><?cs
+          if:!last(t) ?>,&nbsp;<?cs /if ?><?cs
+      /each ?>&gt;<?cs
+  /if ?><?cs
+/def ?>
+
+<?cs def:class_name(type) ?><?cs call:type_link_impl(type, "false") ?><?cs /def ?>
+<?cs def:type_link(type) ?><?cs call:type_link_impl(type, "true") ?><?cs /def ?>
+
+<?cs # a conditional link.
+      if the "condition" parameter evals to true then the link is displayed
+      otherwise only the text is displayed
+?><?cs
+def:cond_link(text, root, path, condition) ?><?cs
+  if:condition ?><a href="<?cs var:root ?><?cs var:path ?>"><?cs /if ?><?cs var:text ?><?cs if:condition ?></a><?cs /if ?><?cs
+/def ?>
+
+
+<?cs # A comma separated parameter list ?><?cs 
+def:parameter_list(params) ?><?cs
+  each:param = params ?><?cs
+      call:type_link(param.type)?> <?cs
+      var:param.name ?><?cs
+      if: name(param)!=subcount(params)-1?>, <?cs /if ?><?cs
+  /each ?><?cs
+/def ?>
+
+<?cs # Print a list of tags (e.g. description text ?><?cs 
+def:tag_list(tags) ?><?cs
+  each:tag = tags ?><?cs
+      if:tag.name == "Text" ?><?cs var:tag.text?><?cs
+      elif:tag.kind == "@more" ?><p><?cs
+      elif:tag.kind == "@see" ?><code><a href="<?cs var:toroot ?><?cs var:tag.href ?>"><?cs var:tag.label ?></a></code><?cs
+      elif:tag.kind == "@seeHref" ?><a href="<?cs var:tag.href ?>"><?cs var:tag.label ?></a><?cs
+      elif:tag.kind == "@seeJustLabel" ?><?cs var:tag.label ?><?cs
+      elif:tag.kind == "@code" ?><code><?cs var:tag.text ?></code><?cs
+      elif:tag.kind == "@samplecode" ?><pre><?cs var:tag.text ?></pre><?cs
+      elif:tag.name == "@sample" ?><pre><?cs var:tag.text ?></pre><?cs
+      elif:tag.name == "@include" ?><?cs var:tag.text ?><?cs
+      elif:tag.kind == "@docRoot" ?><?cs var:toroot ?><?cs
+      elif:tag.kind == "@sdkCurrent" ?><?cs var:sdk.current ?><?cs
+      elif:tag.kind == "@sdkCurrentVersion" ?><?cs var:sdk.version ?><?cs
+      elif:tag.kind == "@sdkCurrentRelId" ?><?cs var:sdk.rel.id ?><?cs
+      elif:tag.kind == "@sdkPlatformVersion" ?><?cs var:sdk.platform.version ?><?cs
+      elif:tag.kind == "@sdkPlatformApiLevel" ?><?cs var:sdk.platform.apiLevel ?><?cs
+      elif:tag.kind == "@sdkPlatformMajorMinor" ?><?cs var:sdk.platform.majorMinor ?><?cs
+      elif:tag.kind == "@sdkPlatformReleaseDate" ?><?cs var:sdk.platform.releaseDate ?><?cs
+      elif:tag.kind == "@sdkPlatformDeployableDate" ?><?cs var:sdk.platform.deployableDate ?><?cs
+      elif:tag.kind == "@adtZipVersion" ?><?cs var:adt.zip.version ?><?cs
+      elif:tag.kind == "@adtZipDownload" ?><?cs var:adt.zip.download ?><?cs
+      elif:tag.kind == "@adtZipBytes" ?><?cs var:adt.zip.bytes ?><?cs
+      elif:tag.kind == "@adtZipChecksum" ?><?cs var:adt.zip.checksum ?><?cs
+      elif:tag.kind == "@inheritDoc" ?><?cs # This is the case when @inheritDoc is in something
+                                              that doesn't inherit from anything?><?cs
+      elif:tag.kind == "@attr" ?><?cs
+      else ?>{<?cs var:tag.name?> <?cs var:tag.text ?>}<?cs
+      /if ?><?cs
+  /each ?><?cs
+/def ?>
+
+<?cs # The message about This xxx is deprecated. ?><?cs 
+def:deprecated_text(kind) ?>
+  This <?cs var:kind ?> is deprecated.<?cs 
+/def ?>
+
+<?cs # Show the short-form description of something.  These come from shortDescr and deprecated ?><?cs 
+def:short_descr(obj) ?><?cs
+  if:subcount(obj.deprecated) ?>
+      <em><?cs call:deprecated_text(obj.kind) ?>
+      <?cs call:tag_list(obj.deprecated) ?></em><?cs
+  else ?><?cs call:tag_list(obj.shortDescr) ?><?cs
+  /if ?><?cs
+/def ?>
+
+<?cs # Show the red box with the deprecated warning ?><?cs 
+def:deprecated_warning(obj) ?><?cs 
+  if:subcount(obj.deprecated) ?><p>
+  <p class="caution">
+      <strong><?cs call:deprecated_text(obj.kind) ?></strong><br/> <?cs 
+      call:tag_list(obj.deprecated) ?>
+  </p><?cs 
+  /if ?><?cs 
+/def ?>
+
+<?cs # print the See Also: section ?><?cs 
+def:see_also_tags(also) ?><?cs 
+  if:subcount(also) ?>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">See Also</h5>
+      <ul class="nolist"><?cs 
+        each:tag=also ?><li><?cs
+            if:tag.kind == "@see" ?><code><a href="<?cs var:toroot ?><?cs var:tag.href ?>"><?cs
+                    var:tag.label ?></a></code><?cs
+            elif:tag.kind == "@seeHref" ?><a href="<?cs var:tag.href ?>"><?cs var:tag.label ?></a><?cs
+            elif:tag.kind == "@seeJustLabel" ?><?cs var:tag.label ?><?cs
+            else ?>[ERROR: Unknown @see kind]<?cs
+            /if ?></li><?cs 
+        /each ?>
+      </ul>
+  </div><?cs 
+  /if ?>
+<?cs /def ?>
+
+<?cs # print the API Level ?><?cs
+def:since_tags(obj) ?>
+<?cs if:reference.apilevels ?>
+  Since: <a href="<?cs var:toroot ?>guide/appendix/api-levels.html#level<?cs var:obj.since ?>">API Level <?cs var:obj.since ?></a>
+<?cs /if ?>
+<?cs /def ?>
+<?cs def:federated_refs(obj) ?>
+  <?cs if:subcount(obj.federated) ?>
+    <div>
+    Also: 
+    <?cs each:federated=obj.federated ?>
+      <a href="<?cs var:federated.url ?>"><?cs var:federated.name ?></a><?cs 
+      if:!last(federated) ?>,<?cs /if ?>
+    <?cs /each ?>
+    </div>
+  <?cs /if ?>
+<?cs /def ?>
+<?cs # Print the long-form description for something.
+       Uses the following fields: deprecated descr seeAlso since ?><?cs
+def:description(obj) ?><?cs 
+  call:deprecated_warning(obj) ?>
+  <div class="jd-tagdata jd-tagdescr"><p><?cs call:tag_list(obj.descr) ?></p></div><?cs 
+  if:subcount(obj.attrRefs) ?>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Related XML Attributes</h5>
+      <ul class="nolist"><?cs 
+        each:attr=obj.attrRefs ?>
+            <li><a href="<?cs var:toroot ?><?cs var:attr.href ?>"><?cs var:attr.name ?></a></li><?cs 
+        /each ?>
+      </ul>
+  </div><?cs 
+  /if ?><?cs 
+  if:subcount(obj.paramTags) ?>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable"><?cs 
+      each:tag=obj.paramTags ?>
+        <tr>
+          <th><?cs if:tag.isTypeParameter ?>&lt;<?cs /if ?><?cs var:tag.name
+                  ?><?cs if:tag.isTypeParameter ?>&gt;<?cs /if ?></td>
+          <td><?cs call:tag_list(tag.comment) ?></td>
+        </tr><?cs 
+      /each ?>
+      </table>
+  </div><?cs 
+  /if ?><?cs 
+  if:subcount(obj.returns) ?>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li><?cs call:tag_list(obj.returns) ?></li></ul>
+  </div><?cs 
+  /if ?><?cs 
+  if:subcount(obj.throws) ?>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Throws</h5>
+      <table class="jd-tagtable"><?cs 
+      each:tag=obj.throws ?>  
+        <tr>
+            <th><?cs call:type_link(tag.type) ?></td>
+            <td><?cs call:tag_list(tag.comment) ?></td>
+        </tr><?cs 
+      /each ?>
+      </table>
+  </div><?cs 
+  /if ?><?cs 
+  call:see_also_tags(obj.seeAlso) ?><?cs
+/def ?>
+
+<?cs # A table of links to classes with descriptions, as in a package file or the nested classes ?><?cs
+def:class_link_table(classes) ?><?cs 
+  set:count = #1 ?>
+  <table class="jd-sumtable-expando"><?cs
+      each:cl=classes ?>
+        <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.type.since ?>" >
+              <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
+              <td class="jd-descrcol" width="100%"><?cs call:short_descr(cl) ?>&nbsp;</td>
+          </tr><?cs set:count = count + #1 ?><?cs
+      /each ?>
+  </table><?cs 
+/def ?>
+
+<?cs # A list of links to classes, for use in the side navigation of classes when viewing a package (panel nav) ?><?cs 
+def:class_link_list(label, classes) ?><?cs 
+  if:subcount(classes) ?>
+    <li><h2><?cs var:label ?></h2>
+      <ul><?cs 
+      each:cl=classes ?>
+        <li class="api apilevel-<?cs var:cl.type.since ?>"><?cs call:type_link(cl.type) ?></li><?cs 
+      /each ?>
+      </ul>
+    </li><?cs 
+  /if ?><?cs 
+/def ?>
+
+<?cs # A list of links to classes, for use in the side navigation of classes when viewing a class (panel nav) ?><?cs 
+def:list(label, classes) ?><?cs 
+  if:subcount(classes) ?>
+    <li><h2><?cs var:label ?></h2>
+      <ul><?cs 
+      each:cl=classes ?>
+          <li class="<?cs if:class.name == cl.label?>selected <?cs /if ?>api apilevel-<?cs var:cl.since ?>"><?cs call:type_link(cl) ?></li><?cs 
+      /each ?>
+      </ul>
+    </li><?cs 
+  /if ?><?cs 
+/def ?>
+
+<?cs # A list of links to packages, for use in the side navigation of packages (panel nav) ?><?cs 
+def:package_link_list(packages) ?><?cs 
+  each:pkg=packages ?>
+    <li class="<?cs if:(class.package.name == pkg.name) || (package.name == pkg.name)?>selected <?cs /if ?>api apilevel-<?cs var:pkg.since ?>"><?cs call:package_link(pkg) ?></li><?cs 
+  /each ?><?cs
+/def ?>
+
+<?cs # An expando trigger ?><?cs 
+def:expando_trigger(id, default) ?>
+  <a href="#" onclick="return toggleInherited(this, null)" id="<?cs var:id ?>" class="jd-expando-trigger closed"
+          ><img id="<?cs var:id ?>-trigger"
+          src="<?cs var:toroot ?>assets/images/triangle-<?cs var:default ?>.png"
+          class="jd-expando-trigger-img" /></a><?cs 
+/def ?>
+
+<?cs # An expandable list of classes ?><?cs 
+def:expandable_class_list(id, classes, default) ?>
+  <div id="<?cs var:id ?>">
+      <div id="<?cs var:id ?>-list"
+              class="jd-inheritedlinks"
+              <?cs if:default != "list" ?>style="display: none;"<?cs /if ?>
+              >
+          <?cs if:subcount(classes) <= #20 ?>
+            <?cs each:cl=classes ?>
+              <?cs call:type_link(cl.type) ?><?cs if:!last(cl) ?>,<?cs /if ?>
+            <?cs /each ?>
+          <?cs else ?>
+            <?cs set:leftovers = subcount(classes) - #15 ?>
+            <?cs loop:i = #0, #15, #1 ?>
+              <?cs with:cl=classes[i] ?>
+                <?cs call:type_link(cl.type) ?>, <?cs  if:(#i == #15) ?>and
+                <a href="#" onclick="return toggleInherited(document.getElementById('<?cs
+                   var:id ?>', null))"><?cs var:leftovers ?> others.<?cs /if ?></a>
+              <?cs /with ?>
+            <?cs /loop ?>
+          <?cs /if ?>
+      </div>
+      <div id="<?cs var:id ?>-summary"
+              <?cs if:default != "summary" ?>style="display: none;"<?cs /if ?>
+              ><?cs 
+          call:class_link_table(classes) ?>
+      </div>
+  </div><?cs 
+/def ?>
+
+
+<?cs include:"components.cs" ?>
diff --git a/res/assets/templates/navtree_data.cs b/res/assets/templates/navtree_data.cs
new file mode 100644
index 0000000..c707232
--- /dev/null
+++ b/res/assets/templates/navtree_data.cs
@@ -0,0 +1,4 @@
+var NAVTREE_DATA =
+<?cs var:reference_tree ?>
+;
+
diff --git a/res/assets/templates/nosidenavpage.cs b/res/assets/templates/nosidenavpage.cs
new file mode 100644
index 0000000..1dec41e
--- /dev/null
+++ b/res/assets/templates/nosidenavpage.cs
@@ -0,0 +1,23 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<body class="gc-documentation">
+<a name="top"></a>
+<?cs call:custom_masthead() ?>
+
+<div id="body-content">
+<div id="doc-content" style="position:relative;">
+
+<?cs call:tag_list(root.descr) ?>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
+
+
+
diff --git a/res/assets/templates/package-descr.cs b/res/assets/templates/package-descr.cs
new file mode 100644
index 0000000..beb01c9
--- /dev/null
+++ b/res/assets/templates/package-descr.cs
@@ -0,0 +1,39 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<body class="<?cs var:package.since ?>">
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="api-info-block">
+<div class="api-level">
+  <?cs call:since_tags(package) ?>
+  <?cs call:federated_refs(package) ?>
+</div>
+</div>
+
+<div id="jd-header">
+  package
+  <h1><?cs var:package.name ?></b></h1>
+  <div class="jd-nav">
+      <a class="jd-navlink" href="package-summary.html">Classes</a> | Description
+  </div>
+</div><!-- end header -->
+
+<div id="naMessage"></div>
+
+<div id="jd-content" class="api apilevel-<?cs var:package.since ?>">
+<div class="jd-descr">
+<p><?cs call:tag_list(package.descr) ?></p>
+</div>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div> <!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/res/assets/templates/package-list.cs b/res/assets/templates/package-list.cs
new file mode 100644
index 0000000..7f0f889
--- /dev/null
+++ b/res/assets/templates/package-list.cs
@@ -0,0 +1,2 @@
+<?cs each:pkg=docs.packages ?><?cs var: pkg.name ?>
+<?cs /each ?>
diff --git a/res/assets/templates/package.cs b/res/assets/templates/package.cs
new file mode 100644
index 0000000..bb53cee
--- /dev/null
+++ b/res/assets/templates/package.cs
@@ -0,0 +1,60 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<body class="<?cs var:package.since ?>">
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="api-info-block">
+<div class="api-level">
+  <?cs call:since_tags(package) ?>
+  <?cs call:federated_refs(package) ?>
+</div>
+</div>
+
+<div id="jd-header">
+  package
+  <h1><?cs var:package.name ?></h1>
+  <div class="jd-nav">
+      <?cs if:subcount(package.shortDescr) ?>
+        Classes | <a class="jd-navlink" href="package-descr.html">Description</a>
+      <?cs /if ?>
+  </div>
+</div><!-- end header -->
+
+<div id="naMessage"></div>
+
+<div id="jd-content" class="api apilevel-<?cs var:package.since ?>">
+
+<?cs if:subcount(package.shortDescr) ?>
+  <div class="jd-descr">
+  <p><?cs call:tag_list(package.shortDescr) ?></p>
+  <p><span class="jd-more"><a href="package-descr.html">more...</a></span></p>
+  </div>
+<?cs /if ?>
+
+<?cs def:class_table(label, classes) ?>
+  <?cs if:subcount(classes) ?>
+    <h3><?cs var:label ?></h3>
+    <div class="jd-sumtable">
+    <?cs call:class_link_table(classes) ?>
+    </div>
+  <?cs /if ?>
+<?cs /def ?>
+
+<?cs call:class_table("Interfaces", package.interfaces) ?>
+<?cs call:class_table("Classes", package.classes) ?>
+<?cs call:class_table("Enums", package.enums) ?>
+<?cs call:class_table("Exceptions", package.exceptions) ?>
+<?cs call:class_table("Errors", package.errors) ?>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div><!-- doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/res/assets/templates/packages.cs b/res/assets/templates/packages.cs
new file mode 100644
index 0000000..c2d8c75
--- /dev/null
+++ b/res/assets/templates/packages.cs
@@ -0,0 +1,38 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<body class="gc-documentation">
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="jd-header">
+<h1><?cs var:page.title ?></h1>
+</div>
+
+<div id="jd-content">
+
+<div class="jd-descr">
+<p><?cs call:tag_list(root.descr) ?></p>
+</div>
+
+<?cs set:count = #1 ?>
+<table class="jd-sumtable">
+<?cs each:pkg = docs.packages ?>
+    <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:pkg.since ?>" >
+        <td class="jd-linkcol"><?cs call:package_link(pkg) ?></td>
+        <td class="jd-descrcol" width="100%"><?cs call:tag_list(pkg.shortDescr) ?>&nbsp;</td>
+    </tr>
+<?cs set:count = count + #1 ?>
+<?cs /each ?>
+</table>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div> <!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/res/assets/templates/sample.cs b/res/assets/templates/sample.cs
new file mode 100644
index 0000000..7979b2a
--- /dev/null
+++ b/res/assets/templates/sample.cs
@@ -0,0 +1,32 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<?cs set:resources="true" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<?cs include:"header.cs" ?>
+<body class="gc-documentation">
+
+
+<a name="top"></a>
+<div class="g-unit" id="doc-content">
+ <div id="jd-header" class="guide-header">
+  <span class="crumb">&nbsp;</span>
+  <h1><?cs var:page.title ?></h1>
+ </div>
+
+<div id="jd-content">
+
+<p>The file containing the source code shown below is located in the corresponding directory in <code>&lt;sdk&gt;/platforms/android-&lt;version&gt;/samples/...</code></p>
+
+<!-- begin file contents -->
+<pre><?cs var:fileContents ?></pre>
+<!-- end file contents -->
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div> <!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/res/assets/templates/sampleindex.cs b/res/assets/templates/sampleindex.cs
new file mode 100644
index 0000000..8a75298
--- /dev/null
+++ b/res/assets/templates/sampleindex.cs
@@ -0,0 +1,64 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<?cs set:resources="true" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<?cs include:"header.cs" ?>
+<body class="gc-documentation">
+
+
+<a name="top"></a>
+<div class="g-unit" id="doc-content">
+ <div id="jd-header" class="guide-header">
+  <span class="crumb">&nbsp;</span>
+  <h1><?cs var:page.title ?></h1>
+ </div>
+
+<div id="jd-content">
+
+<?cs var:summary ?>
+
+<?cs if:android.whichdoc == "online" ?><?cs
+  # If this is the online docs, build the src code navigation links ?>
+
+  <?cs if:subcount(subdirs) ?>
+      <h2>Subdirectories</h2>
+      <ul class="nolist">
+      <?cs each:dir=subdirs ?>
+        <li><a href="<?cs var:dir.name ?>/index.html"><?cs
+          var:dir.name ?>/</a></li>
+      <?cs /each ?>
+      </ul>
+  <?cs /if ?>
+
+  <?cs if:subcount(files) ?>
+      <h2>Files</h2>
+      <ul class="nolist">
+      <?cs each:file=files ?>
+        <li><a href="<?cs var:file.href ?>"><?cs
+          var:file.name ?></a></li>
+      <?cs /each ?>
+      </ul>
+  <?cs /if ?>
+
+<?cs else ?><?cs
+  # else, this means it's offline docs,
+          so don't show src links (we don't have the pages!) ?>
+
+<p>You can find the source code for this sample in your SDK at:</p>
+<p style="margin-left:2em">
+<code><em>&lt;sdk&gt;</em>/platforms/android-<em>&lt;version&gt;</em>/samples/</code>
+</p>
+
+<?cs /if ?><?cs # end if/else online docs ?>
+
+</div><!-- end jd-content -->
+
+<?cs include:"footer.cs" ?>
+
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/res/assets/templates/todo.cs b/res/assets/templates/todo.cs
new file mode 100644
index 0000000..e9f7237
--- /dev/null
+++ b/res/assets/templates/todo.cs
@@ -0,0 +1,99 @@
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <title><?cs var:page.title ?></title>
+    <style type="text/css">
+    table {
+        border-width: 1px 1px 1px 1px;
+        border-spacing: 0px;
+        border-style: solid solid solid solid;
+        border-color: black black black black;
+        border-collapse: collapse;
+        background-color: white;
+    }
+    table th {
+        border-width: 1px 1px 1px 1px;
+        padding: 1px 4px 1px 3px;
+        border-style: inset inset inset inset;
+        border-color: gray gray gray gray;
+        background-color: white;
+    }
+    table td {
+        border-width: 1px 1px 1px 1px;
+        padding: 1px 4px 1px 3px;
+        border-style: inset inset inset inset;
+        border-color: gray gray gray gray;
+        background-color: white;
+    }
+    </style>
+</head>
+<body>
+<h1><?cs var:page.title ?></h1>
+
+<h2>Overall</h2>
+<table>
+<tr><th>Errors</th><td><?cs var:all.errorCount ?></td></tr>
+<tr><th>Percent Good</th><td><?cs var:all.percentGood ?></td></tr>
+<tr><th>Total Comments</th><td><?cs var:all.totalCount ?></td></tr>
+</table>
+
+<h2>Package Summary</h2>
+
+<table>
+<tr>
+    <th>Package</th>
+    <th>Errors</th>
+    <th>Percent Good</th>
+    <th>Total</th>
+</tr>
+<?cs each:pkg=packages ?>
+<tr>
+    <td><?cs var:pkg.name ?></td>
+    <td><?cs var:pkg.errorCount ?></td>
+    <td><?cs var:pkg.percentGood ?></td>
+    <td><?cs var:pkg.totalCount ?></td>
+</tr>
+<?cs /each ?>
+</table>
+
+
+<h2>Class Summary</h3>
+
+<table>
+<tr>
+    <th>Class</th>
+    <th>Errors</th>
+    <th>Percent Good</th>
+    <th>Total</th>
+</tr>
+<?cs each:cl=classes ?>
+<tr>
+    <td><a href="#class_<?cs var:cl.qualified ?>"><?cs var:cl.qualified ?></a></td>
+    <td><?cs var:cl.errorCount ?></td>
+    <td><?cs var:cl.percentGood ?></td>
+    <td><?cs var:cl.totalCount ?></td>
+</tr>
+<?cs /each ?>
+</table>
+
+<h2>Detail</h2>
+
+<?cs each:cl=classes ?>
+<h3><a name="class_<?cs var:cl.qualified ?>"><?cs var:cl.qualified ?></a></h3>
+<p>Errors: <?cs var:cl.errorCount ?><br/>
+Total: <?cs var:cl.totalCount ?><br/>
+Percent Good: <?cs var:cl.percentGood ?></p>
+<table>
+<?cs each:err=cl.errors ?>
+<tr>
+    <td><?cs var:err.pos ?></td>
+    <td><?cs var:err.name ?></td>
+    <td><?cs var:err.descr ?></td>
+</tr>
+<?cs /each ?>
+</table>
+
+<?cs /each ?>
+
+</body>
+</html>
diff --git a/res/assets/templates/trailer.cs b/res/assets/templates/trailer.cs
new file mode 100644
index 0000000..f599284
--- /dev/null
+++ b/res/assets/templates/trailer.cs
@@ -0,0 +1,5 @@
+</div> <!-- end body-content --> <?cs # normally opened by header.cs ?>
+
+<script type="text/javascript">
+init(); /* initialize android-developer-docs.js */
+</script>
\ No newline at end of file
diff --git a/src/MANIFEST.mf b/src/MANIFEST.mf
new file mode 100644
index 0000000..5e4d34a
--- /dev/null
+++ b/src/MANIFEST.mf
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: com.google.doclava.apicheck.ApiCheck
\ No newline at end of file
diff --git a/src/com/google/doclava/AnnotationInstanceInfo.java b/src/com/google/doclava/AnnotationInstanceInfo.java
new file mode 100644
index 0000000..bb498d7
--- /dev/null
+++ b/src/com/google/doclava/AnnotationInstanceInfo.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+public class AnnotationInstanceInfo {
+  private ClassInfo mType;
+  private AnnotationValueInfo[] mElementValues;
+
+  public AnnotationInstanceInfo(ClassInfo type, AnnotationValueInfo[] elementValues) {
+    mType = type;
+    mElementValues = elementValues;
+  }
+
+  ClassInfo type() {
+    return mType;
+  }
+
+  AnnotationValueInfo[] elementValues() {
+    return mElementValues;
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder str = new StringBuilder();
+    str.append("@");
+    str.append(mType.qualifiedName());
+    str.append("(");
+    AnnotationValueInfo[] values = mElementValues;
+    final int N = values.length;
+    for (int i = 0; i < N; i++) {
+      AnnotationValueInfo value = values[i];
+      str.append(value.element().name());
+      str.append("=");
+      str.append(value.valueString());
+      if (i != N - 1) {
+        str.append(",");
+      }
+    }
+    str.append(")");
+    return str.toString();
+  }
+}
diff --git a/src/com/google/doclava/AnnotationValueInfo.java b/src/com/google/doclava/AnnotationValueInfo.java
new file mode 100644
index 0000000..2022a59
--- /dev/null
+++ b/src/com/google/doclava/AnnotationValueInfo.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+public class AnnotationValueInfo {
+  private Object mValue;
+  private String mString;
+  private MethodInfo mElement;
+
+  public AnnotationValueInfo(MethodInfo element) {
+    mElement = element;
+  }
+
+  public void init(Object value) {
+    mValue = value;
+  }
+
+  public MethodInfo element() {
+    return mElement;
+  }
+
+  public Object value() {
+    return mValue;
+  }
+
+  public String valueString() {
+    Object v = mValue;
+    if (v instanceof TypeInfo) {
+      return ((TypeInfo) v).fullName();
+    } else if (v instanceof FieldInfo) {
+      StringBuilder str = new StringBuilder();
+      FieldInfo f = (FieldInfo) v;
+      str.append(f.containingClass().qualifiedName());
+      str.append('.');
+      str.append(f.name());
+      return str.toString();
+    } else if (v instanceof AnnotationInstanceInfo) {
+      return v.toString();
+    } else if (v instanceof AnnotationValueInfo[]) {
+      StringBuilder str = new StringBuilder();
+      AnnotationValueInfo[] array = (AnnotationValueInfo[]) v;
+      final int N = array.length;
+      str.append("{");
+      for (int i = 0; i < array.length; i++) {
+        str.append(array[i].valueString());
+        if (i != N - 1) {
+          str.append(",");
+        }
+      }
+      str.append("}");
+      return str.toString();
+    } else {
+      return FieldInfo.constantLiteralValue(v);
+    }
+  }
+}
diff --git a/src/com/google/doclava/AttrTagInfo.java b/src/com/google/doclava/AttrTagInfo.java
new file mode 100644
index 0000000..909cacf
--- /dev/null
+++ b/src/com/google/doclava/AttrTagInfo.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+public class AttrTagInfo extends TagInfo {
+  private static final String REF_COMMAND = "ref";
+  private static final String NAME_COMMAND = "name";
+  private static final String DESCRIPTION_COMMAND = "description";
+  private static final Pattern TEXT = Pattern.compile("(\\S+)\\s*(.*)", Pattern.DOTALL);
+  private static final Pattern NAME_TEXT = Pattern.compile("(\\S+)(.*)", Pattern.DOTALL);
+
+  private ContainerInfo mBase;
+  private String mCommand;
+
+  // if mCommand == "ref"
+  private FieldInfo mRefField;
+  private AttributeInfo mAttrInfo;
+
+  // if mCommand == "name"
+  private String mAttrName;
+
+  // if mCommand == "description"
+  private Comment mDescrComment;
+
+  AttrTagInfo(String name, String kind, String text, ContainerInfo base, SourcePositionInfo position) {
+    super(name, kind, text, position);
+    mBase = base;
+
+    parse(text, base, position);
+  }
+
+  void parse(String text, ContainerInfo base, SourcePositionInfo position) {
+    Matcher m;
+
+    m = TEXT.matcher(text);
+    if (!m.matches()) {
+      Errors.error(Errors.BAD_ATTR_TAG, position, "Bad @attr tag: " + text);
+      return;
+    }
+
+    String command = m.group(1);
+    String more = m.group(2);
+
+    if (REF_COMMAND.equals(command)) {
+      String ref = more.trim();
+      LinkReference linkRef = LinkReference.parse(ref, mBase, position, false);
+      if (!linkRef.good) {
+        Errors.error(Errors.BAD_ATTR_TAG, position, "Unresolved @attr ref: " + ref);
+        return;
+      }
+      if (!(linkRef.memberInfo instanceof FieldInfo)) {
+        Errors.error(Errors.BAD_ATTR_TAG, position, "@attr must be a field: " + ref);
+        return;
+      }
+      mCommand = command;
+      mRefField = (FieldInfo) linkRef.memberInfo;
+    } else if (NAME_COMMAND.equals(command)) {
+      m = NAME_TEXT.matcher(more);
+      if (!m.matches() || m.group(2).trim().length() != 0) {
+        Errors.error(Errors.BAD_ATTR_TAG, position, "Bad @attr name tag: " + more);
+        return;
+      }
+      mCommand = command;
+      mAttrName = m.group(1);
+    } else if (DESCRIPTION_COMMAND.equals(command)) {
+      mCommand = command;
+      mDescrComment = new Comment(more, base, position);
+    } else {
+      Errors.error(Errors.BAD_ATTR_TAG, position, "Bad @attr command: " + command);
+    }
+  }
+
+  public FieldInfo reference() {
+    return REF_COMMAND.equals(mCommand) ? mRefField : null;
+  }
+
+  @Override
+  public String name() {
+    return NAME_COMMAND.equals(mCommand) ? mAttrName : null;
+  }
+
+  public Comment description() {
+    return DESCRIPTION_COMMAND.equals(mCommand) ? mDescrComment : null;
+  }
+
+  @Override
+  public void makeHDF(Data data, String base) {
+    super.makeHDF(data, base);
+  }
+
+  public void setAttribute(AttributeInfo info) {
+    mAttrInfo = info;
+  }
+
+  public static void makeReferenceHDF(Data data, String base, AttrTagInfo[] tags) {
+    int i = 0;
+    for (AttrTagInfo t : tags) {
+      if (REF_COMMAND.equals(t.mCommand)) {
+        if (t.mAttrInfo == null) {
+          String msg = "ERROR: unlinked attr: " + t.mRefField.name();
+          if (false) {
+            System.out.println(msg);
+          } else {
+            throw new RuntimeException(msg);
+          }
+        } else {
+          data.setValue(base + "." + i + ".name", t.mAttrInfo.name());
+          data.setValue(base + "." + i + ".href", t.mAttrInfo.htmlPage());
+          i++;
+        }
+      }
+    }
+  }
+
+}
diff --git a/src/com/google/doclava/AttributeInfo.java b/src/com/google/doclava/AttributeInfo.java
new file mode 100644
index 0000000..25d424f
--- /dev/null
+++ b/src/com/google/doclava/AttributeInfo.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+
+public class AttributeInfo {
+  public static final Comparator<AttributeInfo> comparator = new Comparator<AttributeInfo>() {
+    public int compare(AttributeInfo a, AttributeInfo b) {
+      return a.name().compareTo(b.name());
+    }
+  };
+
+  public FieldInfo attrField;
+  public ArrayList<MethodInfo> methods = new ArrayList<MethodInfo>();
+
+  private ClassInfo mClass;
+  private String mName;
+  private Comment mComment;
+
+  public AttributeInfo(ClassInfo cl, FieldInfo f) {
+    mClass = cl;
+    attrField = f;
+  }
+
+  public String name() {
+    if (mName == null) {
+      for (AttrTagInfo comment : attrField.comment().attrTags()) {
+        String n = comment.name();
+        if (n != null) {
+          mName = n;
+          return n;
+        }
+      }
+    }
+    return mName;
+  }
+
+  public Comment comment() {
+    if (mComment == null) {
+      for (AttrTagInfo attr : attrField.comment().attrTags()) {
+        Comment c = attr.description();
+        if (c != null) {
+          mComment = c;
+          return c;
+        }
+      }
+    }
+    if (mComment == null) {
+      return new Comment("", mClass, SourcePositionInfo.UNKNOWN);
+    }
+    return mComment;
+  }
+
+  public String anchor() {
+    return "attr_" + name();
+  }
+
+  public String htmlPage() {
+    return mClass.htmlPage() + "#" + anchor();
+  }
+
+  public void makeHDF(Data data, String base) {
+    data.setValue(base + ".name", name());
+    data.setValue(base + ".anchor", anchor());
+    data.setValue(base + ".href", htmlPage());
+    data.setValue(base + ".R.name", attrField.name());
+    data.setValue(base + ".R.href", attrField.htmlPage());
+    TagInfo.makeHDF(data, base + ".deprecated", attrField.comment().deprecatedTags());
+    TagInfo.makeHDF(data, base + ".shortDescr", comment().briefTags());
+    TagInfo.makeHDF(data, base + ".descr", comment().tags());
+
+    int i = 0;
+    for (MethodInfo m : methods) {
+      String s = base + ".methods." + i;
+      data.setValue(s + ".href", m.htmlPage());
+      data.setValue(s + ".name", m.prettySignature());
+    }
+  }
+
+  public boolean checkLevel() {
+    return attrField.checkLevel();
+  }
+}
diff --git a/src/com/google/doclava/ClassInfo.java b/src/com/google/doclava/ClassInfo.java
new file mode 100644
index 0000000..77863fd
--- /dev/null
+++ b/src/com/google/doclava/ClassInfo.java
@@ -0,0 +1,1716 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+import com.google.doclava.apicheck.ApiInfo;
+
+import com.sun.javadoc.*;
+import java.util.*;
+
+public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Scoped {
+  public static final Comparator<ClassInfo> comparator = new Comparator<ClassInfo>() {
+    public int compare(ClassInfo a, ClassInfo b) {
+      return a.name().compareTo(b.name());
+    }
+  };
+
+  public static final Comparator<ClassInfo> qualifiedComparator = new Comparator<ClassInfo>() {
+    public int compare(ClassInfo a, ClassInfo b) {
+      return a.qualifiedName().compareTo(b.qualifiedName());
+    }
+  };
+  
+  /**
+   * Constructs a stub representation of a class.
+   */
+  public ClassInfo(String qualifiedName) {
+    super("", SourcePositionInfo.UNKNOWN);
+    
+    mQualifiedName = qualifiedName;
+    if (qualifiedName.lastIndexOf('.') != -1) {
+      mName = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
+    } else {
+      mName = qualifiedName;
+    }
+  }
+
+  public ClassInfo(ClassDoc cl, String rawCommentText, SourcePositionInfo position,
+      boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate,
+      boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass,
+      boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal,
+      boolean isIncluded, String name, String qualifiedName, String qualifiedTypeName,
+      boolean isPrimitive) {
+    super(rawCommentText, position);
+
+    mClass = cl;
+    mIsPublic = isPublic;
+    mIsProtected = isProtected;
+    mIsPackagePrivate = isPackagePrivate;
+    mIsPrivate = isPrivate;
+    mIsStatic = isStatic;
+    mIsInterface = isInterface;
+    mIsAbstract = isAbstract;
+    mIsOrdinaryClass = isOrdinaryClass;
+    mIsException = isException;
+    mIsError = isError;
+    mIsEnum = isEnum;
+    mIsAnnotation = isAnnotation;
+    mIsFinal = isFinal;
+    mIsIncluded = isIncluded;
+    mName = name;
+    mQualifiedName = qualifiedName;
+    mQualifiedTypeName = qualifiedTypeName;
+    mIsPrimitive = isPrimitive;
+    mNameParts = name.split("\\.");
+  }
+
+  public void init(TypeInfo typeInfo, ClassInfo[] interfaces, TypeInfo[] interfaceTypes,
+      ClassInfo[] innerClasses, MethodInfo[] constructors, MethodInfo[] methods,
+      MethodInfo[] annotationElements, FieldInfo[] fields, FieldInfo[] enumConstants,
+      PackageInfo containingPackage, ClassInfo containingClass, ClassInfo superclass,
+      TypeInfo superclassType, AnnotationInstanceInfo[] annotations) {
+    mTypeInfo = typeInfo;
+    mRealInterfaces = new ArrayList<ClassInfo>();
+    for (ClassInfo cl : interfaces) {
+      mRealInterfaces.add(cl);
+    }
+    mRealInterfaceTypes = interfaceTypes;
+    mInnerClasses = innerClasses;
+    mAllConstructors = constructors;
+    mAllSelfMethods = methods;
+    mAnnotationElements = annotationElements;
+    mAllSelfFields = fields;
+    mEnumConstants = enumConstants;
+    mContainingPackage = containingPackage;
+    mContainingClass = containingClass;
+    mRealSuperclass = superclass;
+    mRealSuperclassType = superclassType;
+    mAnnotations = annotations;
+
+    // after providing new methods and new superclass info,clear any cached
+    // lists of self + superclass methods, ctors, etc.
+    mSuperclassInit = false;
+    mConstructors = null;
+    mMethods = null;
+    mSelfMethods = null;
+    mFields = null;
+    mSelfFields = null;
+    mSelfAttributes = null;
+    mDeprecatedKnown = false;
+
+    Arrays.sort(mEnumConstants, FieldInfo.comparator);
+    Arrays.sort(mInnerClasses, ClassInfo.comparator);
+  }
+
+  public void init2() {
+    // calling this here forces the AttrTagInfo objects to be linked to the AttribtueInfo
+    // objects
+    selfAttributes();
+  }
+
+  public void init3(TypeInfo[] types, ClassInfo[] realInnerClasses) {
+    mTypeParameters = types;
+    mRealInnerClasses = realInnerClasses;
+  }
+
+  public ClassInfo[] getRealInnerClasses() {
+    return mRealInnerClasses;
+  }
+
+  public TypeInfo[] getTypeParameters() {
+    return mTypeParameters;
+  }
+
+  public boolean checkLevel() {
+    int val = mCheckLevel;
+    if (val >= 0) {
+      return val != 0;
+    } else {
+      boolean v =
+          Doclava.checkLevel(mIsPublic, mIsProtected, mIsPackagePrivate, mIsPrivate, isHidden());
+      mCheckLevel = v ? 1 : 0;
+      return v;
+    }
+  }
+
+  public int compareTo(Object that) {
+    if (that instanceof ClassInfo) {
+      return mQualifiedName.compareTo(((ClassInfo) that).mQualifiedName);
+    } else {
+      return this.hashCode() - that.hashCode();
+    }
+  }
+
+  @Override
+  public ContainerInfo parent() {
+    return this;
+  }
+
+  public boolean isPublic() {
+    return mIsPublic;
+  }
+
+  public boolean isProtected() {
+    return mIsProtected;
+  }
+
+  public boolean isPackagePrivate() {
+    return mIsPackagePrivate;
+  }
+
+  public boolean isPrivate() {
+    return mIsPrivate;
+  }
+
+  public boolean isStatic() {
+    return mIsStatic;
+  }
+
+  public boolean isInterface() {
+    return mIsInterface;
+  }
+
+  public boolean isAbstract() {
+    return mIsAbstract;
+  }
+
+  public PackageInfo containingPackage() {
+    return mContainingPackage;
+  }
+
+  public ClassInfo containingClass() {
+    return mContainingClass;
+  }
+
+  public boolean isOrdinaryClass() {
+    return mIsOrdinaryClass;
+  }
+
+  public boolean isException() {
+    return mIsException;
+  }
+
+  public boolean isError() {
+    return mIsError;
+  }
+
+  public boolean isEnum() {
+    return mIsEnum;
+  }
+
+  public boolean isAnnotation() {
+    return mIsAnnotation;
+  }
+
+  public boolean isFinal() {
+    return mIsFinal;
+  }
+
+  public boolean isIncluded() {
+    return mIsIncluded;
+  }
+
+  public HashSet<String> typeVariables() {
+    HashSet<String> result = TypeInfo.typeVariables(mTypeInfo.typeArguments());
+    ClassInfo cl = containingClass();
+    while (cl != null) {
+      TypeInfo[] types = cl.asTypeInfo().typeArguments();
+      if (types != null) {
+        TypeInfo.typeVariables(types, result);
+      }
+      cl = cl.containingClass();
+    }
+    return result;
+  }
+
+  private static void gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces) {
+    for (ClassInfo iface : cl.mRealInterfaces) {
+      if (iface.checkLevel()) {
+        interfaces.add(iface);
+      } else {
+        gatherHiddenInterfaces(iface, interfaces);
+      }
+    }
+  }
+
+  public ClassInfo[] interfaces() {
+    if (mInterfaces == null) {
+      if (checkLevel()) {
+        HashSet<ClassInfo> interfaces = new HashSet<ClassInfo>();
+        ClassInfo superclass = mRealSuperclass;
+        while (superclass != null && !superclass.checkLevel()) {
+          gatherHiddenInterfaces(superclass, interfaces);
+          superclass = superclass.mRealSuperclass;
+        }
+        gatherHiddenInterfaces(this, interfaces);
+        mInterfaces = interfaces.toArray(new ClassInfo[interfaces.size()]);
+      } else {
+        // put something here in case someone uses it
+        mInterfaces = new ClassInfo[mRealInterfaces.size()];
+        mRealInterfaces.toArray(mInterfaces);
+      }
+      Arrays.sort(mInterfaces, ClassInfo.qualifiedComparator);
+    }
+    return mInterfaces;
+  }
+
+  public ClassInfo[] realInterfaces() {
+    ClassInfo[] classInfos = new ClassInfo[mRealInterfaces.size()];
+    return mRealInterfaces.toArray(classInfos);
+  }
+
+  TypeInfo[] realInterfaceTypes() {
+    return mRealInterfaceTypes;
+  }
+
+  public String name() {
+    return mName;
+  }
+
+  public String[] nameParts() {
+    return mNameParts;
+  }
+
+  public String leafName() {
+    return mNameParts[mNameParts.length - 1];
+  }
+
+  public String qualifiedName() {
+    return mQualifiedName;
+  }
+
+  public String qualifiedTypeName() {
+    return mQualifiedTypeName;
+  }
+
+  public boolean isPrimitive() {
+    return mIsPrimitive;
+  }
+
+  public MethodInfo[] allConstructors() {
+    return mAllConstructors;
+  }
+
+  public MethodInfo[] constructors() {
+    if (mConstructors == null) {
+      MethodInfo[] methods = mAllConstructors;
+      ArrayList<MethodInfo> ctors = new ArrayList<MethodInfo>();
+      for (int i = 0; i < methods.length; i++) {
+        MethodInfo m = methods[i];
+        if (!m.isHidden()) {
+          ctors.add(m);
+        }
+      }
+      mConstructors = ctors.toArray(new MethodInfo[ctors.size()]);
+      Arrays.sort(mConstructors, MethodInfo.comparator);
+    }
+    return mConstructors;
+  }
+
+  public ClassInfo[] innerClasses() {
+    return mInnerClasses;
+  }
+
+  public TagInfo[] inlineTags() {
+    return comment().tags();
+  }
+
+  public TagInfo[] firstSentenceTags() {
+    return comment().briefTags();
+  }
+
+  public boolean isDeprecated() {
+    boolean deprecated = false;
+    if (!mDeprecatedKnown) {
+      boolean commentDeprecated = comment().isDeprecated();
+      boolean annotationDeprecated = false;
+      for (AnnotationInstanceInfo annotation : annotations()) {
+        if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) {
+          annotationDeprecated = true;
+          break;
+        }
+      }
+
+      if (commentDeprecated != annotationDeprecated) {
+        Errors.error(Errors.DEPRECATION_MISMATCH, position(), "Class " + qualifiedName()
+            + ": @Deprecated annotation and @deprecated comment do not match");
+      }
+
+      mIsDeprecated = commentDeprecated | annotationDeprecated;
+      mDeprecatedKnown = true;
+    }
+    return mIsDeprecated;
+  }
+
+  public TagInfo[] deprecatedTags() {
+    // Should we also do the interfaces?
+    return comment().deprecatedTags();
+  }
+
+  public MethodInfo[] methods() {
+    if (mMethods == null) {
+      TreeMap<String, MethodInfo> all = new TreeMap<String, MethodInfo>();
+
+      ClassInfo[] ifaces = interfaces();
+      for (ClassInfo iface : ifaces) {
+        if (iface != null) {
+          MethodInfo[] inhereted = iface.methods();
+          for (MethodInfo method : inhereted) {
+            String key = method.getHashableName();
+            all.put(key, method);
+          }
+        }
+      }
+
+      ClassInfo superclass = superclass();
+      if (superclass != null) {
+        MethodInfo[] inhereted = superclass.methods();
+        for (MethodInfo method : inhereted) {
+          String key = method.getHashableName();
+          all.put(key, method);
+        }
+      }
+
+      MethodInfo[] methods = selfMethods();
+      for (MethodInfo method : methods) {
+        String key = method.getHashableName();
+        all.put(key, method);
+      }
+
+      mMethods = all.values().toArray(new MethodInfo[all.size()]);
+      Arrays.sort(mMethods, MethodInfo.comparator);
+    }
+    return mMethods;
+  }
+
+  public MethodInfo[] annotationElements() {
+    return mAnnotationElements;
+  }
+
+  public AnnotationInstanceInfo[] annotations() {
+    return mAnnotations;
+  }
+
+  private static void addFields(ClassInfo cl, TreeMap<String, FieldInfo> all) {
+    FieldInfo[] fields = cl.fields();
+    int N = fields.length;
+    for (int i = 0; i < N; i++) {
+      FieldInfo f = fields[i];
+      all.put(f.name(), f);
+    }
+  }
+
+  public FieldInfo[] fields() {
+    if (mFields == null) {
+      int N;
+      TreeMap<String, FieldInfo> all = new TreeMap<String, FieldInfo>();
+
+      ClassInfo[] interfaces = interfaces();
+      N = interfaces.length;
+      for (int i = 0; i < N; i++) {
+        addFields(interfaces[i], all);
+      }
+
+      ClassInfo superclass = superclass();
+      if (superclass != null) {
+        addFields(superclass, all);
+      }
+
+      FieldInfo[] fields = selfFields();
+      N = fields.length;
+      for (int i = 0; i < N; i++) {
+        FieldInfo f = fields[i];
+        if (!f.isHidden()) {
+          String key = f.name();
+          all.put(key, f);
+        }
+      }
+
+      mFields = all.values().toArray(new FieldInfo[0]);
+    }
+    return mFields;
+  }
+
+  public void gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String, FieldInfo> fields) {
+    FieldInfo[] flds = cl.selfFields();
+    for (FieldInfo f : flds) {
+      if (f.checkLevel()) {
+        fields.put(f.name(), f.cloneForClass(owner));
+      }
+    }
+  }
+
+  public FieldInfo[] selfFields() {
+    if (mSelfFields == null) {
+      HashMap<String, FieldInfo> fields = new HashMap<String, FieldInfo>();
+      // our hidden parents
+      if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) {
+        gatherFields(this, mRealSuperclass, fields);
+      }
+      for (ClassInfo iface : mRealInterfaces) {
+        if (!iface.checkLevel()) {
+          gatherFields(this, iface, fields);
+        }
+      }
+      // mine
+      FieldInfo[] selfFields = mAllSelfFields;
+      for (int i = 0; i < selfFields.length; i++) {
+        FieldInfo f = selfFields[i];
+        if (!f.isHidden()) {
+          fields.put(f.name(), f);
+        }
+      }
+      // combine and return in
+      mSelfFields = fields.values().toArray(new FieldInfo[fields.size()]);
+      Arrays.sort(mSelfFields, FieldInfo.comparator);
+    }
+    return mSelfFields;
+  }
+
+  public FieldInfo[] allSelfFields() {
+    return mAllSelfFields;
+  }
+
+  private void gatherMethods(ClassInfo owner, ClassInfo cl, HashMap<String, MethodInfo> methods) {
+    MethodInfo[] meth = cl.selfMethods();
+    for (MethodInfo m : meth) {
+      if (m.checkLevel()) {
+        methods.put(m.name() + m.signature(), m.cloneForClass(owner));
+      }
+    }
+  }
+
+  public MethodInfo[] selfMethods() {
+    if (mSelfMethods == null) {
+      HashMap<String, MethodInfo> methods = new HashMap<String, MethodInfo>();
+      // our hidden parents
+      if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) {
+        gatherMethods(this, mRealSuperclass, methods);
+      }
+      for (ClassInfo iface : mRealInterfaces) {
+        if (!iface.checkLevel()) {
+          gatherMethods(this, iface, methods);
+        }
+      }
+      // mine
+      if (mAllSelfMethods != null) {
+        for (int i = 0; i < mAllSelfMethods.length; i++) {
+          MethodInfo m = mAllSelfMethods[i];
+          if (m.checkLevel()) {
+            methods.put(m.name() + m.signature(), m);
+          }
+        }
+      }
+      
+      // combine and return it
+      mSelfMethods = methods.values().toArray(new MethodInfo[methods.size()]);
+      Arrays.sort(mSelfMethods, MethodInfo.comparator);
+    }
+    return mSelfMethods;
+  }
+
+  public MethodInfo[] allSelfMethods() {
+    return mAllSelfMethods;
+  }
+
+  public void addMethod(MethodInfo method) {
+    mApiCheckMethods.put(method.getHashableName(), method);
+    
+    if (mAllSelfMethods == null) {
+      mAllSelfMethods = new MethodInfo[] { method };
+      return;
+    }
+    
+    MethodInfo[] methods = new MethodInfo[mAllSelfMethods.length + 1];
+    int i = 0;
+    for (MethodInfo m : mAllSelfMethods) {
+      methods[i++] = m;
+    }
+    methods[i] = method;
+    mAllSelfMethods = methods;
+  }
+  
+  public void setContainingPackage(PackageInfo pkg) {
+    mContainingPackage = pkg;
+  }
+
+  public AttributeInfo[] selfAttributes() {
+    if (mSelfAttributes == null) {
+      TreeMap<FieldInfo, AttributeInfo> attrs = new TreeMap<FieldInfo, AttributeInfo>();
+
+      // the ones in the class comment won't have any methods
+      for (AttrTagInfo tag : comment().attrTags()) {
+        FieldInfo field = tag.reference();
+        if (field != null) {
+          AttributeInfo attr = attrs.get(field);
+          if (attr == null) {
+            attr = new AttributeInfo(this, field);
+            attrs.put(field, attr);
+          }
+          tag.setAttribute(attr);
+        }
+      }
+
+      // in the methods
+      for (MethodInfo m : selfMethods()) {
+        for (AttrTagInfo tag : m.comment().attrTags()) {
+          FieldInfo field = tag.reference();
+          if (field != null) {
+            AttributeInfo attr = attrs.get(field);
+            if (attr == null) {
+              attr = new AttributeInfo(this, field);
+              attrs.put(field, attr);
+            }
+            tag.setAttribute(attr);
+            attr.methods.add(m);
+          }
+        }
+      }
+
+      // constructors too
+      for (MethodInfo m : constructors()) {
+        for (AttrTagInfo tag : m.comment().attrTags()) {
+          FieldInfo field = tag.reference();
+          if (field != null) {
+            AttributeInfo attr = attrs.get(field);
+            if (attr == null) {
+              attr = new AttributeInfo(this, field);
+              attrs.put(field, attr);
+            }
+            tag.setAttribute(attr);
+            attr.methods.add(m);
+          }
+        }
+      }
+
+      mSelfAttributes = attrs.values().toArray(new AttributeInfo[attrs.size()]);
+      Arrays.sort(mSelfAttributes, AttributeInfo.comparator);
+    }
+    return mSelfAttributes;
+  }
+
+  public FieldInfo[] enumConstants() {
+    return mEnumConstants;
+  }
+
+  public ClassInfo superclass() {
+    if (!mSuperclassInit) {
+      if (this.checkLevel()) {
+        // rearrange our little inheritance hierarchy, because we need to hide classes that
+        // don't pass checkLevel
+        ClassInfo superclass = mRealSuperclass;
+        while (superclass != null && !superclass.checkLevel()) {
+          superclass = superclass.mRealSuperclass;
+        }
+        mSuperclass = superclass;
+      } else {
+        mSuperclass = mRealSuperclass;
+      }
+    }
+    return mSuperclass;
+  }
+
+  public ClassInfo realSuperclass() {
+    return mRealSuperclass;
+  }
+
+  /**
+   * always the real superclass, not the collapsed one we get through superclass(), also has the
+   * type parameter info if it's generic.
+   */
+  public TypeInfo superclassType() {
+    return mRealSuperclassType;
+  }
+
+  public TypeInfo asTypeInfo() {
+    return mTypeInfo;
+  }
+
+  TypeInfo[] interfaceTypes() {
+    ClassInfo[] infos = interfaces();
+    int len = infos.length;
+    TypeInfo[] types = new TypeInfo[len];
+    for (int i = 0; i < len; i++) {
+      types[i] = infos[i].asTypeInfo();
+    }
+    return types;
+  }
+
+  public String htmlPage() {
+    String s = containingPackage().name();
+    s = s.replace('.', '/');
+    s += '/';
+    s += name();
+    s += ".html";
+    s = Doclava.javadocDir + s;
+    return s;
+  }
+
+  /** Even indirectly */
+  public boolean isDerivedFrom(ClassInfo cl) {
+    ClassInfo dad = this.superclass();
+    if (dad != null) {
+      if (dad.equals(cl)) {
+        return true;
+      } else {
+        if (dad.isDerivedFrom(cl)) {
+          return true;
+        }
+      }
+    }
+    for (ClassInfo iface : interfaces()) {
+      if (iface.equals(cl)) {
+        return true;
+      } else {
+        if (iface.isDerivedFrom(cl)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  public void makeKeywordEntries(List<KeywordEntry> keywords) {
+    if (!checkLevel()) {
+      return;
+    }
+
+    String htmlPage = htmlPage();
+    String qualifiedName = qualifiedName();
+
+    keywords.add(new KeywordEntry(name(), htmlPage, "class in " + containingPackage().name()));
+
+    FieldInfo[] fields = selfFields();
+    FieldInfo[] enumConstants = enumConstants();
+    MethodInfo[] ctors = constructors();
+    MethodInfo[] methods = selfMethods();
+
+    // enum constants
+    for (FieldInfo field : enumConstants()) {
+      if (field.checkLevel()) {
+        keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(),
+            "enum constant in " + qualifiedName));
+      }
+    }
+
+    // constants
+    for (FieldInfo field : fields) {
+      if (field.isConstant() && field.checkLevel()) {
+        keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), "constant in "
+            + qualifiedName));
+      }
+    }
+
+    // fields
+    for (FieldInfo field : fields) {
+      if (!field.isConstant() && field.checkLevel()) {
+        keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), "field in "
+            + qualifiedName));
+      }
+    }
+
+    // public constructors
+    for (MethodInfo m : ctors) {
+      if (m.isPublic() && m.checkLevel()) {
+        keywords.add(new KeywordEntry(m.prettySignature(), htmlPage + "#" + m.anchor(),
+            "constructor in " + qualifiedName));
+      }
+    }
+
+    // protected constructors
+    if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
+      for (MethodInfo m : ctors) {
+        if (m.isProtected() && m.checkLevel()) {
+          keywords.add(new KeywordEntry(m.prettySignature(),
+              htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
+        }
+      }
+    }
+
+    // package private constructors
+    if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
+      for (MethodInfo m : ctors) {
+        if (m.isPackagePrivate() && m.checkLevel()) {
+          keywords.add(new KeywordEntry(m.prettySignature(),
+              htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
+        }
+      }
+    }
+
+    // private constructors
+    if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
+      for (MethodInfo m : ctors) {
+        if (m.isPrivate() && m.checkLevel()) {
+          keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
+              htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
+        }
+      }
+    }
+
+    // public methods
+    for (MethodInfo m : methods) {
+      if (m.isPublic() && m.checkLevel()) {
+        keywords.add(new KeywordEntry(m.name() + m.prettySignature(), htmlPage + "#" + m.anchor(),
+            "method in " + qualifiedName));
+      }
+    }
+
+    // protected methods
+    if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
+      for (MethodInfo m : methods) {
+        if (m.isProtected() && m.checkLevel()) {
+          keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
+              htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
+        }
+      }
+    }
+
+    // package private methods
+    if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
+      for (MethodInfo m : methods) {
+        if (m.isPackagePrivate() && m.checkLevel()) {
+          keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
+              htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
+        }
+      }
+    }
+
+    // private methods
+    if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
+      for (MethodInfo m : methods) {
+        if (m.isPrivate() && m.checkLevel()) {
+          keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
+              htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
+        }
+      }
+    }
+  }
+
+  public void makeLink(Data data, String base) {
+    data.setValue(base + ".label", this.name());
+    if (!this.isPrimitive() && this.isIncluded() && this.checkLevel()) {
+      data.setValue(base + ".link", this.htmlPage());
+    }
+  }
+
+  public static void makeLinkListHDF(Data data, String base, ClassInfo[] classes) {
+    final int N = classes.length;
+    for (int i = 0; i < N; i++) {
+      ClassInfo cl = classes[i];
+      if (cl.checkLevel()) {
+        cl.asTypeInfo().makeHDF(data, base + "." + i);
+      }
+    }
+  }
+
+  /**
+   * Used in lists of this class (packages, nested classes, known subclasses)
+   */
+  public void makeShortDescrHDF(Data data, String base) {
+    mTypeInfo.makeHDF(data, base + ".type");
+    data.setValue(base + ".kind", this.kind());
+    TagInfo.makeHDF(data, base + ".shortDescr", this.firstSentenceTags());
+    TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags());
+    data.setValue(base + ".since", getSince());
+    setFederatedReferences(data, base);
+  }
+
+  /**
+   * Turns into the main class page
+   */
+  public void makeHDF(Data data) {
+    int i, j, n;
+    String name = name();
+    String qualified = qualifiedName();
+    AttributeInfo[] selfAttributes = selfAttributes();
+    MethodInfo[] methods = selfMethods();
+    FieldInfo[] fields = selfFields();
+    FieldInfo[] enumConstants = enumConstants();
+    MethodInfo[] ctors = constructors();
+    ClassInfo[] inners = innerClasses();
+
+    // class name
+    mTypeInfo.makeHDF(data, "class.type");
+    mTypeInfo.makeQualifiedHDF(data, "class.qualifiedType");
+    data.setValue("class.name", name);
+    data.setValue("class.qualified", qualified);
+    String scope = "";
+    if (isProtected()) {
+      data.setValue("class.scope", "protected");
+    } else if (isPublic()) {
+      data.setValue("class.scope", "public");
+    }
+    if (isStatic()) {
+      data.setValue("class.static", "static");
+    }
+    if (isFinal()) {
+      data.setValue("class.final", "final");
+    }
+    if (isAbstract() && !isInterface()) {
+      data.setValue("class.abstract", "abstract");
+    }
+
+    // class info
+    String kind = kind();
+    if (kind != null) {
+      data.setValue("class.kind", kind);
+    }
+    data.setValue("class.since", getSince());
+    setFederatedReferences(data, "class");
+
+    // the containing package -- note that this can be passed to type_link,
+    // but it also contains the list of all of the packages
+    containingPackage().makeClassLinkListHDF(data, "class.package");
+
+    // inheritance hierarchy
+    Vector<ClassInfo> superClasses = new Vector<ClassInfo>();
+    superClasses.add(this);
+    ClassInfo supr = superclass();
+    while (supr != null) {
+      superClasses.add(supr);
+      supr = supr.superclass();
+    }
+    n = superClasses.size();
+    for (i = 0; i < n; i++) {
+      supr = superClasses.elementAt(n - i - 1);
+
+      supr.asTypeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class");
+      supr.asTypeInfo().makeHDF(data, "class.inheritance." + i + ".short_class");
+      j = 0;
+      for (TypeInfo t : supr.interfaceTypes()) {
+        t.makeHDF(data, "class.inheritance." + i + ".interfaces." + j);
+        j++;
+      }
+    }
+
+    // class description
+    TagInfo.makeHDF(data, "class.descr", inlineTags());
+    TagInfo.makeHDF(data, "class.seeAlso", comment().seeTags());
+    TagInfo.makeHDF(data, "class.deprecated", deprecatedTags());
+
+    // known subclasses
+    TreeMap<String, ClassInfo> direct = new TreeMap<String, ClassInfo>();
+    TreeMap<String, ClassInfo> indirect = new TreeMap<String, ClassInfo>();
+    ClassInfo[] all = Converter.rootClasses();
+    for (ClassInfo cl : all) {
+      if (cl.superclass() != null && cl.superclass().equals(this)) {
+        direct.put(cl.name(), cl);
+      } else if (cl.isDerivedFrom(this)) {
+        indirect.put(cl.name(), cl);
+      }
+    }
+    // direct
+    i = 0;
+    for (ClassInfo cl : direct.values()) {
+      if (cl.checkLevel()) {
+        cl.makeShortDescrHDF(data, "class.subclasses.direct." + i);
+      }
+      i++;
+    }
+    // indirect
+    i = 0;
+    for (ClassInfo cl : indirect.values()) {
+      if (cl.checkLevel()) {
+        cl.makeShortDescrHDF(data, "class.subclasses.indirect." + i);
+      }
+      i++;
+    }
+
+    // hide special cases
+    if ("java.lang.Object".equals(qualified) || "java.io.Serializable".equals(qualified)) {
+      data.setValue("class.subclasses.hidden", "1");
+    } else {
+      data.setValue("class.subclasses.hidden", "0");
+    }
+
+    // nested classes
+    i = 0;
+    for (ClassInfo inner : inners) {
+      if (inner.checkLevel()) {
+        inner.makeShortDescrHDF(data, "class.inners." + i);
+      }
+      i++;
+    }
+
+    // enum constants
+    i = 0;
+    for (FieldInfo field : enumConstants) {
+      if (field.isConstant()) {
+        field.makeHDF(data, "class.enumConstants." + i);
+        i++;
+      }
+    }
+
+    // constants
+    i = 0;
+    for (FieldInfo field : fields) {
+      if (field.isConstant()) {
+        field.makeHDF(data, "class.constants." + i);
+        i++;
+      }
+    }
+
+    // fields
+    i = 0;
+    for (FieldInfo field : fields) {
+      if (!field.isConstant()) {
+        field.makeHDF(data, "class.fields." + i);
+        i++;
+      }
+    }
+
+    // public constructors
+    i = 0;
+    for (MethodInfo ctor : ctors) {
+      if (ctor.isPublic()) {
+        ctor.makeHDF(data, "class.ctors.public." + i);
+        i++;
+      }
+    }
+
+    // protected constructors
+    if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
+      i = 0;
+      for (MethodInfo ctor : ctors) {
+        if (ctor.isProtected()) {
+          ctor.makeHDF(data, "class.ctors.protected." + i);
+          i++;
+        }
+      }
+    }
+
+    // package private constructors
+    if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
+      i = 0;
+      for (MethodInfo ctor : ctors) {
+        if (ctor.isPackagePrivate()) {
+          ctor.makeHDF(data, "class.ctors.package." + i);
+          i++;
+        }
+      }
+    }
+
+    // private constructors
+    if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
+      i = 0;
+      for (MethodInfo ctor : ctors) {
+        if (ctor.isPrivate()) {
+          ctor.makeHDF(data, "class.ctors.private." + i);
+          i++;
+        }
+      }
+    }
+
+    // public methods
+    i = 0;
+    for (MethodInfo method : methods) {
+      if (method.isPublic()) {
+        method.makeHDF(data, "class.methods.public." + i);
+        i++;
+      }
+    }
+
+    // protected methods
+    if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
+      i = 0;
+      for (MethodInfo method : methods) {
+        if (method.isProtected()) {
+          method.makeHDF(data, "class.methods.protected." + i);
+          i++;
+        }
+      }
+    }
+
+    // package private methods
+    if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
+      i = 0;
+      for (MethodInfo method : methods) {
+        if (method.isPackagePrivate()) {
+          method.makeHDF(data, "class.methods.package." + i);
+          i++;
+        }
+      }
+    }
+
+    // private methods
+    if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
+      i = 0;
+      for (MethodInfo method : methods) {
+        if (method.isPrivate()) {
+          method.makeHDF(data, "class.methods.private." + i);
+          i++;
+        }
+      }
+    }
+
+    // xml attributes
+    i = 0;
+    for (AttributeInfo attr : selfAttributes) {
+      if (attr.checkLevel()) {
+        attr.makeHDF(data, "class.attrs." + i);
+        i++;
+      }
+    }
+
+    // inherited methods
+    Set<ClassInfo> interfaces = new TreeSet<ClassInfo>();
+    addInterfaces(interfaces(), interfaces);
+    ClassInfo cl = superclass();
+    i = 0;
+    while (cl != null) {
+      addInterfaces(cl.interfaces(), interfaces);
+      makeInheritedHDF(data, i, cl);
+      cl = cl.superclass();
+      i++;
+    }
+    for (ClassInfo iface : interfaces) {
+      makeInheritedHDF(data, i, iface);
+      i++;
+    }
+  }
+
+  private static void addInterfaces(ClassInfo[] ifaces, Set<ClassInfo> out) {
+    for (ClassInfo cl : ifaces) {
+      out.add(cl);
+      addInterfaces(cl.interfaces(), out);
+    }
+  }
+
+  private static void makeInheritedHDF(Data data, int index, ClassInfo cl) {
+    int i;
+
+    String base = "class.inherited." + index;
+    data.setValue(base + ".qualified", cl.qualifiedName());
+    if (cl.checkLevel()) {
+      data.setValue(base + ".link", cl.htmlPage());
+    }
+    String kind = cl.kind();
+    if (kind != null) {
+      data.setValue(base + ".kind", kind);
+    }
+
+    if (cl.mIsIncluded) {
+      data.setValue(base + ".included", "true");
+    } else {
+      Doclava.federationTagger.tagAll(new ClassInfo[] {cl});
+      if (!cl.getFederatedReferences().isEmpty()) {
+        FederatedSite site = cl.getFederatedReferences().iterator().next();
+        data.setValue(base + ".link", site.linkFor(cl.htmlPage()));
+        data.setValue(base + ".federated", site.name());
+      }
+    }
+
+    // xml attributes
+    i = 0;
+    for (AttributeInfo attr : cl.selfAttributes()) {
+      attr.makeHDF(data, base + ".attrs." + i);
+      i++;
+    }
+
+    // methods
+    i = 0;
+    for (MethodInfo method : cl.selfMethods()) {
+      method.makeHDF(data, base + ".methods." + i);
+      i++;
+    }
+
+    // fields
+    i = 0;
+    for (FieldInfo field : cl.selfFields()) {
+      if (!field.isConstant()) {
+        field.makeHDF(data, base + ".fields." + i);
+        i++;
+      }
+    }
+
+    // constants
+    i = 0;
+    for (FieldInfo field : cl.selfFields()) {
+      if (field.isConstant()) {
+        field.makeHDF(data, base + ".constants." + i);
+        i++;
+      }
+    }
+  }
+
+  @Override
+  public boolean isHidden() {
+    int val = mHidden;
+    if (val >= 0) {
+      return val != 0;
+    } else {
+      boolean v = isHiddenImpl();
+      mHidden = v ? 1 : 0;
+      return v;
+    }
+  }
+
+  public boolean isHiddenImpl() {
+    ClassInfo cl = this;
+    while (cl != null) {
+      PackageInfo pkg = cl.containingPackage();
+      if (pkg != null && pkg.isHidden()) {
+        return true;
+      }
+      if (cl.comment().isHidden()) {
+        return true;
+      }
+      cl = cl.containingClass();
+    }
+    return false;
+  }
+
+  private MethodInfo matchMethod(MethodInfo[] methods, String name, String[] params,
+      String[] dimensions, boolean varargs) {
+    int len = methods.length;
+    for (int i = 0; i < len; i++) {
+      MethodInfo method = methods[i];
+      if (method.name().equals(name)) {
+        if (params == null) {
+          return method;
+        } else {
+          if (method.matchesParams(params, dimensions, varargs)) {
+            return method;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  public MethodInfo findMethod(String name, String[] params, String[] dimensions, boolean varargs) {
+    // first look on our class, and our superclasses
+
+    // for methods
+    MethodInfo rv;
+    rv = matchMethod(methods(), name, params, dimensions, varargs);
+
+    if (rv != null) {
+      return rv;
+    }
+
+    // for constructors
+    rv = matchMethod(constructors(), name, params, dimensions, varargs);
+    if (rv != null) {
+      return rv;
+    }
+
+    // then recursively look at our containing class
+    ClassInfo containing = containingClass();
+    if (containing != null) {
+      return containing.findMethod(name, params, dimensions, varargs);
+    }
+
+    return null;
+  }
+  
+  public boolean supportsMethod(MethodInfo method) {
+    for (MethodInfo m : methods()) {
+      if (m.getHashableName().equals(method.getHashableName())) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private ClassInfo searchInnerClasses(String[] nameParts, int index) {
+    String part = nameParts[index];
+
+    ClassInfo[] inners = mInnerClasses;
+    for (ClassInfo in : inners) {
+      String[] innerParts = in.nameParts();
+      if (part.equals(innerParts[innerParts.length - 1])) {
+        if (index == nameParts.length - 1) {
+          return in;
+        } else {
+          return in.searchInnerClasses(nameParts, index + 1);
+        }
+      }
+    }
+    return null;
+  }
+
+  public ClassInfo extendedFindClass(String className) {
+    // ClassDoc.findClass has this bug that we're working around here:
+    // If you have a class PackageManager with an inner class PackageInfo
+    // and you call it with "PackageInfo" it doesn't find it.
+    return searchInnerClasses(className.split("\\."), 0);
+  }
+
+  public ClassInfo findClass(String className) {
+    return Converter.obtainClass(mClass.findClass(className));
+  }
+
+  public ClassInfo findInnerClass(String className) {
+    // ClassDoc.findClass won't find inner classes. To deal with that,
+    // we try what they gave us first, but if that didn't work, then
+    // we see if there are any periods in className, and start searching
+    // from there.
+    String[] nodes = className.split("\\.");
+    ClassDoc cl = mClass;
+    for (String n : nodes) {
+      cl = cl.findClass(n);
+      if (cl == null) {
+        return null;
+      }
+    }
+    return Converter.obtainClass(cl);
+  }
+
+  public FieldInfo findField(String name) {
+    // first look on our class, and our superclasses
+    for (FieldInfo f : fields()) {
+      if (f.name().equals(name)) {
+        return f;
+      }
+    }
+
+    // then look at our enum constants (these are really fields, maybe
+    // they should be mixed into fields(). not sure)
+    for (FieldInfo f : enumConstants()) {
+      if (f.name().equals(name)) {
+        return f;
+      }
+    }
+
+    // then recursively look at our containing class
+    ClassInfo containing = containingClass();
+    if (containing != null) {
+      return containing.findField(name);
+    }
+
+    return null;
+  }
+
+  public static ClassInfo[] sortByName(ClassInfo[] classes) {
+    int i;
+    Sorter[] sorted = new Sorter[classes.length];
+    for (i = 0; i < sorted.length; i++) {
+      ClassInfo cl = classes[i];
+      sorted[i] = new Sorter(cl.name(), cl);
+    }
+
+    Arrays.sort(sorted);
+
+    ClassInfo[] rv = new ClassInfo[classes.length];
+    for (i = 0; i < rv.length; i++) {
+      rv[i] = (ClassInfo) sorted[i].data;
+    }
+
+    return rv;
+  }
+
+  public boolean equals(ClassInfo that) {
+    if (that != null) {
+      return this.qualifiedName().equals(that.qualifiedName());
+    } else {
+      return false;
+    }
+  }
+
+  public void setNonWrittenConstructors(MethodInfo[] nonWritten) {
+    mNonWrittenConstructors = nonWritten;
+  }
+
+  public MethodInfo[] getNonWrittenConstructors() {
+    return mNonWrittenConstructors;
+  }
+
+  public String kind() {
+    if (isOrdinaryClass()) {
+      return "class";
+    } else if (isInterface()) {
+      return "interface";
+    } else if (isEnum()) {
+      return "enum";
+    } else if (isError()) {
+      return "class";
+    } else if (isException()) {
+      return "class";
+    } else if (isAnnotation()) {
+      return "@interface";
+    }
+    return null;
+  }
+  
+  public String scope() {
+    if (isPublic()) {
+      return "public";
+    } else if (isProtected()) {
+      return "protected";
+    } else if (isPackagePrivate()) {
+      return "";
+    } else if (isPrivate()) {
+      return "private";
+    } else {
+      throw new RuntimeException("invalid scope for object " + this);
+    }
+  }
+
+  public void setHiddenMethods(MethodInfo[] mInfo) {
+    mHiddenMethods = mInfo;
+  }
+
+  public MethodInfo[] getHiddenMethods() {
+    return mHiddenMethods;
+  }
+
+  @Override
+  public String toString() {
+    return this.qualifiedName();
+  }
+
+  public void setReasonIncluded(String reason) {
+    mReasonIncluded = reason;
+  }
+
+  public String getReasonIncluded() {
+    return mReasonIncluded;
+  }
+
+  private ClassDoc mClass;
+
+  // ctor
+  private boolean mIsPublic;
+  private boolean mIsProtected;
+  private boolean mIsPackagePrivate;
+  private boolean mIsPrivate;
+  private boolean mIsStatic;
+  private boolean mIsInterface;
+  private boolean mIsAbstract;
+  private boolean mIsOrdinaryClass;
+  private boolean mIsException;
+  private boolean mIsError;
+  private boolean mIsEnum;
+  private boolean mIsAnnotation;
+  private boolean mIsFinal;
+  private boolean mIsIncluded;
+  private String mName;
+  private String mQualifiedName;
+  private String mQualifiedTypeName;
+  private boolean mIsPrimitive;
+  private TypeInfo mTypeInfo;
+  private String[] mNameParts;
+
+  // init
+  private List<ClassInfo> mRealInterfaces = new ArrayList<ClassInfo>();
+  private ClassInfo[] mInterfaces;
+  private TypeInfo[] mRealInterfaceTypes;
+  private ClassInfo[] mInnerClasses;
+  private MethodInfo[] mAllConstructors;
+  private MethodInfo[] mAllSelfMethods;
+  private MethodInfo[] mAnnotationElements; // if this class is an annotation
+  private FieldInfo[] mAllSelfFields;
+  private FieldInfo[] mEnumConstants;
+  private PackageInfo mContainingPackage;
+  private ClassInfo mContainingClass;
+  private ClassInfo mRealSuperclass;
+  private TypeInfo mRealSuperclassType;
+  private ClassInfo mSuperclass;
+  private AnnotationInstanceInfo[] mAnnotations;
+  private boolean mSuperclassInit;
+  private boolean mDeprecatedKnown;
+
+  // lazy
+  private MethodInfo[] mConstructors;
+  private ClassInfo[] mRealInnerClasses;
+  private MethodInfo[] mSelfMethods;
+  private FieldInfo[] mSelfFields;
+  private AttributeInfo[] mSelfAttributes;
+  private MethodInfo[] mMethods;
+  private FieldInfo[] mFields;
+  private TypeInfo[] mTypeParameters;
+  private MethodInfo[] mHiddenMethods;
+  private int mHidden = -1;
+  private int mCheckLevel = -1;
+  private String mReasonIncluded;
+  private MethodInfo[] mNonWrittenConstructors;
+  private boolean mIsDeprecated;
+  
+  // TODO: Temporary members from apicheck migration.
+  private HashMap<String, MethodInfo> mApiCheckMethods = new HashMap<String, MethodInfo>();
+  private HashMap<String, FieldInfo> mApiCheckFields = new HashMap<String, FieldInfo>();
+  private HashMap<String, ConstructorInfo> mApiCheckConstructors
+      = new HashMap<String, ConstructorInfo>();
+  
+  /**
+   * Returns true if {@code cl} implements the interface {@code iface} either by either being that
+   * interface, implementing that interface or extending a type that implements the interface.
+   */
+  private boolean implementsInterface(ClassInfo cl, String iface) {
+    if (cl.qualifiedName().equals(iface)) {
+      return true;
+    }
+    for (ClassInfo clImplements : cl.interfaces()) {
+      if (implementsInterface(clImplements, iface)) {
+        return true;
+      }
+    }
+    if (cl.mSuperclass != null && implementsInterface(cl.mSuperclass, iface)) {
+      return true;
+    }
+    return false;
+  }
+
+
+  public void addInterface(ClassInfo iface) {
+    mRealInterfaces.add(iface);
+  }
+
+  public void addConstructor(ConstructorInfo cInfo) {
+    mApiCheckConstructors.put(cInfo.getHashableName(), cInfo);
+
+  }
+
+  public void addField(FieldInfo fInfo) {
+    mApiCheckFields.put(fInfo.name(), fInfo);
+
+  }
+
+  public void setSuperClass(ClassInfo superclass) {
+    mSuperclass = superclass;
+  }
+
+  public Map<String, ConstructorInfo> allConstructorsMap() {
+    return mApiCheckConstructors;
+  }
+
+  public Map<String, FieldInfo> allFields() {
+    return mApiCheckFields;
+  }
+
+  /**
+   * Returns all methods defined directly in this class. For a list of all
+   * methods supported by this class, see {@link #methods()}.
+   */
+  
+  public Map<String, MethodInfo> allMethods() {
+    return mApiCheckMethods;
+  }
+
+  /**
+   * Returns the class hierarchy for this class, starting with this class.
+   */
+  public Iterable<ClassInfo> hierarchy() {
+    List<ClassInfo> result = new ArrayList<ClassInfo>(4);
+    for (ClassInfo c = this; c != null; c = c.mSuperclass) {
+      result.add(c);
+    }
+    return result;
+  }
+  
+  public String superclassName() {
+    if (mSuperclass == null) {
+      if (mQualifiedName.equals("java.lang.Object")) {
+        return null;
+      }
+      throw new UnsupportedOperationException("Superclass not set for " + qualifiedName());
+    }
+    return mSuperclass.mQualifiedName;
+  }
+  
+  public void setAnnotations(AnnotationInstanceInfo[] annotations) {
+    mAnnotations = annotations;
+  }
+  
+  public boolean isConsistent(ClassInfo cl) {
+    boolean consistent = true;
+
+    if (isInterface() != cl.isInterface()) {
+      Errors.error(Errors.CHANGED_CLASS, cl.position(), "Class " + cl.qualifiedName()
+          + " changed class/interface declaration");
+      consistent = false;
+    }
+    for (ClassInfo iface : mRealInterfaces) {
+      if (!implementsInterface(cl, iface.mQualifiedName)) {
+        Errors.error(Errors.REMOVED_INTERFACE, cl.position(), "Class " + qualifiedName()
+            + " no longer implements " + iface);
+      }
+    }
+    for (ClassInfo iface : cl.mRealInterfaces) {
+      if (!implementsInterface(this, iface.mQualifiedName)) {
+        Errors.error(Errors.ADDED_INTERFACE, cl.position(), "Added interface " + iface
+            + " to class " + qualifiedName());
+        consistent = false;
+      }
+    }
+
+    for (MethodInfo mInfo : mApiCheckMethods.values()) {
+      if (cl.mApiCheckMethods.containsKey(mInfo.getHashableName())) {
+        if (!mInfo.isConsistent(cl.mApiCheckMethods.get(mInfo.getHashableName()))) {
+          consistent = false;
+        }
+      } else {
+        /*
+         * This class formerly provided this method directly, and now does not. Check our ancestry
+         * to see if there's an inherited version that still fulfills the API requirement.
+         */
+        MethodInfo mi = ClassInfo.overriddenMethod(mInfo, cl);
+        if (mi == null) {
+          mi = ClassInfo.interfaceMethod(mInfo, cl);
+        }
+        if (mi == null) {
+          Errors.error(Errors.REMOVED_METHOD, mInfo.position(), "Removed public method "
+              + mInfo.qualifiedName());
+          consistent = false;
+        }
+      }
+    }
+    for (MethodInfo mInfo : cl.mApiCheckMethods.values()) {
+      if (!mApiCheckMethods.containsKey(mInfo.getHashableName())) {
+        /*
+         * Similarly to the above, do not fail if this "new" method is really an override of an
+         * existing superclass method.
+         */
+        MethodInfo mi = ClassInfo.overriddenMethod(mInfo, this);
+        if (mi == null) {
+          Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public method "
+              + mInfo.qualifiedName());
+          consistent = false;
+        }
+      }
+    }
+
+    for (ConstructorInfo mInfo : mApiCheckConstructors.values()) {
+      if (cl.mApiCheckConstructors.containsKey(mInfo.getHashableName())) {
+        if (!mInfo.isConsistent(cl.mApiCheckConstructors.get(mInfo.getHashableName()))) {
+          consistent = false;
+        }
+      } else {
+        Errors.error(Errors.REMOVED_METHOD, mInfo.position(), "Removed public constructor "
+            + mInfo.prettySignature());
+        consistent = false;
+      }
+    }
+    for (ConstructorInfo mInfo : cl.mApiCheckConstructors.values()) {
+      if (!mApiCheckConstructors.containsKey(mInfo.getHashableName())) {
+        Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public constructor "
+            + mInfo.prettySignature());
+        consistent = false;
+      }
+    }
+
+    for (FieldInfo mInfo : mApiCheckFields.values()) {
+      if (cl.mApiCheckFields.containsKey(mInfo.name())) {
+        if (!mInfo.isConsistent(cl.mApiCheckFields.get(mInfo.name()))) {
+          consistent = false;
+        }
+      } else {
+        Errors.error(Errors.REMOVED_FIELD, mInfo.position(), "Removed field "
+            + mInfo.qualifiedName());
+        consistent = false;
+      }
+    }
+    for (FieldInfo mInfo : cl.mApiCheckFields.values()) {
+      if (!mApiCheckFields.containsKey(mInfo.name())) {
+        Errors.error(Errors.ADDED_FIELD, mInfo.position(), "Added public field "
+            + mInfo.qualifiedName());
+        consistent = false;
+      }
+    }
+
+    if (mIsAbstract != cl.mIsAbstract) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_ABSTRACT, cl.position(), "Class " + cl.qualifiedName()
+          + " changed abstract qualifier");
+    }
+
+    if (mIsFinal != cl.mIsFinal) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_FINAL, cl.position(), "Class " + cl.qualifiedName()
+          + " changed final qualifier");
+    }
+
+    if (mIsStatic != cl.mIsStatic) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_STATIC, cl.position(), "Class " + cl.qualifiedName()
+          + " changed static qualifier");
+    }
+
+    if (!scope().equals(cl.scope())) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_SCOPE, cl.position(), "Class " + cl.qualifiedName()
+          + " scope changed from " + scope() + " to " + cl.scope());
+    }
+
+    if (!isDeprecated() == cl.isDeprecated()) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_DEPRECATED, cl.position(), "Class " + cl.qualifiedName()
+          + " has changed deprecation state");
+    }
+
+    if (superclassName() != null) {
+      if (cl.superclassName() == null || !superclassName().equals(cl.superclassName())) {
+        consistent = false;
+        Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(), "Class " + qualifiedName()
+            + " superclass changed from " + superclassName() + " to " + cl.superclassName());
+      }
+    } else if (cl.superclassName() != null) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(), "Class " + qualifiedName()
+          + " superclass changed from " + "null to " + cl.superclassName());
+    }
+
+    return consistent;
+  }
+  
+  // Find a superclass implementation of the given method.
+  public static MethodInfo overriddenMethod(MethodInfo candidate, ClassInfo newClassObj) {
+    if (newClassObj == null) {
+      return null;
+    }
+    for (MethodInfo mi : newClassObj.mApiCheckMethods.values()) {
+      if (mi.matches(candidate)) {
+        // found it
+        return mi;
+      }
+    }
+
+    // not found here. recursively search ancestors
+    return ClassInfo.overriddenMethod(candidate, newClassObj.mSuperclass);
+  }
+
+  // Find a superinterface declaration of the given method.
+  public static MethodInfo interfaceMethod(MethodInfo candidate, ClassInfo newClassObj) {
+    if (newClassObj == null) {
+      return null;
+    }
+    for (ClassInfo interfaceInfo : newClassObj.interfaces()) {
+      for (MethodInfo mi : interfaceInfo.mApiCheckMethods.values()) {
+        if (mi.matches(candidate)) {
+          return mi;
+        }
+      }
+    }
+    return ClassInfo.interfaceMethod(candidate, newClassObj.mSuperclass);
+  }
+  
+  public boolean hasConstructor(MethodInfo constructor) {
+    String name = constructor.getHashableName();
+    for (ConstructorInfo ctor : mApiCheckConstructors.values()) {
+      if (name.equals(ctor.getHashableName())) {
+        return true;
+      }
+    }
+    return false;
+  }
+  
+  public void setTypeInfo(TypeInfo typeInfo) {
+    mTypeInfo = typeInfo;
+  }
+}
diff --git a/src/com/google/doclava/ClearPage.java b/src/com/google/doclava/ClearPage.java
new file mode 100644
index 0000000..4bb0784
--- /dev/null
+++ b/src/com/google/doclava/ClearPage.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.JSilver;
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ClearPage {
+  /*
+   * public ClearPage() { String templ = "templates/index.cs"; String filename = "docs/index.html";
+   * 
+   * data.setValue("A.B.C", "1"); data.setValue("A.B.D", "2"); }
+   */
+
+  private static ArrayList<String> mTemplateDirs = new ArrayList<String>();
+  private static boolean mTemplateDirSet = false;
+
+  private static ArrayList<String> mBundledTemplateDirs = new ArrayList<String>();
+
+  public static String outputDir = "docs";
+  public static String htmlDir = null;
+  public static String toroot = null;
+
+  public static void addTemplateDir(String dir) {
+    mTemplateDirSet = true;
+    mTemplateDirs.add(dir);
+  }
+
+  public static List<String> getTemplateDirs() {
+    return mTemplateDirs;
+  }
+
+  public static void addBundledTemplateDir(String dir) {
+    mTemplateDirSet = true;
+    mBundledTemplateDirs.add(dir);
+  }
+
+  public static List<String> getBundledTemplateDirs() {
+    return mBundledTemplateDirs;
+  }
+
+  private static int countSlashes(String s) {
+    final int N = s.length();
+    int slashcount = 0;
+    for (int i = 0; i < N; i++) {
+      if (s.charAt(i) == '/') {
+        slashcount++;
+      }
+    }
+    return slashcount;
+  }
+
+  public static void write(Data data, String templ, String filename, JSilver cs) {
+    write(data, templ, filename, false, cs);
+  }
+
+  public static void write(Data data, String templ, String filename) {
+    write(data, templ, filename, false, Doclava.jSilver);
+  }
+
+  public static void write(Data data, String templ, String filename, boolean fullPath) {
+    write(data, templ, filename, false, Doclava.jSilver);
+  }
+
+  public static void write(Data data, String templ, String filename, boolean fullPath, JSilver cs) {
+    if (htmlDir != null) {
+      data.setValue("hasindex", "true");
+    }
+
+    String toroot;
+    if (ClearPage.toroot != null) {
+      toroot = ClearPage.toroot;
+    } else {
+      int slashcount = countSlashes(filename);
+      if (slashcount > 0) {
+        toroot = "";
+        for (int i = 0; i < slashcount; i++) {
+          toroot += "../";
+        }
+      } else {
+        toroot = "./";
+      }
+    }
+    data.setValue("toroot", toroot);
+
+    data.setValue("filename", filename);
+
+    if (!fullPath) {
+      filename = outputDir + "/" + filename;
+    }
+
+    int i = 0;
+    if (htmlDir != null) {
+      data.setValue("hdf.loadpaths." + i, htmlDir);
+      i++;
+    }
+    if (mTemplateDirSet) {
+      for (String dir : mTemplateDirs) {
+        data.setValue("hdf.loadpaths." + i, dir);
+        i++;
+      }
+    } else {
+      data.setValue("hdf.loadpaths." + i, "templates");
+    }
+
+    File file = new File(outputFilename(filename));
+
+    ensureDirectory(file);
+
+    OutputStreamWriter stream = null;
+    try {
+      stream = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
+      String rendered = cs.render(templ, data);
+      stream.write(rendered, 0, rendered.length());
+    } catch (IOException e) {
+      System.out.println("error: " + e.getMessage() + "; when writing file: " + filename);
+    } finally {
+      if (stream != null) {
+        try {
+          stream.close();
+        } catch (IOException e) {}
+      }
+    }
+  }
+
+  // recursively create the directories to the output
+  public static void ensureDirectory(File f) {
+    File parent = f.getParentFile();
+    if (parent != null) {
+      parent.mkdirs();
+    }
+  }
+
+  public static void copyFile(File from, String toPath) {
+    File to = new File(outputDir + "/" + toPath);
+    FileInputStream in;
+    FileOutputStream out;
+    try {
+      if (!from.exists()) {
+        throw new IOException();
+      }
+      in = new FileInputStream(from);
+    } catch (IOException e) {
+      System.err.println(from.getAbsolutePath() + ": Error opening file");
+      return;
+    }
+    ensureDirectory(to);
+    try {
+      out = new FileOutputStream(to);
+    } catch (IOException e) {
+      System.err.println(from.getAbsolutePath() + ": Error opening file");
+      return;
+    }
+
+    long sizel = from.length();
+    final int maxsize = 64 * 1024;
+    int size = sizel > maxsize ? maxsize : (int) sizel;
+    byte[] buf = new byte[size];
+    while (true) {
+      try {
+        size = in.read(buf);
+      } catch (IOException e) {
+        System.err.println(from.getAbsolutePath() + ": error reading file");
+        break;
+      }
+      if (size > 0) {
+        try {
+          out.write(buf, 0, size);
+        } catch (IOException e) {
+          System.err.println(from.getAbsolutePath() + ": error writing file");
+        }
+      } else {
+        break;
+      }
+    }
+    try {
+      in.close();
+    } catch (IOException e) {}
+    try {
+      out.close();
+    } catch (IOException e) {}
+  }
+
+  /** Takes a string that ends w/ .html and changes the .html to htmlExtension */
+  public static String outputFilename(String htmlFile) {
+    if (!Doclava.htmlExtension.equals(".html") && htmlFile.endsWith(".html")) {
+      return htmlFile.substring(0, htmlFile.length() - 5) + Doclava.htmlExtension;
+    } else {
+      return htmlFile;
+    }
+  }
+
+}
diff --git a/src/com/google/doclava/CodeTagInfo.java b/src/com/google/doclava/CodeTagInfo.java
new file mode 100644
index 0000000..1a4a864
--- /dev/null
+++ b/src/com/google/doclava/CodeTagInfo.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+public class CodeTagInfo extends TagInfo {
+  private static String encode(String t) {
+    t = t.replace("&", "&amp;");
+    t = t.replace("<", "&lt;");
+    t = t.replace(">", "&gt;");
+    return t;
+  }
+
+  public CodeTagInfo(String text, SourcePositionInfo sp) {
+    // TODO: the correct behavior is to escape the text,
+    // but we'll have to update the Android sources before making the switch.
+    //super("@code", "@code", encode(text), sp);
+    super("@code", "@code", text, sp);
+  }
+}
diff --git a/src/com/google/doclava/Comment.java b/src/com/google/doclava/Comment.java
new file mode 100644
index 0000000..178c17a
--- /dev/null
+++ b/src/com/google/doclava/Comment.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.ArrayList;
+
+public class Comment {
+  static final Pattern LEADING_WHITESPACE = Pattern.compile("^[ \t\n\r]*(.*)$", Pattern.DOTALL);
+
+  static final Pattern TAG_BEGIN = Pattern.compile("[\r\n][\r\n \t]*@", Pattern.DOTALL);
+
+  static final Pattern TAG = Pattern.compile("(@[^ \t\r\n]+)[ \t\r\n]+(.*)", Pattern.DOTALL);
+
+  static final Pattern INLINE_TAG =
+      Pattern.compile("(.*?)\\{(@[^ \t\r\n\\}]+)[ \t\r\n]*(.*?)\\}", Pattern.DOTALL);
+
+  static final Pattern FIRST_SENTENCE =
+      Pattern.compile("((.*?)\\.)[ \t\r\n\\<](.*)", Pattern.DOTALL);
+
+  private static final String[] KNOWN_TAGS =
+      new String[] {"@author", "@since", "@version", "@deprecated", "@undeprecate", "@docRoot",
+          "@sdkCurrent", "@inheritDoc", "@more", "@samplecode", "@sample", "@include",
+          "@serial", "@com.intel.drl.spec_ref", "@ar.org.fitc.spec_ref",};
+
+  public Comment(String text, ContainerInfo base, SourcePositionInfo sp) {
+    mText = text;
+    mBase = base;
+    // sp now points to the end of the text, not the beginning!
+    mPosition = SourcePositionInfo.findBeginning(sp, text);
+  }
+
+  private void parseRegex(String text) {
+    Matcher m;
+
+    m = LEADING_WHITESPACE.matcher(text);
+    m.matches();
+    text = m.group(1);
+
+    m = TAG_BEGIN.matcher(text);
+
+    int start = 0;
+    int end = 0;
+    while (m.find()) {
+      end = m.start();
+
+      tag(text, start, end);
+
+      start = m.end() - 1; // -1 is the @
+    }
+    end = text.length();
+    tag(text, start, end);
+  }
+
+  private void tag(String text, int start, int end) {
+    SourcePositionInfo pos = SourcePositionInfo.add(mPosition, mText, start);
+
+    if (start >= 0 && end > 0 && (end - start) > 0) {
+      text = text.substring(start, end);
+
+      Matcher m = TAG.matcher(text);
+      if (m.matches()) {
+        // out of line tag
+        tag(m.group(1), m.group(2), false, pos);
+      } else {
+        // look for inline tags
+        m = INLINE_TAG.matcher(text);
+        start = 0;
+        while (m.find()) {
+          String str = m.group(1);
+          String tagname = m.group(2);
+          String tagvalue = m.group(3);
+          tag(null, m.group(1), true, pos);
+          tag(tagname, tagvalue, true, pos);
+          start = m.end();
+        }
+        int len = text.length();
+        if (start != len) {
+          tag(null, text.substring(start), true, pos);
+        }
+      }
+    }
+  }
+
+  private void tag(String name, String text, boolean isInline, SourcePositionInfo pos) {
+    /*
+     * String s = isInline ? "inline" : "outofline"; System.out.println("---> " + s + " name=[" +
+     * name + "] text=[" + text + "]");
+     */
+    if (name == null) {
+      mInlineTagsList.add(new TextTagInfo("Text", "Text", text, pos));
+    } else if (name.equals("@param")) {
+      mParamTagsList.add(new ParamTagInfo("@param", "@param", text, mBase, pos));
+    } else if (name.equals("@see")) {
+      mSeeTagsList.add(new SeeTagInfo("@see", "@see", text, mBase, pos));
+    } else if (name.equals("@link") || name.equals("@linkplain")) {
+      mInlineTagsList.add(new SeeTagInfo(name, "@see", text, mBase, pos));
+    } else if (name.equals("@throws") || name.equals("@exception")) {
+      mThrowsTagsList.add(new ThrowsTagInfo("@throws", "@throws", text, mBase, pos));
+    } else if (name.equals("@return")) {
+      mReturnTagsList.add(new ParsedTagInfo("@return", "@return", text, mBase, pos));
+    } else if (name.equals("@deprecated")) {
+      if (text.length() == 0) {
+        Errors.error(Errors.MISSING_COMMENT, pos, "@deprecated tag with no explanatory comment");
+        text = "No replacement.";
+      }
+      mDeprecatedTagsList.add(new ParsedTagInfo("@deprecated", "@deprecated", text, mBase, pos));
+    } else if (name.equals("@literal")) {
+      mInlineTagsList.add(new LiteralTagInfo(text, pos));
+    } else if (name.equals("@code")) {
+      mInlineTagsList.add(new CodeTagInfo(text, pos));
+    } else if (name.equals("@hide") || name.equals("@pending") || name.equals("@doconly")) {
+      // nothing
+    } else if (name.equals("@attr")) {
+      AttrTagInfo tag = new AttrTagInfo("@attr", "@attr", text, mBase, pos);
+      mAttrTagsList.add(tag);
+      Comment c = tag.description();
+      if (c != null) {
+        for (TagInfo t : c.tags()) {
+          mInlineTagsList.add(t);
+        }
+      }
+    } else if (name.equals("@undeprecate")) {
+      mUndeprecateTagsList.add(new TextTagInfo("@undeprecate", "@undeprecate", text, pos));
+    } else if (name.equals("@include") || name.equals("@sample")) {
+      mInlineTagsList.add(new SampleTagInfo(name, "@include", text, mBase, pos));
+    } else {
+      boolean known = false;
+      for (String s : KNOWN_TAGS) {
+        if (s.equals(name)) {
+          known = true;
+          break;
+        }
+      }
+      if (!known) {
+        Errors.error(Errors.UNKNOWN_TAG, pos == null ? null : new SourcePositionInfo(pos),
+            "Unknown tag: " + name);
+      }
+      TagInfo t = new TextTagInfo(name, name, text, pos);
+      if (isInline) {
+        mInlineTagsList.add(t);
+      } else {
+        mTagsList.add(t);
+      }
+    }
+  }
+
+  private void parseBriefTags() {
+    int N = mInlineTagsList.size();
+
+    // look for "@more" tag, which means that we might go past the first sentence.
+    int more = -1;
+    for (int i = 0; i < N; i++) {
+      if (mInlineTagsList.get(i).name().equals("@more")) {
+        more = i;
+      }
+    }
+    if (more >= 0) {
+      for (int i = 0; i < more; i++) {
+        mBriefTagsList.add(mInlineTagsList.get(i));
+      }
+    } else {
+      for (int i = 0; i < N; i++) {
+        TagInfo t = mInlineTagsList.get(i);
+        if (t.name().equals("Text")) {
+          Matcher m = FIRST_SENTENCE.matcher(t.text());
+          if (m.matches()) {
+            String text = m.group(1);
+            TagInfo firstSentenceTag = new TagInfo(t.name(), t.kind(), text, t.position());
+            mBriefTagsList.add(firstSentenceTag);
+            break;
+          }
+        }
+        mBriefTagsList.add(t);
+
+      }
+    }
+  }
+
+  public TagInfo[] tags() {
+    init();
+    return mInlineTags;
+  }
+
+  public TagInfo[] tags(String name) {
+    init();
+    ArrayList<TagInfo> results = new ArrayList<TagInfo>();
+    int N = mInlineTagsList.size();
+    for (int i = 0; i < N; i++) {
+      TagInfo t = mInlineTagsList.get(i);
+      if (t.name().equals(name)) {
+        results.add(t);
+      }
+    }
+    return results.toArray(new TagInfo[results.size()]);
+  }
+
+  public ParamTagInfo[] paramTags() {
+    init();
+    return mParamTags;
+  }
+
+  public SeeTagInfo[] seeTags() {
+    init();
+    return mSeeTags;
+  }
+
+  public ThrowsTagInfo[] throwsTags() {
+    init();
+    return mThrowsTags;
+  }
+
+  public TagInfo[] returnTags() {
+    init();
+    return mReturnTags;
+  }
+
+  public TagInfo[] deprecatedTags() {
+    init();
+    return mDeprecatedTags;
+  }
+
+  public TagInfo[] undeprecateTags() {
+    init();
+    return mUndeprecateTags;
+  }
+
+  public AttrTagInfo[] attrTags() {
+    init();
+    return mAttrTags;
+  }
+
+  public TagInfo[] briefTags() {
+    init();
+    return mBriefTags;
+  }
+
+  public boolean isHidden() {
+    if (mHidden != -1) {
+      return mHidden != 0;
+    } else {
+      if (Doclava.checkLevel(Doclava.SHOW_HIDDEN)) {
+        mHidden = 0;
+        return false;
+      }
+      boolean b = mText.indexOf("@hide") >= 0 || mText.indexOf("@pending") >= 0;
+      mHidden = b ? 1 : 0;
+      return b;
+    }
+  }
+
+  public boolean isDocOnly() {
+    if (mDocOnly != -1) {
+      return mDocOnly != 0;
+    } else {
+      boolean b = (mText != null) && (mText.indexOf("@doconly") >= 0);
+      mDocOnly = b ? 1 : 0;
+      return b;
+    }
+  }
+  
+  public boolean isDeprecated() {
+    if (mDeprecated != -1) {
+      return mDeprecated != 0;
+    } else {
+      boolean b = (mText != null) && (mText.indexOf("@deprecated") >= 0);
+      mDeprecated = b ? 1 : 0;
+      return b;
+    }
+  }
+
+  private void init() {
+    if (!mInitialized) {
+      initImpl();
+    }
+  }
+
+  private void initImpl() {
+    isHidden();
+    isDocOnly();
+    isDeprecated();
+
+    // Don't bother parsing text if we aren't generating documentation.
+    if (Doclava.generatingDocs()) {
+      parseRegex(mText);
+      parseBriefTags();
+    } else {
+      // Forces methods to be recognized by findOverriddenMethods in MethodInfo.
+      mInlineTagsList.add(new TextTagInfo("Text", "Text", mText,
+          SourcePositionInfo.add(mPosition, mText, 0)));
+    }
+
+    mText = null;
+    mInitialized = true;
+
+    mInlineTags = mInlineTagsList.toArray(new TagInfo[mInlineTagsList.size()]);
+    mParamTags = mParamTagsList.toArray(new ParamTagInfo[mParamTagsList.size()]);
+    mSeeTags = mSeeTagsList.toArray(new SeeTagInfo[mSeeTagsList.size()]);
+    mThrowsTags = mThrowsTagsList.toArray(new ThrowsTagInfo[mThrowsTagsList.size()]);
+    mReturnTags =
+        ParsedTagInfo.joinTags(mReturnTagsList.toArray(new ParsedTagInfo[mReturnTagsList.size()]));
+    mDeprecatedTags =
+        ParsedTagInfo.joinTags(mDeprecatedTagsList.toArray(new ParsedTagInfo[mDeprecatedTagsList
+            .size()]));
+    mUndeprecateTags = mUndeprecateTagsList.toArray(new TagInfo[mUndeprecateTagsList.size()]);
+    mAttrTags = mAttrTagsList.toArray(new AttrTagInfo[mAttrTagsList.size()]);
+    mBriefTags = mBriefTagsList.toArray(new TagInfo[mBriefTagsList.size()]);
+
+    mParamTagsList = null;
+    mSeeTagsList = null;
+    mThrowsTagsList = null;
+    mReturnTagsList = null;
+    mDeprecatedTagsList = null;
+    mUndeprecateTagsList = null;
+    mAttrTagsList = null;
+    mBriefTagsList = null;
+  }
+
+  boolean mInitialized;
+  int mHidden = -1;
+  int mDocOnly = -1;
+  int mDeprecated = -1;
+  String mText;
+  ContainerInfo mBase;
+  SourcePositionInfo mPosition;
+  int mLine = 1;
+
+  TagInfo[] mInlineTags;
+  TagInfo[] mTags;
+  ParamTagInfo[] mParamTags;
+  SeeTagInfo[] mSeeTags;
+  ThrowsTagInfo[] mThrowsTags;
+  TagInfo[] mBriefTags;
+  TagInfo[] mReturnTags;
+  TagInfo[] mDeprecatedTags;
+  TagInfo[] mUndeprecateTags;
+  AttrTagInfo[] mAttrTags;
+
+  ArrayList<TagInfo> mInlineTagsList = new ArrayList<TagInfo>();
+  ArrayList<TagInfo> mTagsList = new ArrayList<TagInfo>();
+  ArrayList<ParamTagInfo> mParamTagsList = new ArrayList<ParamTagInfo>();
+  ArrayList<SeeTagInfo> mSeeTagsList = new ArrayList<SeeTagInfo>();
+  ArrayList<ThrowsTagInfo> mThrowsTagsList = new ArrayList<ThrowsTagInfo>();
+  ArrayList<TagInfo> mBriefTagsList = new ArrayList<TagInfo>();
+  ArrayList<ParsedTagInfo> mReturnTagsList = new ArrayList<ParsedTagInfo>();
+  ArrayList<ParsedTagInfo> mDeprecatedTagsList = new ArrayList<ParsedTagInfo>();
+  ArrayList<TagInfo> mUndeprecateTagsList = new ArrayList<TagInfo>();
+  ArrayList<AttrTagInfo> mAttrTagsList = new ArrayList<AttrTagInfo>();
+
+
+}
diff --git a/src/com/google/doclava/ConstructorInfo.java b/src/com/google/doclava/ConstructorInfo.java
new file mode 100644
index 0000000..0f2c2fd
--- /dev/null
+++ b/src/com/google/doclava/ConstructorInfo.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.doclava.apicheck.AbstractMethodInfo;
+
+import java.util.*;
+
+public class ConstructorInfo implements AbstractMethodInfo {
+
+  private boolean mIsVarargs;
+  private String mName;
+  private String mType;
+  private boolean mIsStatic;
+  private boolean mIsFinal;
+  private String mDeprecated;
+  private boolean mIsDeprecated;
+  private String mScope;
+  private List<String> mExceptions;
+  private List<ParameterInfo> mParameters;
+  private SourcePositionInfo mSourcePosition;
+  private ClassInfo mClass;
+
+  public ConstructorInfo(String name, String type, boolean isStatic, boolean isFinal,
+      String deprecated, String scope, SourcePositionInfo pos, ClassInfo clazz) {
+    mName = name;
+    mType = type;
+    mIsStatic = isStatic;
+    mIsFinal = isFinal;
+    mDeprecated = deprecated;
+    mIsDeprecated = "deprecated".equals(deprecated);
+    mScope = scope;
+    mExceptions = new ArrayList<String>();
+    mParameters = new ArrayList<ParameterInfo>();
+    mSourcePosition = pos;
+    mClass = clazz;
+  }
+  
+  public void setDeprecated(boolean deprecated) {
+    mIsDeprecated = deprecated;
+  }
+
+  public void addParameter(ParameterInfo pInfo) {
+    mParameters.add(pInfo);
+  }
+
+  public void addException(String exec) {
+    mExceptions.add(exec);
+  }
+
+  public String getHashableName() {
+    StringBuilder result = new StringBuilder();
+    result.append(name());
+    for (ParameterInfo pInfo : mParameters) {
+      result.append(":").append(pInfo.typeName());
+    }
+    return result.toString();
+  }
+
+  public SourcePositionInfo position() {
+    return mSourcePosition;
+  }
+
+  public String name() {
+    return mName;
+  }
+
+  public String qualifiedName() {
+    String baseName = (mClass != null) ? (mClass.qualifiedName() + ".") : "";
+    return baseName + name();
+  }
+
+  public String prettySignature() {
+    String params = "";
+    for (ParameterInfo pInfo : mParameters) {
+      if (params.length() > 0) {
+        params += ", ";
+      }
+      params += pInfo.typeName();
+    }
+    return qualifiedName() + '(' + params + ')';
+  }
+
+  public boolean isConsistent(ConstructorInfo mInfo) {
+    boolean consistent = true;
+
+    if (mIsFinal != mInfo.mIsFinal) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_FINAL, mInfo.position(), "Constructor " + mInfo.qualifiedName()
+          + " has changed 'final' qualifier");
+    }
+
+    if (mIsStatic != mInfo.mIsStatic) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_FINAL, mInfo.position(), "Constructor " + mInfo.qualifiedName()
+          + " has changed 'static' qualifier");
+    }
+
+    if (!mScope.equals(mInfo.mScope)) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_SCOPE, mInfo.position(), "Constructor " + mInfo.qualifiedName()
+          + " changed scope from " + mScope + " to " + mInfo.mScope);
+    }
+
+    if (!mIsDeprecated == mInfo.mIsDeprecated) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_DEPRECATED, mInfo.position(), "Constructor "
+          + mInfo.qualifiedName() + " has changed deprecation state");
+    }
+
+    for (String exec : mExceptions) {
+      if (!mInfo.mExceptions.contains(exec)) {
+        Errors.error(Errors.CHANGED_THROWS, mInfo.position(), "Constructor "
+            + mInfo.qualifiedName() + " no longer throws exception " + exec);
+        consistent = false;
+      }
+    }
+
+    for (String exec : mInfo.mExceptions) {
+      if (!mExceptions.contains(exec)) {
+        Errors.error(Errors.CHANGED_THROWS, mInfo.position(), "Constructor "
+            + mInfo.qualifiedName() + " added thrown exception " + exec);
+        consistent = false;
+      }
+    }
+
+    return consistent;
+  }
+
+  @Override
+  public void setVarargs(boolean varargs) {
+    mIsVarargs = varargs;
+  }
+
+  public boolean isVarArgs() {
+    return mIsVarargs;
+  }
+
+}
diff --git a/src/com/google/doclava/ContainerInfo.java b/src/com/google/doclava/ContainerInfo.java
new file mode 100644
index 0000000..bde9506
--- /dev/null
+++ b/src/com/google/doclava/ContainerInfo.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+public interface ContainerInfo {
+  public String qualifiedName();
+
+  public boolean checkLevel();
+}
diff --git a/src/com/google/doclava/Converter.java b/src/com/google/doclava/Converter.java
new file mode 100644
index 0000000..06b7acb
--- /dev/null
+++ b/src/com/google/doclava/Converter.java
@@ -0,0 +1,661 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.sun.javadoc.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+
+public class Converter {
+  private static RootDoc root;
+
+  public static void makeInfo(RootDoc r) {
+    root = r;
+
+    int N, i;
+
+    // create the objects
+    ClassDoc[] classDocs = r.classes();
+    N = classDocs.length;
+    for (i = 0; i < N; i++) {
+      Converter.obtainClass(classDocs[i]);
+    }
+    ArrayList<ClassInfo> classesNeedingInit2 = new ArrayList<ClassInfo>();
+    // fill in the fields that reference other classes
+    while (mClassesNeedingInit.size() > 0) {
+      i = mClassesNeedingInit.size() - 1;
+      ClassNeedingInit clni = mClassesNeedingInit.get(i);
+      mClassesNeedingInit.remove(i);
+
+      initClass(clni.c, clni.cl);
+      classesNeedingInit2.add(clni.cl);
+    }
+    mClassesNeedingInit = null;
+    for (ClassInfo cl : classesNeedingInit2) {
+      cl.init2();
+    }
+
+    finishAnnotationValueInit();
+
+    // fill in the "root" stuff
+    mRootClasses = Converter.convertClasses(r.classes());
+  }
+
+  private static ClassInfo[] mRootClasses;
+
+  public static ClassInfo[] rootClasses() {
+    return mRootClasses;
+  }
+
+  public static ClassInfo[] allClasses() {
+    return (ClassInfo[]) mClasses.all();
+  }
+
+  private static void initClass(ClassDoc c, ClassInfo cl) {
+    MethodDoc[] annotationElements;
+    if (c instanceof AnnotationTypeDoc) {
+      annotationElements = ((AnnotationTypeDoc) c).elements();
+    } else {
+      annotationElements = new MethodDoc[0];
+    }
+    cl.init(Converter.obtainType(c), Converter.convertClasses(c.interfaces()), Converter
+        .convertTypes(c.interfaceTypes()), Converter.convertClasses(c.innerClasses()), Converter
+        .convertMethods(c.constructors(false)), Converter.convertMethods(c.methods(false)),
+        Converter.convertMethods(annotationElements), Converter.convertFields(c.fields(false)),
+        Converter.convertFields(c.enumConstants()), Converter.obtainPackage(c.containingPackage()),
+        Converter.obtainClass(c.containingClass()), Converter.obtainClass(c.superclass()),
+        Converter.obtainType(c.superclassType()), Converter.convertAnnotationInstances(c
+            .annotations()));
+    cl.setHiddenMethods(Converter.getHiddenMethods(c.methods(false)));
+    cl.setNonWrittenConstructors(Converter.convertNonWrittenConstructors(c.constructors(false)));
+    cl.init3(Converter.convertTypes(c.typeParameters()), Converter.convertClasses(c
+        .innerClasses(false)));
+  }
+
+  public static ClassInfo obtainClass(String className) {
+    return Converter.obtainClass(root.classNamed(className));
+  }
+
+  public static PackageInfo obtainPackage(String packageName) {
+    return Converter.obtainPackage(root.packageNamed(packageName));
+  }
+
+  private static TagInfo convertTag(Tag tag) {
+    return new TextTagInfo(tag.name(), tag.kind(), tag.text(), Converter.convertSourcePosition(tag
+        .position()));
+  }
+
+  private static ThrowsTagInfo convertThrowsTag(ThrowsTag tag, ContainerInfo base) {
+    return new ThrowsTagInfo(tag.name(), tag.text(), tag.kind(), Converter.obtainClass(tag
+        .exception()), tag.exceptionComment(), base, Converter
+        .convertSourcePosition(tag.position()));
+  }
+
+  private static ParamTagInfo convertParamTag(ParamTag tag, ContainerInfo base) {
+    return new ParamTagInfo(tag.name(), tag.kind(), tag.text(), tag.isTypeParameter(), tag
+        .parameterComment(), tag.parameterName(), base, Converter.convertSourcePosition(tag
+        .position()));
+  }
+
+  private static SeeTagInfo convertSeeTag(SeeTag tag, ContainerInfo base) {
+    return new SeeTagInfo(tag.name(), tag.kind(), tag.text(), base, Converter
+        .convertSourcePosition(tag.position()));
+  }
+
+  private static SourcePositionInfo convertSourcePosition(SourcePosition sp) {
+    if (sp == null) {
+      return null;
+    }
+    return new SourcePositionInfo(sp.file().toString(), sp.line(), sp.column());
+  }
+
+  public static TagInfo[] convertTags(Tag[] tags, ContainerInfo base) {
+    int len = tags.length;
+    TagInfo[] out = new TagInfo[len];
+    for (int i = 0; i < len; i++) {
+      Tag t = tags[i];
+      /*
+       * System.out.println("Tag name='" + t.name() + "' kind='" + t.kind() + "'");
+       */
+      if (t instanceof SeeTag) {
+        out[i] = Converter.convertSeeTag((SeeTag) t, base);
+      } else if (t instanceof ThrowsTag) {
+        out[i] = Converter.convertThrowsTag((ThrowsTag) t, base);
+      } else if (t instanceof ParamTag) {
+        out[i] = Converter.convertParamTag((ParamTag) t, base);
+      } else {
+        out[i] = Converter.convertTag(t);
+      }
+    }
+    return out;
+  }
+
+  public static ClassInfo[] convertClasses(ClassDoc[] classes) {
+    if (classes == null) return null;
+    int N = classes.length;
+    ClassInfo[] result = new ClassInfo[N];
+    for (int i = 0; i < N; i++) {
+      result[i] = Converter.obtainClass(classes[i]);
+    }
+    return result;
+  }
+
+  private static ParameterInfo convertParameter(Parameter p, SourcePosition pos, boolean isVarArg) {
+    if (p == null) return null;
+    ParameterInfo pi =
+        new ParameterInfo(p.name(), p.typeName(), Converter.obtainType(p.type()), isVarArg,
+          Converter.convertSourcePosition(pos));
+    return pi;
+  }
+
+  private static ParameterInfo[] convertParameters(Parameter[] p, ExecutableMemberDoc m) {
+    SourcePosition pos = m.position();
+    int len = p.length;
+    ParameterInfo[] q = new ParameterInfo[len];
+    for (int i = 0; i < len; i++) {
+      boolean isVarArg = (m.isVarArgs() && i == len - 1);
+      q[i] = Converter.convertParameter(p[i], pos, isVarArg);
+    }
+    return q;
+  }
+
+  private static TypeInfo[] convertTypes(Type[] p) {
+    if (p == null) return null;
+    int len = p.length;
+    TypeInfo[] q = new TypeInfo[len];
+    for (int i = 0; i < len; i++) {
+      q[i] = Converter.obtainType(p[i]);
+    }
+    return q;
+  }
+
+  private Converter() {}
+
+  private static class ClassNeedingInit {
+    ClassNeedingInit(ClassDoc c, ClassInfo cl) {
+      this.c = c;
+      this.cl = cl;
+    }
+
+    ClassDoc c;
+    ClassInfo cl;
+  }
+
+  private static ArrayList<ClassNeedingInit> mClassesNeedingInit =
+      new ArrayList<ClassNeedingInit>();
+
+  static ClassInfo obtainClass(ClassDoc o) {
+    return (ClassInfo) mClasses.obtain(o);
+  }
+
+  private static Cache mClasses = new Cache() {
+    @Override
+    protected Object make(Object o) {
+      ClassDoc c = (ClassDoc) o;
+      ClassInfo cl =
+          new ClassInfo(c, c.getRawCommentText(), Converter.convertSourcePosition(c.position()), c
+              .isPublic(), c.isProtected(), c.isPackagePrivate(), c.isPrivate(), c.isStatic(), c
+              .isInterface(), c.isAbstract(), c.isOrdinaryClass(), c.isException(), c.isError(), c
+              .isEnum(), (c instanceof AnnotationTypeDoc), c.isFinal(), c.isIncluded(), c.name(), c
+              .qualifiedName(), c.qualifiedTypeName(), c.isPrimitive());
+      if (mClassesNeedingInit != null) {
+        mClassesNeedingInit.add(new ClassNeedingInit(c, cl));
+      }
+      return cl;
+    }
+
+    @Override
+    protected void made(Object o, Object r) {
+      if (mClassesNeedingInit == null) {
+        initClass((ClassDoc) o, (ClassInfo) r);
+        ((ClassInfo) r).init2();
+      }
+    }
+
+    @Override
+    ClassInfo[] all() {
+      return mCache.values().toArray(new ClassInfo[mCache.size()]);
+    }
+  };
+
+  private static MethodInfo[] getHiddenMethods(MethodDoc[] methods) {
+    if (methods == null) return null;
+    ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
+    int N = methods.length;
+    for (int i = 0; i < N; i++) {
+      MethodInfo m = Converter.obtainMethod(methods[i]);
+      // System.out.println(m.toString() + ": ");
+      // for (TypeInfo ti : m.getTypeParameters()){
+      // if (ti.asClassInfo() != null){
+      // System.out.println(" " +ti.asClassInfo().toString());
+      // } else {
+      // System.out.println(" null");
+      // }
+      // }
+      if (m.isHidden()) {
+        out.add(m);
+      }
+    }
+    return out.toArray(new MethodInfo[out.size()]);
+  }
+
+  /**
+   * Convert MethodDoc[] into MethodInfo[]. Also filters according to the -private, -public option,
+   * because the filtering doesn't seem to be working in the ClassDoc.constructors(boolean) call.
+   */
+  private static MethodInfo[] convertMethods(MethodDoc[] methods) {
+    if (methods == null) return null;
+    ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
+    int N = methods.length;
+    for (int i = 0; i < N; i++) {
+      MethodInfo m = Converter.obtainMethod(methods[i]);
+      // System.out.println(m.toString() + ": ");
+      // for (TypeInfo ti : m.getTypeParameters()){
+      // if (ti.asClassInfo() != null){
+      // System.out.println(" " +ti.asClassInfo().toString());
+      // } else {
+      // System.out.println(" null");
+      // }
+      // }
+      if (m.checkLevel()) {
+        out.add(m);
+      }
+    }
+    return out.toArray(new MethodInfo[out.size()]);
+  }
+
+  private static MethodInfo[] convertMethods(ConstructorDoc[] methods) {
+    if (methods == null) return null;
+    ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
+    int N = methods.length;
+    for (int i = 0; i < N; i++) {
+      MethodInfo m = Converter.obtainMethod(methods[i]);
+      if (m.checkLevel()) {
+        out.add(m);
+      }
+    }
+    return out.toArray(new MethodInfo[out.size()]);
+  }
+
+  private static MethodInfo[] convertNonWrittenConstructors(ConstructorDoc[] methods) {
+    if (methods == null) return null;
+    ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
+    int N = methods.length;
+    for (int i = 0; i < N; i++) {
+      MethodInfo m = Converter.obtainMethod(methods[i]);
+      if (!m.checkLevel()) {
+        out.add(m);
+      }
+    }
+    return out.toArray(new MethodInfo[out.size()]);
+  }
+
+  private static MethodInfo obtainMethod(MethodDoc o) {
+    return (MethodInfo) mMethods.obtain(o);
+  }
+
+  private static MethodInfo obtainMethod(ConstructorDoc o) {
+    return (MethodInfo) mMethods.obtain(o);
+  }
+
+  private static Cache mMethods = new Cache() {
+    @Override
+    protected Object make(Object o) {
+      if (o instanceof AnnotationTypeElementDoc) {
+        AnnotationTypeElementDoc m = (AnnotationTypeElementDoc) o;
+        MethodInfo result =
+            new MethodInfo(m.getRawCommentText(), Converter.convertTypes(m.typeParameters()), m
+                .name(), m.signature(), Converter.obtainClass(m.containingClass()), Converter
+                .obtainClass(m.containingClass()), m.isPublic(), m.isProtected(), m
+                .isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(), m
+                .isAbstract(), m.isSynchronized(), m.isNative(), true, "annotationElement", m
+                .flatSignature(), Converter.obtainMethod(m.overriddenMethod()), Converter
+                .obtainType(m.returnType()), Converter.convertParameters(m.parameters(), m),
+                Converter.convertClasses(m.thrownExceptions()), Converter.convertSourcePosition(m
+                    .position()), Converter.convertAnnotationInstances(m.annotations()));
+        result.setVarargs(m.isVarArgs());
+        result.init(Converter.obtainAnnotationValue(m.defaultValue(), result));
+        return result;
+      } else if (o instanceof MethodDoc) {
+        MethodDoc m = (MethodDoc) o;
+        MethodInfo result =
+            new MethodInfo(m.getRawCommentText(), Converter.convertTypes(m.typeParameters()), m
+                .name(), m.signature(), Converter.obtainClass(m.containingClass()), Converter
+                .obtainClass(m.containingClass()), m.isPublic(), m.isProtected(), m
+                .isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(), m
+                .isAbstract(), m.isSynchronized(), m.isNative(), false, "method",
+                m.flatSignature(), Converter.obtainMethod(m.overriddenMethod()), Converter
+                    .obtainType(m.returnType()), Converter.convertParameters(m.parameters(), m),
+                Converter.convertClasses(m.thrownExceptions()), Converter.convertSourcePosition(m
+                    .position()), Converter.convertAnnotationInstances(m.annotations()));
+        result.setVarargs(m.isVarArgs());
+        result.init(null);
+        return result;
+      } else {
+        ConstructorDoc m = (ConstructorDoc) o;
+        MethodInfo result =
+            new MethodInfo(m.getRawCommentText(), Converter.convertTypes(m.typeParameters()), m
+                .name(), m.signature(), Converter.obtainClass(m.containingClass()), Converter
+                .obtainClass(m.containingClass()), m.isPublic(), m.isProtected(), m
+                .isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(),
+                false, m.isSynchronized(), m.isNative(), false, "constructor", m.flatSignature(),
+                null, null, Converter.convertParameters(m.parameters(), m), Converter
+                    .convertClasses(m.thrownExceptions()), Converter.convertSourcePosition(m
+                    .position()), Converter.convertAnnotationInstances(m.annotations()));
+        result.setVarargs(m.isVarArgs());
+        result.init(null);
+        return result;
+      }
+    }
+  };
+
+
+  private static FieldInfo[] convertFields(FieldDoc[] fields) {
+    if (fields == null) return null;
+    ArrayList<FieldInfo> out = new ArrayList<FieldInfo>();
+    int N = fields.length;
+    for (int i = 0; i < N; i++) {
+      FieldInfo f = Converter.obtainField(fields[i]);
+      if (f.checkLevel()) {
+        out.add(f);
+      }
+    }
+    return out.toArray(new FieldInfo[out.size()]);
+  }
+
+  private static FieldInfo obtainField(FieldDoc o) {
+    return (FieldInfo) mFields.obtain(o);
+  }
+
+  private static FieldInfo obtainField(ConstructorDoc o) {
+    return (FieldInfo) mFields.obtain(o);
+  }
+
+  private static Cache mFields = new Cache() {
+    @Override
+    protected Object make(Object o) {
+      FieldDoc f = (FieldDoc) o;
+      return new FieldInfo(f.name(), Converter.obtainClass(f.containingClass()), Converter
+          .obtainClass(f.containingClass()), f.isPublic(), f.isProtected(), f.isPackagePrivate(), f
+          .isPrivate(), f.isFinal(), f.isStatic(), f.isTransient(), f.isVolatile(),
+          f.isSynthetic(), Converter.obtainType(f.type()), f.getRawCommentText(),
+          f.constantValue(), Converter.convertSourcePosition(f.position()), Converter
+              .convertAnnotationInstances(f.annotations()));
+    }
+  };
+
+  private static PackageInfo obtainPackage(PackageDoc o) {
+    return (PackageInfo) mPackagees.obtain(o);
+  }
+
+  private static Cache mPackagees = new Cache() {
+    @Override
+    protected Object make(Object o) {
+      PackageDoc p = (PackageDoc) o;
+      return new PackageInfo(p, p.name(), Converter.convertSourcePosition(p.position()));
+    }
+  };
+
+  private static TypeInfo obtainType(Type o) {
+    return (TypeInfo) mTypes.obtain(o);
+  }
+
+  private static Cache mTypes = new Cache() {
+    @Override
+    protected Object make(Object o) {
+      Type t = (Type) o;
+      String simpleTypeName;
+      if (t instanceof ClassDoc) {
+        simpleTypeName = ((ClassDoc) t).name();
+      } else {
+        simpleTypeName = t.simpleTypeName();
+      }
+      TypeInfo ti =
+          new TypeInfo(t.isPrimitive(), t.dimension(), simpleTypeName, t.qualifiedTypeName(),
+              Converter.obtainClass(t.asClassDoc()));
+      return ti;
+    }
+
+    @Override
+    protected void made(Object o, Object r) {
+      Type t = (Type) o;
+      TypeInfo ti = (TypeInfo) r;
+      if (t.asParameterizedType() != null) {
+        ti.setTypeArguments(Converter.convertTypes(t.asParameterizedType().typeArguments()));
+      } else if (t instanceof ClassDoc) {
+        ti.setTypeArguments(Converter.convertTypes(((ClassDoc) t).typeParameters()));
+      } else if (t.asTypeVariable() != null) {
+        ti.setBounds(null, Converter.convertTypes((t.asTypeVariable().bounds())));
+        ti.setIsTypeVariable(true);
+      } else if (t.asWildcardType() != null) {
+        ti.setIsWildcard(true);
+        ti.setBounds(Converter.convertTypes(t.asWildcardType().superBounds()), Converter
+            .convertTypes(t.asWildcardType().extendsBounds()));
+      }
+    }
+
+    @Override
+    protected Object keyFor(Object o) {
+      Type t = (Type) o;
+      String keyString = o.getClass().getName() + "/" + o.toString() + "/";
+      if (t.asParameterizedType() != null) {
+        keyString += t.asParameterizedType().toString() + "/";
+        if (t.asParameterizedType().typeArguments() != null) {
+          for (Type ty : t.asParameterizedType().typeArguments()) {
+            keyString += ty.toString() + "/";
+          }
+        }
+      } else {
+        keyString += "NoParameterizedType//";
+      }
+      if (t.asTypeVariable() != null) {
+        keyString += t.asTypeVariable().toString() + "/";
+        if (t.asTypeVariable().bounds() != null) {
+          for (Type ty : t.asTypeVariable().bounds()) {
+            keyString += ty.toString() + "/";
+          }
+        }
+      } else {
+        keyString += "NoTypeVariable//";
+      }
+      if (t.asWildcardType() != null) {
+        keyString += t.asWildcardType().toString() + "/";
+        if (t.asWildcardType().superBounds() != null) {
+          for (Type ty : t.asWildcardType().superBounds()) {
+            keyString += ty.toString() + "/";
+          }
+        }
+        if (t.asWildcardType().extendsBounds() != null) {
+          for (Type ty : t.asWildcardType().extendsBounds()) {
+            keyString += ty.toString() + "/";
+          }
+        }
+      } else {
+        keyString += "NoWildCardType//";
+      }
+
+      return keyString;
+    }
+  };
+  
+  public static TypeInfo obtainTypeFromString(String type) {
+    return (TypeInfo) mTypesFromString.obtain(type);
+  }
+  
+  private static final Cache mTypesFromString = new Cache() {
+    @Override
+    protected Object make(Object o) {
+      String name = (String) o;
+      return new TypeInfo(name);
+    }
+
+    @Override
+    protected void made(Object o, Object r) {
+      
+    }
+
+    @Override
+    protected Object keyFor(Object o) {
+      return o;
+    }
+  };
+
+  private static MemberInfo obtainMember(MemberDoc o) {
+    return (MemberInfo) mMembers.obtain(o);
+  }
+
+  private static Cache mMembers = new Cache() {
+    @Override
+    protected Object make(Object o) {
+      if (o instanceof MethodDoc) {
+        return Converter.obtainMethod((MethodDoc) o);
+      } else if (o instanceof ConstructorDoc) {
+        return Converter.obtainMethod((ConstructorDoc) o);
+      } else if (o instanceof FieldDoc) {
+        return Converter.obtainField((FieldDoc) o);
+      } else {
+        return null;
+      }
+    }
+  };
+
+  private static AnnotationInstanceInfo[] convertAnnotationInstances(AnnotationDesc[] orig) {
+    int len = orig.length;
+    AnnotationInstanceInfo[] out = new AnnotationInstanceInfo[len];
+    for (int i = 0; i < len; i++) {
+      out[i] = Converter.obtainAnnotationInstance(orig[i]);
+    }
+    return out;
+  }
+
+
+  private static AnnotationInstanceInfo obtainAnnotationInstance(AnnotationDesc o) {
+    return (AnnotationInstanceInfo) mAnnotationInstances.obtain(o);
+  }
+
+  private static Cache mAnnotationInstances = new Cache() {
+    @Override
+    protected Object make(Object o) {
+      AnnotationDesc a = (AnnotationDesc) o;
+      ClassInfo annotationType = Converter.obtainClass(a.annotationType());
+      AnnotationDesc.ElementValuePair[] ev = a.elementValues();
+      AnnotationValueInfo[] elementValues = new AnnotationValueInfo[ev.length];
+      for (int i = 0; i < ev.length; i++) {
+        elementValues[i] =
+            obtainAnnotationValue(ev[i].value(), Converter.obtainMethod(ev[i].element()));
+      }
+      return new AnnotationInstanceInfo(annotationType, elementValues);
+    }
+  };
+
+
+  private abstract static class Cache {
+    void put(Object key, Object value) {
+      mCache.put(key, value);
+    }
+
+    Object obtain(Object o) {
+      if (o == null) {
+        return null;
+      }
+      Object k = keyFor(o);
+      Object r = mCache.get(k);
+      if (r == null) {
+        r = make(o);
+        mCache.put(k, r);
+        made(o, r);
+      }
+      return r;
+    }
+
+    protected HashMap<Object, Object> mCache = new HashMap<Object, Object>();
+
+    protected abstract Object make(Object o);
+
+    protected void made(Object o, Object r) {}
+
+    protected Object keyFor(Object o) {
+      return o;
+    }
+
+    Object[] all() {
+      return null;
+    }
+  }
+
+  // annotation values
+  private static HashMap<AnnotationValue, AnnotationValueInfo> mAnnotationValues =
+      new HashMap<AnnotationValue, AnnotationValueInfo>();
+  private static HashSet<AnnotationValue> mAnnotationValuesNeedingInit =
+      new HashSet<AnnotationValue>();
+
+  private static AnnotationValueInfo obtainAnnotationValue(AnnotationValue o, MethodInfo element) {
+    if (o == null) {
+      return null;
+    }
+    AnnotationValueInfo v = mAnnotationValues.get(o);
+    if (v != null) return v;
+    v = new AnnotationValueInfo(element);
+    mAnnotationValues.put(o, v);
+    if (mAnnotationValuesNeedingInit != null) {
+      mAnnotationValuesNeedingInit.add(o);
+    } else {
+      initAnnotationValue(o, v);
+    }
+    return v;
+  }
+
+  private static void initAnnotationValue(AnnotationValue o, AnnotationValueInfo v) {
+    Object orig = o.value();
+    Object converted;
+    if (orig instanceof Type) {
+      // class literal
+      converted = Converter.obtainType((Type) orig);
+    } else if (orig instanceof FieldDoc) {
+      // enum constant
+      converted = Converter.obtainField((FieldDoc) orig);
+    } else if (orig instanceof AnnotationDesc) {
+      // annotation instance
+      converted = Converter.obtainAnnotationInstance((AnnotationDesc) orig);
+    } else if (orig instanceof AnnotationValue[]) {
+      AnnotationValue[] old = (AnnotationValue[]) orig;
+      AnnotationValueInfo[] array = new AnnotationValueInfo[old.length];
+      for (int i = 0; i < array.length; i++) {
+        array[i] = Converter.obtainAnnotationValue(old[i], null);
+      }
+      converted = array;
+    } else {
+      converted = orig;
+    }
+    v.init(converted);
+  }
+
+  private static void finishAnnotationValueInit() {
+    int depth = 0;
+    while (mAnnotationValuesNeedingInit.size() > 0) {
+      HashSet<AnnotationValue> set = mAnnotationValuesNeedingInit;
+      mAnnotationValuesNeedingInit = new HashSet<AnnotationValue>();
+      for (AnnotationValue o : set) {
+        AnnotationValueInfo v = mAnnotationValues.get(o);
+        initAnnotationValue(o, v);
+      }
+      depth++;
+    }
+    mAnnotationValuesNeedingInit = null;
+  }
+}
diff --git a/src/com/google/doclava/DocFile.java b/src/com/google/doclava/DocFile.java
new file mode 100644
index 0000000..ab0a4fd
--- /dev/null
+++ b/src/com/google/doclava/DocFile.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.io.*;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+
+public class DocFile {
+  private static final Pattern LINE = Pattern.compile("(.*)[\r]?\n", Pattern.MULTILINE);
+  private static final Pattern PROP = Pattern.compile("([^=]+)=(.*)");
+
+  public static String readFile(String filename) {
+    try {
+      File f = new File(filename);
+      int length = (int) f.length();
+      FileInputStream is = new FileInputStream(f);
+      InputStreamReader reader = new InputStreamReader(is, "UTF-8");
+      char[] buf = new char[length];
+      int index = 0;
+      int amt;
+      while (true) {
+        amt = reader.read(buf, index, length - index);
+
+        if (amt < 1) {
+          break;
+        }
+
+        index += amt;
+      }
+      return new String(buf, 0, index);
+    } catch (IOException e) {
+      return null;
+    }
+  }
+
+  public static void writePage(String docfile, String relative, String outfile) {
+    Data hdf = Doclava.makeHDF();
+
+    /*
+     * System.out.println("docfile='" + docfile + "' relative='" + relative + "'" + "' outfile='" +
+     * outfile + "'");
+     */
+
+    String filedata = readFile(docfile);
+
+    // The document is properties up until the line "@jd:body".
+    // Any blank lines are ignored.
+    int start = -1;
+    int lineno = 1;
+    Matcher lines = LINE.matcher(filedata);
+    String line = null;
+    while (lines.find()) {
+      line = lines.group(1);
+      if (line.length() > 0) {
+        if (line.equals("@jd:body")) {
+          start = lines.end();
+          break;
+        }
+        Matcher prop = PROP.matcher(line);
+        if (prop.matches()) {
+          String key = prop.group(1);
+          String value = prop.group(2);
+          hdf.setValue(key, value);
+        } else {
+          break;
+        }
+      }
+      lineno++;
+    }
+    if (start < 0) {
+      System.err.println(docfile + ":" + lineno + ": error parsing docfile");
+      if (line != null) {
+        System.err.println(docfile + ":" + lineno + ":" + line);
+      }
+      System.exit(1);
+    }
+
+    // if they asked to only be for a certain template, maybe skip it
+    String fromTemplate = hdf.getValue("template.which", "");
+    String fromPage = hdf.getValue("page.onlyfortemplate", "");
+    if (!"".equals(fromPage) && !fromTemplate.equals(fromPage)) {
+      return;
+    }
+
+    // and the actual text after that
+    String commentText = filedata.substring(start);
+
+    Comment comment = new Comment(commentText, null, new SourcePositionInfo(docfile, lineno, 1));
+    TagInfo[] tags = comment.tags();
+
+    TagInfo.makeHDF(hdf, "root.descr", tags);
+
+    hdf.setValue("commentText", commentText);
+
+    // write the page using the appropriate root template, based on the
+    // whichdoc value supplied by build
+    String fromWhichmodule = hdf.getValue("android.whichmodule", "");
+    if (fromWhichmodule.equals("online-pdk")) {
+      // leaving this in just for temporary compatibility with pdk doc
+      hdf.setValue("online-pdk", "true");
+      // add any conditional login for root template here (such as
+      // for custom left nav based on tab etc.
+      ClearPage.write(hdf, "docpage.cs", outfile);
+    } else {
+      if (outfile.indexOf("sdk/") != -1) {
+        hdf.setValue("sdk", "true");
+        if ((outfile.indexOf("index.html") != -1) || (outfile.indexOf("features.html") != -1)) {
+          ClearPage.write(hdf, "sdkpage.cs", outfile);
+        } else {
+          ClearPage.write(hdf, "docpage.cs", outfile);
+        }
+      } else if (outfile.indexOf("guide/") != -1) {
+        hdf.setValue("guide", "true");
+        ClearPage.write(hdf, "docpage.cs", outfile);
+      } else if (outfile.indexOf("resources/") != -1) {
+        hdf.setValue("resources", "true");
+        ClearPage.write(hdf, "docpage.cs", outfile);
+      } else {
+        ClearPage.write(hdf, "nosidenavpage.cs", outfile);
+      }
+    }
+  } // writePage
+}
diff --git a/src/com/google/doclava/DocInfo.java b/src/com/google/doclava/DocInfo.java
new file mode 100644
index 0000000..d1fdae1
--- /dev/null
+++ b/src/com/google/doclava/DocInfo.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+public abstract class DocInfo {
+  public DocInfo(String rawCommentText, SourcePositionInfo sp) {
+    mRawCommentText = rawCommentText;
+    mPosition = sp;
+  }
+
+  /**
+   * The relative path to a web page representing this item.
+   */
+  public abstract String htmlPage();
+  
+  public boolean isHidden() {
+    return comment().isHidden();
+  }
+
+  public boolean isDocOnly() {
+    return comment().isDocOnly();
+  }
+
+  public String getRawCommentText() {
+    return mRawCommentText;
+  }
+
+  public Comment comment() {
+    if (mComment == null) {
+      mComment = new Comment(mRawCommentText, parent(), mPosition);
+    }
+    return mComment;
+  }
+
+  public SourcePositionInfo position() {
+    return mPosition;
+  }
+
+  public abstract ContainerInfo parent();
+
+  public void setSince(String since) {
+    mSince = since;
+  }
+
+  public String getSince() {
+    return mSince;
+  }
+  
+  public final void addFederatedReference(FederatedSite source) {
+    mFederatedReferences.add(source);
+  }
+  
+  public final Set<FederatedSite> getFederatedReferences() {
+    return mFederatedReferences;
+  }
+  
+  public final void setFederatedReferences(Data data, String base) {
+    int pos = 0;
+    for (FederatedSite source : getFederatedReferences()) {
+      data.setValue(base + ".federated." + pos + ".url", source.linkFor(htmlPage()));
+      data.setValue(base + ".federated." + pos + ".name", source.name());
+      pos++;
+    }
+  }
+
+  private String mRawCommentText;
+  Comment mComment;
+  SourcePositionInfo mPosition;
+  private String mSince;
+  private Set<FederatedSite> mFederatedReferences = new LinkedHashSet<FederatedSite>();
+}
diff --git a/src/com/google/doclava/Doclava.java b/src/com/google/doclava/Doclava.java
new file mode 100644
index 0000000..9489090
--- /dev/null
+++ b/src/com/google/doclava/Doclava.java
@@ -0,0 +1,1375 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.JSilver;
+import com.google.clearsilver.jsilver.data.Data;
+import com.google.clearsilver.jsilver.resourceloader.ClassResourceLoader;
+import com.google.clearsilver.jsilver.resourceloader.CompositeResourceLoader;
+import com.google.clearsilver.jsilver.resourceloader.FileSystemResourceLoader;
+import com.google.clearsilver.jsilver.resourceloader.ResourceLoader;
+
+import com.sun.javadoc.*;
+
+import java.util.*;
+import java.util.jar.JarFile;
+import java.io.*;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class Doclava {
+  private static final String SDK_CONSTANT_ANNOTATION = "android.annotation.SdkConstant";
+  private static final String SDK_CONSTANT_TYPE_ACTIVITY_ACTION =
+      "android.annotation.SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION";
+  private static final String SDK_CONSTANT_TYPE_BROADCAST_ACTION =
+      "android.annotation.SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION";
+  private static final String SDK_CONSTANT_TYPE_SERVICE_ACTION =
+      "android.annotation.SdkConstant.SdkConstantType.SERVICE_INTENT_ACTION";
+  private static final String SDK_CONSTANT_TYPE_CATEGORY =
+      "android.annotation.SdkConstant.SdkConstantType.INTENT_CATEGORY";
+  private static final String SDK_CONSTANT_TYPE_FEATURE =
+      "android.annotation.SdkConstant.SdkConstantType.FEATURE";
+  private static final String SDK_WIDGET_ANNOTATION = "android.annotation.Widget";
+  private static final String SDK_LAYOUT_ANNOTATION = "android.annotation.Layout";
+
+  private static final int TYPE_NONE = 0;
+  private static final int TYPE_WIDGET = 1;
+  private static final int TYPE_LAYOUT = 2;
+  private static final int TYPE_LAYOUT_PARAM = 3;
+
+  public static final int SHOW_PUBLIC = 0x00000001;
+  public static final int SHOW_PROTECTED = 0x00000003;
+  public static final int SHOW_PACKAGE = 0x00000007;
+  public static final int SHOW_PRIVATE = 0x0000000f;
+  public static final int SHOW_HIDDEN = 0x0000001f;
+
+  public static int showLevel = SHOW_PROTECTED;
+
+  public static final String javadocDir = "reference/";
+  public static String htmlExtension;
+
+  public static RootDoc root;
+  public static ArrayList<String[]> mHDFData = new ArrayList<String[]>();
+  public static Map<Character, String> escapeChars = new HashMap<Character, String>();
+  public static String title = "";
+  public static SinceTagger sinceTagger = new SinceTagger();
+  public static FederationTagger federationTagger = new FederationTagger();
+  private static boolean generatingDocs = true;
+  
+  public static JSilver jSilver = null;
+
+  public static boolean checkLevel(int level) {
+    return (showLevel & level) == level;
+  }
+  
+  /**
+   * Returns true if we are generating html reference documentation.
+   */
+  public static boolean generatingDocs() {
+    return generatingDocs;
+  }
+
+  public static boolean checkLevel(boolean pub, boolean prot, boolean pkgp, boolean priv,
+      boolean hidden) {
+    int level = 0;
+    if (hidden && !checkLevel(SHOW_HIDDEN)) {
+      return false;
+    }
+    if (pub && checkLevel(SHOW_PUBLIC)) {
+      return true;
+    }
+    if (prot && checkLevel(SHOW_PROTECTED)) {
+      return true;
+    }
+    if (pkgp && checkLevel(SHOW_PACKAGE)) {
+      return true;
+    }
+    if (priv && checkLevel(SHOW_PRIVATE)) {
+      return true;
+    }
+    return false;
+  }
+
+  public static void main(String[] args) {
+    com.sun.tools.javadoc.Main.execute(args);
+  }
+
+  public static boolean start(RootDoc r) {
+    String keepListFile = null;
+    String proofreadFile = null;
+    String todoFile = null;
+    String sdkValuePath = null;
+    ArrayList<SampleCode> sampleCodes = new ArrayList<SampleCode>();
+    String stubsDir = null;
+    // Create the dependency graph for the stubs directory
+    boolean offlineMode = false;
+    String apiFile = null;
+    String debugStubsFile = "";
+    HashSet<String> stubPackages = null;
+
+    root = r;
+
+    String[][] options = r.options();
+    for (String[] a : options) {
+      if (a[0].equals("-d")) {
+        ClearPage.outputDir = a[1];
+      } else if (a[0].equals("-templatedir")) {
+        ClearPage.addTemplateDir(a[1]);
+      } else if (a[0].equals("-hdf")) {
+        mHDFData.add(new String[] {a[1], a[2]});
+      } else if (a[0].equals("-toroot")) {
+        ClearPage.toroot = a[1];
+      } else if (a[0].equals("-samplecode")) {
+        sampleCodes.add(new SampleCode(a[1], a[2], a[3]));
+      } else if (a[0].equals("-htmldir")) {
+        ClearPage.htmlDir = a[1];
+      } else if (a[0].equals("-title")) {
+        Doclava.title = a[1];
+      } else if (a[0].equals("-werror")) {
+        Errors.setWarningsAreErrors(true);
+      } else if (a[0].equals("-error") || a[0].equals("-warning") || a[0].equals("-hide")) {
+        try {
+          int level = -1;
+          if (a[0].equals("-error")) {
+            level = Errors.ERROR;
+          } else if (a[0].equals("-warning")) {
+            level = Errors.WARNING;
+          } else if (a[0].equals("-hide")) {
+            level = Errors.HIDDEN;
+          }
+          Errors.setErrorLevel(Integer.parseInt(a[1]), level);
+        } catch (NumberFormatException e) {
+          // already printed below
+          return false;
+        }
+      } else if (a[0].equals("-keeplist")) {
+        keepListFile = a[1];
+      } else if (a[0].equals("-proofread")) {
+        proofreadFile = a[1];
+      } else if (a[0].equals("-todo")) {
+        todoFile = a[1];
+      } else if (a[0].equals("-public")) {
+        showLevel = SHOW_PUBLIC;
+      } else if (a[0].equals("-protected")) {
+        showLevel = SHOW_PROTECTED;
+      } else if (a[0].equals("-package")) {
+        showLevel = SHOW_PACKAGE;
+      } else if (a[0].equals("-private")) {
+        showLevel = SHOW_PRIVATE;
+      } else if (a[0].equals("-hidden")) {
+        showLevel = SHOW_HIDDEN;
+      } else if (a[0].equals("-stubs")) {
+        stubsDir = a[1];
+      } else if (a[0].equals("-stubpackages")) {
+        stubPackages = new HashSet<String>();
+        for (String pkg : a[1].split(":")) {
+          stubPackages.add(pkg);
+        }
+      } else if (a[0].equals("-sdkvalues")) {
+        sdkValuePath = a[1];
+      } else if (a[0].equals("-apixml")) {
+        apiFile = a[1];
+      } else if (a[0].equals("-nodocs")) {
+        generatingDocs = false;
+      } else if (a[0].equals("-since")) {
+        sinceTagger.addVersion(a[1], a[2]);
+      } else if (a[0].equals("-offlinemode")) {
+        offlineMode = true;
+      } else if (a[0].equals("-federate")) {
+        try {
+          String name = a[1];
+          URL federationURL = new URL(a[2]);
+          federationTagger.addSite(name, federationURL);
+        } catch (MalformedURLException e) {
+          System.err.println("Could not parse URL for federation: " + a[1]);
+          return false;
+        }
+      }
+    }
+
+
+    // Set up the data structures
+    Converter.makeInfo(r);
+
+    if (generatingDocs) {
+      ClearPage.addBundledTemplateDir("assets/customizations");
+      ClearPage.addBundledTemplateDir("assets/templates");
+
+      List<ResourceLoader> resourceLoaders = new ArrayList<ResourceLoader>();
+      List<String> templates = ClearPage.getTemplateDirs();
+      for (String tmpl : templates) {
+        resourceLoaders.add(new FileSystemResourceLoader(tmpl));
+      }
+
+      templates = ClearPage.getBundledTemplateDirs();
+      for (String tmpl : templates) {
+        resourceLoaders.add(new ClassResourceLoader(Doclava.class, '/'+tmpl));
+      }
+
+      ResourceLoader compositeResourceLoader = new CompositeResourceLoader(resourceLoaders);
+      jSilver = new JSilver(compositeResourceLoader);
+
+      if (!Doclava.readTemplateSettings()) {
+        return false;
+      }
+
+      long startTime = System.nanoTime();
+
+      // Apply @since tags from the XML file
+      sinceTagger.tagAll(Converter.rootClasses());
+      
+      // Apply details of federated documentation
+      federationTagger.tagAll(Converter.rootClasses());
+
+      // Files for proofreading
+      if (proofreadFile != null) {
+        Proofread.initProofread(proofreadFile);
+      }
+      if (todoFile != null) {
+        TodoFile.writeTodoFile(todoFile);
+      }
+
+      // HTML Pages
+      if (ClearPage.htmlDir != null) {
+        writeHTMLPages();
+      }
+
+      writeAssets();
+
+      // Navigation tree
+      NavTree.writeNavTree(javadocDir);
+
+      // Packages Pages
+      writePackages(javadocDir + "packages" + htmlExtension);
+
+      // Classes
+      writeClassLists();
+      writeClasses();
+      writeHierarchy();
+      // writeKeywords();
+
+      // Lists for JavaScript
+      writeLists();
+      if (keepListFile != null) {
+        writeKeepList(keepListFile);
+      }
+
+      // Sample Code
+      for (SampleCode sc : sampleCodes) {
+        sc.write(offlineMode);
+      }
+
+      // Index page
+      writeIndex();
+
+      Proofread.finishProofread(proofreadFile);
+
+      if (sdkValuePath != null) {
+        writeSdkValues(sdkValuePath);
+      }
+
+      long time = System.nanoTime() - startTime;
+      System.out.println("DroidDoc took " + (time / 1000000000) + " sec. to write docs to "
+          + ClearPage.outputDir);
+    }
+
+    // Stubs
+    if (stubsDir != null || apiFile != null) {
+      Stubs.writeStubsAndXml(stubsDir, apiFile, stubPackages);
+    }
+
+    Errors.printErrors();
+    
+    return !Errors.hadError;
+  }
+
+  private static void writeIndex() {
+    Data data = makeHDF();
+    ClearPage.write(data, "index.cs", javadocDir + "index" + htmlExtension);
+  }
+
+  private static boolean readTemplateSettings() {
+    Data data = makeHDF();
+
+    // The .html extension is hard-coded in several .cs files,
+    // and so you cannot currently set it as a property.
+    htmlExtension = ".html";
+    // htmlExtension = data.getValue("template.extension", ".html");
+    int i = 0;
+    while (true) {
+      String k = data.getValue("template.escape." + i + ".key", "");
+      String v = data.getValue("template.escape." + i + ".value", "");
+      if ("".equals(k)) {
+        break;
+      }
+      if (k.length() != 1) {
+        System.err.println("template.escape." + i + ".key must have a length of 1: " + k);
+        return false;
+      }
+      escapeChars.put(k.charAt(0), v);
+      i++;
+    }
+    return true;
+  }
+
+  public static String escape(String s) {
+    if (escapeChars.size() == 0) {
+      return s;
+    }
+    StringBuffer b = null;
+    int begin = 0;
+    final int N = s.length();
+    for (int i = 0; i < N; i++) {
+      char c = s.charAt(i);
+      String mapped = escapeChars.get(c);
+      if (mapped != null) {
+        if (b == null) {
+          b = new StringBuffer(s.length() + mapped.length());
+        }
+        if (begin != i) {
+          b.append(s.substring(begin, i));
+        }
+        b.append(mapped);
+        begin = i + 1;
+      }
+    }
+    if (b != null) {
+      if (begin != N) {
+        b.append(s.substring(begin, N));
+      }
+      return b.toString();
+    }
+    return s;
+  }
+
+  public static void setPageTitle(Data data, String title) {
+    String s = title;
+    if (Doclava.title.length() > 0) {
+      s += " - " + Doclava.title;
+    }
+    data.setValue("page.title", s);
+  }
+
+
+  public static LanguageVersion languageVersion() {
+    return LanguageVersion.JAVA_1_5;
+  }
+
+
+  public static int optionLength(String option) {
+    if (option.equals("-d")) {
+      return 2;
+    }
+    if (option.equals("-templatedir")) {
+      return 2;
+    }
+    if (option.equals("-hdf")) {
+      return 3;
+    }
+    if (option.equals("-toroot")) {
+      return 2;
+    }
+    if (option.equals("-samplecode")) {
+      return 4;
+    }
+    if (option.equals("-htmldir")) {
+      return 2;
+    }
+    if (option.equals("-title")) {
+      return 2;
+    }
+    if (option.equals("-werror")) {
+      return 1;
+    }
+    if (option.equals("-hide")) {
+      return 2;
+    }
+    if (option.equals("-warning")) {
+      return 2;
+    }
+    if (option.equals("-error")) {
+      return 2;
+    }
+    if (option.equals("-keeplist")) {
+      return 2;
+    }
+    if (option.equals("-proofread")) {
+      return 2;
+    }
+    if (option.equals("-todo")) {
+      return 2;
+    }
+    if (option.equals("-public")) {
+      return 1;
+    }
+    if (option.equals("-protected")) {
+      return 1;
+    }
+    if (option.equals("-package")) {
+      return 1;
+    }
+    if (option.equals("-private")) {
+      return 1;
+    }
+    if (option.equals("-hidden")) {
+      return 1;
+    }
+    if (option.equals("-stubs")) {
+      return 2;
+    }
+    if (option.equals("-stubpackages")) {
+      return 2;
+    }
+    if (option.equals("-sdkvalues")) {
+      return 2;
+    }
+    if (option.equals("-apixml")) {
+      return 2;
+    }
+    if (option.equals("-nodocs")) {
+      return 1;
+    }
+    if (option.equals("-since")) {
+      return 3;
+    }
+    if (option.equals("-offlinemode")) {
+      return 1;
+    }
+    if (option.equals("-federate")) {
+      return 3;
+    }
+    return 0;
+  }
+
+  public static boolean validOptions(String[][] options, DocErrorReporter r) {
+    for (String[] a : options) {
+      if (a[0].equals("-error") || a[0].equals("-warning") || a[0].equals("-hide")) {
+        try {
+          Integer.parseInt(a[1]);
+        } catch (NumberFormatException e) {
+          r.printError("bad -" + a[0] + " value must be a number: " + a[1]);
+          return false;
+        }
+      }
+    }
+
+    return true;
+  }
+
+  public static Data makeHDF() {
+    Data data = jSilver.createData();
+
+    for (String[] p : mHDFData) {
+      data.setValue(p[0], p[1]);
+    }
+
+    return data;
+  }
+
+
+
+  public static Data makePackageHDF() {
+    Data data = makeHDF();
+    ClassInfo[] classes = Converter.rootClasses();
+
+    SortedMap<String, PackageInfo> sorted = new TreeMap<String, PackageInfo>();
+    for (ClassInfo cl : classes) {
+      PackageInfo pkg = cl.containingPackage();
+      String name;
+      if (pkg == null) {
+        name = "";
+      } else {
+        name = pkg.name();
+      }
+      sorted.put(name, pkg);
+    }
+
+    int i = 0;
+    for (String s : sorted.keySet()) {
+      PackageInfo pkg = sorted.get(s);
+
+      if (pkg.isHidden()) {
+        continue;
+      }
+      Boolean allHidden = true;
+      int pass = 0;
+      ClassInfo[] classesToCheck = null;
+      while (pass < 5) {
+        switch (pass) {
+          case 0:
+            classesToCheck = pkg.ordinaryClasses();
+            break;
+          case 1:
+            classesToCheck = pkg.enums();
+            break;
+          case 2:
+            classesToCheck = pkg.errors();
+            break;
+          case 3:
+            classesToCheck = pkg.exceptions();
+            break;
+          case 4:
+            classesToCheck = pkg.interfaces();
+            break;
+          default:
+            System.err.println("Error reading package: " + pkg.name());
+            break;
+        }
+        for (ClassInfo cl : classesToCheck) {
+          if (!cl.isHidden()) {
+            allHidden = false;
+            break;
+          }
+        }
+        if (!allHidden) {
+          break;
+        }
+        pass++;
+      }
+      if (allHidden) {
+        continue;
+      }
+
+      data.setValue("reference", "1");
+      data.setValue("reference.apilevels", sinceTagger.hasVersions() ? "1" : "0");
+      data.setValue("docs.packages." + i + ".name", s);
+      data.setValue("docs.packages." + i + ".link", pkg.htmlPage());
+      data.setValue("docs.packages." + i + ".since", pkg.getSince());
+      TagInfo.makeHDF(data, "docs.packages." + i + ".shortDescr", pkg.firstSentenceTags());
+      i++;
+    }
+
+    sinceTagger.writeVersionNames(data);
+    return data;
+  }
+
+  private static void writeDirectory(File dir, String relative, JSilver js) {
+    File[] files = dir.listFiles();
+    int i, count = files.length;
+    for (i = 0; i < count; i++) {
+      File f = files[i];
+      if (f.isFile()) {
+        String templ = relative + f.getName();
+        int len = templ.length();
+        if (len > 3 && ".cs".equals(templ.substring(len - 3))) {
+          Data data = makeHDF();
+          String filename = templ.substring(0, len - 3) + htmlExtension;
+          ClearPage.write(data, templ, filename, js);
+        } else if (len > 3 && ".jd".equals(templ.substring(len - 3))) {
+          String filename = templ.substring(0, len - 3) + htmlExtension;
+          DocFile.writePage(f.getAbsolutePath(), relative, filename);
+        } else {
+          ClearPage.copyFile(f, templ);
+        }
+      } else if (f.isDirectory()) {
+        writeDirectory(f, relative + f.getName() + "/", js);
+      }
+    }
+  }
+
+  public static void writeHTMLPages() {
+    File f = new File(ClearPage.htmlDir);
+    if (!f.isDirectory()) {
+      System.err.println("htmlDir not a directory: " + ClearPage.htmlDir);
+    }
+
+    ResourceLoader loader = new FileSystemResourceLoader(f);
+    JSilver js = new JSilver(loader);
+    writeDirectory(f, "", js);
+  }
+
+  public static void writeAssets() {
+    JarFile thisJar = JarUtils.jarForClass(Doclava.class, null);
+    if (thisJar != null) {
+      try {
+        List<String> templateDirs = ClearPage.getBundledTemplateDirs();
+        for (String templateDir : templateDirs) {
+          String assetsDir = templateDir + "/assets";
+          JarUtils.copyResourcesToDirectory(thisJar, assetsDir, ClearPage.outputDir + "/assets");
+        }
+      } catch (IOException e) {
+        System.err.println("Error copying assets directory.");
+        e.printStackTrace();
+        return;
+      }
+    }
+
+    List<String> templateDirs = ClearPage.getTemplateDirs();
+    for (String templateDir : templateDirs) {
+      File assets = new File(templateDir + "/assets");
+      if (assets.isDirectory()) {
+        writeDirectory(assets, "assets/", null);
+      }
+    }
+  }
+
+  public static void writeLists() {
+    Data data = makeHDF();
+
+    ClassInfo[] classes = Converter.rootClasses();
+
+    SortedMap<String, Object> sorted = new TreeMap<String, Object>();
+    for (ClassInfo cl : classes) {
+      if (cl.isHidden()) {
+        continue;
+      }
+      sorted.put(cl.qualifiedName(), cl);
+      PackageInfo pkg = cl.containingPackage();
+      String name;
+      if (pkg == null) {
+        name = "";
+      } else {
+        name = pkg.name();
+      }
+      sorted.put(name, pkg);
+    }
+
+    int i = 0;
+    for (String s : sorted.keySet()) {
+      data.setValue("docs.pages." + i + ".id", "" + i);
+      data.setValue("docs.pages." + i + ".label", s);
+
+      Object o = sorted.get(s);
+      if (o instanceof PackageInfo) {
+        PackageInfo pkg = (PackageInfo) o;
+        data.setValue("docs.pages." + i + ".link", pkg.htmlPage());
+        data.setValue("docs.pages." + i + ".type", "package");
+      } else if (o instanceof ClassInfo) {
+        ClassInfo cl = (ClassInfo) o;
+        data.setValue("docs.pages." + i + ".link", cl.htmlPage());
+        data.setValue("docs.pages." + i + ".type", "class");
+      }
+      i++;
+    }
+
+    ClearPage.write(data, "lists.cs", javadocDir + "lists.js");
+  }
+
+  public static void cantStripThis(ClassInfo cl, HashSet<ClassInfo> notStrippable) {
+    if (!notStrippable.add(cl)) {
+      // slight optimization: if it already contains cl, it already contains
+      // all of cl's parents
+      return;
+    }
+    ClassInfo supr = cl.superclass();
+    if (supr != null) {
+      cantStripThis(supr, notStrippable);
+    }
+    for (ClassInfo iface : cl.interfaces()) {
+      cantStripThis(iface, notStrippable);
+    }
+  }
+
+  private static String getPrintableName(ClassInfo cl) {
+    ClassInfo containingClass = cl.containingClass();
+    if (containingClass != null) {
+      // This is an inner class.
+      String baseName = cl.name();
+      baseName = baseName.substring(baseName.lastIndexOf('.') + 1);
+      return getPrintableName(containingClass) + '$' + baseName;
+    }
+    return cl.qualifiedName();
+  }
+
+  /**
+   * Writes the list of classes that must be present in order to provide the non-hidden APIs known
+   * to javadoc.
+   * 
+   * @param filename the path to the file to write the list to
+   */
+  public static void writeKeepList(String filename) {
+    HashSet<ClassInfo> notStrippable = new HashSet<ClassInfo>();
+    ClassInfo[] all = Converter.allClasses();
+    Arrays.sort(all); // just to make the file a little more readable
+
+    // If a class is public and not hidden, then it and everything it derives
+    // from cannot be stripped. Otherwise we can strip it.
+    for (ClassInfo cl : all) {
+      if (cl.isPublic() && !cl.isHidden()) {
+        cantStripThis(cl, notStrippable);
+      }
+    }
+    PrintStream stream = null;
+    try {
+      stream = new PrintStream(filename);
+      for (ClassInfo cl : notStrippable) {
+        stream.println(getPrintableName(cl));
+      }
+    } catch (FileNotFoundException e) {
+      System.err.println("error writing file: " + filename);
+    } finally {
+      if (stream != null) {
+        stream.close();
+      }
+    }
+  }
+
+  private static PackageInfo[] sVisiblePackages = null;
+
+  public static PackageInfo[] choosePackages() {
+    if (sVisiblePackages != null) {
+      return sVisiblePackages;
+    }
+
+    ClassInfo[] classes = Converter.rootClasses();
+    SortedMap<String, PackageInfo> sorted = new TreeMap<String, PackageInfo>();
+    for (ClassInfo cl : classes) {
+      PackageInfo pkg = cl.containingPackage();
+      String name;
+      if (pkg == null) {
+        name = "";
+      } else {
+        name = pkg.name();
+      }
+      sorted.put(name, pkg);
+    }
+
+    ArrayList<PackageInfo> result = new ArrayList<PackageInfo>();
+
+    for (String s : sorted.keySet()) {
+      PackageInfo pkg = sorted.get(s);
+
+      if (pkg.isHidden()) {
+        continue;
+      }
+      Boolean allHidden = true;
+      int pass = 0;
+      ClassInfo[] classesToCheck = null;
+      while (pass < 5) {
+        switch (pass) {
+          case 0:
+            classesToCheck = pkg.ordinaryClasses();
+            break;
+          case 1:
+            classesToCheck = pkg.enums();
+            break;
+          case 2:
+            classesToCheck = pkg.errors();
+            break;
+          case 3:
+            classesToCheck = pkg.exceptions();
+            break;
+          case 4:
+            classesToCheck = pkg.interfaces();
+            break;
+          default:
+            System.err.println("Error reading package: " + pkg.name());
+            break;
+        }
+        for (ClassInfo cl : classesToCheck) {
+          if (!cl.isHidden()) {
+            allHidden = false;
+            break;
+          }
+        }
+        if (!allHidden) {
+          break;
+        }
+        pass++;
+      }
+      if (allHidden) {
+        continue;
+      }
+
+      result.add(pkg);
+    }
+
+    sVisiblePackages = result.toArray(new PackageInfo[result.size()]);
+    return sVisiblePackages;
+  }
+
+  public static void writePackages(String filename) {
+    Data data = makePackageHDF();
+
+    int i = 0;
+    for (PackageInfo pkg : choosePackages()) {
+      writePackage(pkg);
+
+      data.setValue("docs.packages." + i + ".name", pkg.name());
+      data.setValue("docs.packages." + i + ".link", pkg.htmlPage());
+      TagInfo.makeHDF(data, "docs.packages." + i + ".shortDescr", pkg.firstSentenceTags());
+
+      i++;
+    }
+
+    setPageTitle(data, "Package Index");
+
+    TagInfo.makeHDF(data, "root.descr", Converter.convertTags(root.inlineTags(), null));
+
+    ClearPage.write(data, "packages.cs", filename);
+    ClearPage.write(data, "package-list.cs", javadocDir + "package-list");
+
+    Proofread.writePackages(filename, Converter.convertTags(root.inlineTags(), null));
+  }
+
+  public static void writePackage(PackageInfo pkg) {
+    // these this and the description are in the same directory,
+    // so it's okay
+    Data data = makePackageHDF();
+
+    String name = pkg.name();
+
+    data.setValue("package.name", name);
+    data.setValue("package.since", pkg.getSince());
+    data.setValue("package.descr", "...description...");
+    pkg.setFederatedReferences(data, "package");
+
+    makeClassListHDF(data, "package.interfaces", ClassInfo.sortByName(pkg.interfaces()));
+    makeClassListHDF(data, "package.classes", ClassInfo.sortByName(pkg.ordinaryClasses()));
+    makeClassListHDF(data, "package.enums", ClassInfo.sortByName(pkg.enums()));
+    makeClassListHDF(data, "package.exceptions", ClassInfo.sortByName(pkg.exceptions()));
+    makeClassListHDF(data, "package.errors", ClassInfo.sortByName(pkg.errors()));
+    TagInfo.makeHDF(data, "package.shortDescr", pkg.firstSentenceTags());
+    TagInfo.makeHDF(data, "package.descr", pkg.inlineTags());
+
+    String filename = pkg.htmlPage();
+    setPageTitle(data, name);
+    ClearPage.write(data, "package.cs", filename);
+
+    filename = pkg.fullDescriptionHtmlPage();
+    setPageTitle(data, name + " Details");
+    ClearPage.write(data, "package-descr.cs", filename);
+
+    Proofread.writePackage(filename, pkg.inlineTags());
+  }
+
+  public static void writeClassLists() {
+    int i;
+    Data data = makePackageHDF();
+
+    ClassInfo[] classes = PackageInfo.filterHidden(Converter.convertClasses(root.classes()));
+    if (classes.length == 0) {
+      return;
+    }
+
+    Sorter[] sorted = new Sorter[classes.length];
+    for (i = 0; i < sorted.length; i++) {
+      ClassInfo cl = classes[i];
+      String name = cl.name();
+      sorted[i] = new Sorter(name, cl);
+    }
+
+    Arrays.sort(sorted);
+
+    // make a pass and resolve ones that have the same name
+    int firstMatch = 0;
+    String lastName = sorted[0].label;
+    for (i = 1; i < sorted.length; i++) {
+      String s = sorted[i].label;
+      if (!lastName.equals(s)) {
+        if (firstMatch != i - 1) {
+          // there were duplicates
+          for (int j = firstMatch; j < i; j++) {
+            PackageInfo pkg = ((ClassInfo) sorted[j].data).containingPackage();
+            if (pkg != null) {
+              sorted[j].label = sorted[j].label + " (" + pkg.name() + ")";
+            }
+          }
+        }
+        firstMatch = i;
+        lastName = s;
+      }
+    }
+
+    // and sort again
+    Arrays.sort(sorted);
+
+    for (i = 0; i < sorted.length; i++) {
+      String s = sorted[i].label;
+      ClassInfo cl = (ClassInfo) sorted[i].data;
+      char first = Character.toUpperCase(s.charAt(0));
+      cl.makeShortDescrHDF(data, "docs.classes." + first + '.' + i);
+    }
+
+    setPageTitle(data, "Class Index");
+    ClearPage.write(data, "classes.cs", javadocDir + "classes" + htmlExtension);
+  }
+
+  // we use the word keywords because "index" means something else in html land
+  // the user only ever sees the word index
+  /*
+   * public static void writeKeywords() { ArrayList<KeywordEntry> keywords = new
+   * ArrayList<KeywordEntry>();
+   * 
+   * ClassInfo[] classes = PackageInfo.filterHidden(Converter.convertClasses(root.classes()));
+   * 
+   * for (ClassInfo cl: classes) { cl.makeKeywordEntries(keywords); }
+   * 
+   * HDF data = makeHDF();
+   * 
+   * Collections.sort(keywords);
+   * 
+   * int i=0; for (KeywordEntry entry: keywords) { String base = "keywords." + entry.firstChar() +
+   * "." + i; entry.makeHDF(data, base); i++; }
+   * 
+   * setPageTitle(data, "Index"); ClearPage.write(data, "keywords.cs", javadocDir + "keywords" +
+   * htmlExtension); }
+   */
+
+  public static void writeHierarchy() {
+    ClassInfo[] classes = Converter.rootClasses();
+    ArrayList<ClassInfo> info = new ArrayList<ClassInfo>();
+    for (ClassInfo cl : classes) {
+      if (!cl.isHidden()) {
+        info.add(cl);
+      }
+    }
+    Data data = makePackageHDF();
+    Hierarchy.makeHierarchy(data, info.toArray(new ClassInfo[info.size()]));
+    setPageTitle(data, "Class Hierarchy");
+    ClearPage.write(data, "hierarchy.cs", javadocDir + "hierarchy" + htmlExtension);
+  }
+
+  public static void writeClasses() {
+    ClassInfo[] classes = Converter.rootClasses();
+
+    for (ClassInfo cl : classes) {
+      Data data = makePackageHDF();
+      if (!cl.isHidden()) {
+        writeClass(cl, data);
+      }
+    }
+  }
+
+  public static void writeClass(ClassInfo cl, Data data) {
+    cl.makeHDF(data);
+
+    setPageTitle(data, cl.name());
+    ClearPage.write(data, "class.cs", cl.htmlPage());
+
+    Proofread.writeClass(cl.htmlPage(), cl);
+  }
+
+  public static void makeClassListHDF(Data data, String base, ClassInfo[] classes) {
+    for (int i = 0; i < classes.length; i++) {
+      ClassInfo cl = classes[i];
+      if (!cl.isHidden()) {
+        cl.makeShortDescrHDF(data, base + "." + i);
+      }
+    }
+  }
+
+  public static String linkTarget(String source, String target) {
+    String[] src = source.split("/");
+    String[] tgt = target.split("/");
+
+    int srclen = src.length;
+    int tgtlen = tgt.length;
+
+    int same = 0;
+    while (same < (srclen - 1) && same < (tgtlen - 1) && (src[same].equals(tgt[same]))) {
+      same++;
+    }
+
+    String s = "";
+
+    int up = srclen - same - 1;
+    for (int i = 0; i < up; i++) {
+      s += "../";
+    }
+
+
+    int N = tgtlen - 1;
+    for (int i = same; i < N; i++) {
+      s += tgt[i] + '/';
+    }
+    s += tgt[tgtlen - 1];
+
+    return s;
+  }
+
+  /**
+   * Returns true if the given element has an @hide or @pending annotation.
+   */
+  private static boolean hasHideAnnotation(Doc doc) {
+    String comment = doc.getRawCommentText();
+    return comment.indexOf("@hide") != -1 || comment.indexOf("@pending") != -1;
+  }
+
+  /**
+   * Returns true if the given element is hidden.
+   */
+  private static boolean isHidden(Doc doc) {
+    // Methods, fields, constructors.
+    if (doc instanceof MemberDoc) {
+      return hasHideAnnotation(doc);
+    }
+
+    // Classes, interfaces, enums, annotation types.
+    if (doc instanceof ClassDoc) {
+      ClassDoc classDoc = (ClassDoc) doc;
+
+      // Check the containing package.
+      if (hasHideAnnotation(classDoc.containingPackage())) {
+        return true;
+      }
+
+      // Check the class doc and containing class docs if this is a
+      // nested class.
+      ClassDoc current = classDoc;
+      do {
+        if (hasHideAnnotation(current)) {
+          return true;
+        }
+
+        current = current.containingClass();
+      } while (current != null);
+    }
+
+    return false;
+  }
+
+  /**
+   * Filters out hidden elements.
+   */
+  private static Object filterHidden(Object o, Class<?> expected) {
+    if (o == null) {
+      return null;
+    }
+
+    Class type = o.getClass();
+    if (type.getName().startsWith("com.sun.")) {
+      // TODO: Implement interfaces from superclasses, too.
+      return Proxy
+          .newProxyInstance(type.getClassLoader(), type.getInterfaces(), new HideHandler(o));
+    } else if (o instanceof Object[]) {
+      Class<?> componentType = expected.getComponentType();
+      Object[] array = (Object[]) o;
+      List<Object> list = new ArrayList<Object>(array.length);
+      for (Object entry : array) {
+        if ((entry instanceof Doc) && isHidden((Doc) entry)) {
+          continue;
+        }
+        list.add(filterHidden(entry, componentType));
+      }
+      return list.toArray((Object[]) Array.newInstance(componentType, list.size()));
+    } else {
+      return o;
+    }
+  }
+
+  /**
+   * Filters hidden elements out of method return values.
+   */
+  private static class HideHandler implements InvocationHandler {
+
+    private final Object target;
+
+    public HideHandler(Object target) {
+      this.target = target;
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+      String methodName = method.getName();
+      if (args != null) {
+        if (methodName.equals("compareTo") || methodName.equals("equals")
+            || methodName.equals("overrides") || methodName.equals("subclassOf")) {
+          args[0] = unwrap(args[0]);
+        }
+      }
+
+      if (methodName.equals("getRawCommentText")) {
+        return filterComment((String) method.invoke(target, args));
+      }
+
+      // escape "&" in disjunctive types.
+      if (proxy instanceof Type && methodName.equals("toString")) {
+        return ((String) method.invoke(target, args)).replace("&", "&amp;");
+      }
+
+      try {
+        return filterHidden(method.invoke(target, args), method.getReturnType());
+      } catch (InvocationTargetException e) {
+        throw e.getTargetException();
+      }
+    }
+
+    private String filterComment(String s) {
+      if (s == null) {
+        return null;
+      }
+
+      s = s.trim();
+
+      // Work around off by one error
+      while (s.length() >= 5 && s.charAt(s.length() - 5) == '{') {
+        s += "&nbsp;";
+      }
+
+      return s;
+    }
+
+    private static Object unwrap(Object proxy) {
+      if (proxy instanceof Proxy) return ((HideHandler) Proxy.getInvocationHandler(proxy)).target;
+      return proxy;
+    }
+  }
+
+  /**
+   * Collect the values used by the Dev tools and write them in files packaged with the SDK
+   * 
+   * @param output the ouput directory for the files.
+   */
+  private static void writeSdkValues(String output) {
+    ArrayList<String> activityActions = new ArrayList<String>();
+    ArrayList<String> broadcastActions = new ArrayList<String>();
+    ArrayList<String> serviceActions = new ArrayList<String>();
+    ArrayList<String> categories = new ArrayList<String>();
+    ArrayList<String> features = new ArrayList<String>();
+
+    ArrayList<ClassInfo> layouts = new ArrayList<ClassInfo>();
+    ArrayList<ClassInfo> widgets = new ArrayList<ClassInfo>();
+    ArrayList<ClassInfo> layoutParams = new ArrayList<ClassInfo>();
+
+    ClassInfo[] classes = Converter.allClasses();
+
+    // Go through all the fields of all the classes, looking SDK stuff.
+    for (ClassInfo clazz : classes) {
+
+      // first check constant fields for the SdkConstant annotation.
+      FieldInfo[] fields = clazz.allSelfFields();
+      for (FieldInfo field : fields) {
+        Object cValue = field.constantValue();
+        if (cValue != null) {
+          AnnotationInstanceInfo[] annotations = field.annotations();
+          if (annotations.length > 0) {
+            for (AnnotationInstanceInfo annotation : annotations) {
+              if (SDK_CONSTANT_ANNOTATION.equals(annotation.type().qualifiedName())) {
+                AnnotationValueInfo[] values = annotation.elementValues();
+                if (values.length > 0) {
+                  String type = values[0].valueString();
+                  if (SDK_CONSTANT_TYPE_ACTIVITY_ACTION.equals(type)) {
+                    activityActions.add(cValue.toString());
+                  } else if (SDK_CONSTANT_TYPE_BROADCAST_ACTION.equals(type)) {
+                    broadcastActions.add(cValue.toString());
+                  } else if (SDK_CONSTANT_TYPE_SERVICE_ACTION.equals(type)) {
+                    serviceActions.add(cValue.toString());
+                  } else if (SDK_CONSTANT_TYPE_CATEGORY.equals(type)) {
+                    categories.add(cValue.toString());
+                  } else if (SDK_CONSTANT_TYPE_FEATURE.equals(type)) {
+                    features.add(cValue.toString());
+                  }
+                }
+                break;
+              }
+            }
+          }
+        }
+      }
+
+      // Now check the class for @Widget or if its in the android.widget package
+      // (unless the class is hidden or abstract, or non public)
+      if (clazz.isHidden() == false && clazz.isPublic() && clazz.isAbstract() == false) {
+        boolean annotated = false;
+        AnnotationInstanceInfo[] annotations = clazz.annotations();
+        if (annotations.length > 0) {
+          for (AnnotationInstanceInfo annotation : annotations) {
+            if (SDK_WIDGET_ANNOTATION.equals(annotation.type().qualifiedName())) {
+              widgets.add(clazz);
+              annotated = true;
+              break;
+            } else if (SDK_LAYOUT_ANNOTATION.equals(annotation.type().qualifiedName())) {
+              layouts.add(clazz);
+              annotated = true;
+              break;
+            }
+          }
+        }
+
+        if (annotated == false) {
+          // lets check if this is inside android.widget
+          PackageInfo pckg = clazz.containingPackage();
+          String packageName = pckg.name();
+          if ("android.widget".equals(packageName) || "android.view".equals(packageName)) {
+            // now we check what this class inherits either from android.view.ViewGroup
+            // or android.view.View, or android.view.ViewGroup.LayoutParams
+            int type = checkInheritance(clazz);
+            switch (type) {
+              case TYPE_WIDGET:
+                widgets.add(clazz);
+                break;
+              case TYPE_LAYOUT:
+                layouts.add(clazz);
+                break;
+              case TYPE_LAYOUT_PARAM:
+                layoutParams.add(clazz);
+                break;
+            }
+          }
+        }
+      }
+    }
+
+    // now write the files, whether or not the list are empty.
+    // the SDK built requires those files to be present.
+
+    Collections.sort(activityActions);
+    writeValues(output + "/activity_actions.txt", activityActions);
+
+    Collections.sort(broadcastActions);
+    writeValues(output + "/broadcast_actions.txt", broadcastActions);
+
+    Collections.sort(serviceActions);
+    writeValues(output + "/service_actions.txt", serviceActions);
+
+    Collections.sort(categories);
+    writeValues(output + "/categories.txt", categories);
+
+    Collections.sort(features);
+    writeValues(output + "/features.txt", features);
+
+    // before writing the list of classes, we do some checks, to make sure the layout params
+    // are enclosed by a layout class (and not one that has been declared as a widget)
+    for (int i = 0; i < layoutParams.size();) {
+      ClassInfo layoutParamClass = layoutParams.get(i);
+      ClassInfo containingClass = layoutParamClass.containingClass();
+      if (containingClass == null || layouts.indexOf(containingClass) == -1) {
+        layoutParams.remove(i);
+      } else {
+        i++;
+      }
+    }
+
+    writeClasses(output + "/widgets.txt", widgets, layouts, layoutParams);
+  }
+
+  /**
+   * Writes a list of values into a text files.
+   * 
+   * @param pathname the absolute os path of the output file.
+   * @param values the list of values to write.
+   */
+  private static void writeValues(String pathname, ArrayList<String> values) {
+    FileWriter fw = null;
+    BufferedWriter bw = null;
+    try {
+      fw = new FileWriter(pathname, false);
+      bw = new BufferedWriter(fw);
+
+      for (String value : values) {
+        bw.append(value).append('\n');
+      }
+    } catch (IOException e) {
+      // pass for now
+    } finally {
+      try {
+        if (bw != null) bw.close();
+      } catch (IOException e) {
+        // pass for now
+      }
+      try {
+        if (fw != null) fw.close();
+      } catch (IOException e) {
+        // pass for now
+      }
+    }
+  }
+
+  /**
+   * Writes the widget/layout/layout param classes into a text files.
+   * 
+   * @param pathname the absolute os path of the output file.
+   * @param widgets the list of widget classes to write.
+   * @param layouts the list of layout classes to write.
+   * @param layoutParams the list of layout param classes to write.
+   */
+  private static void writeClasses(String pathname, ArrayList<ClassInfo> widgets,
+      ArrayList<ClassInfo> layouts, ArrayList<ClassInfo> layoutParams) {
+    FileWriter fw = null;
+    BufferedWriter bw = null;
+    try {
+      fw = new FileWriter(pathname, false);
+      bw = new BufferedWriter(fw);
+
+      // write the 3 types of classes.
+      for (ClassInfo clazz : widgets) {
+        writeClass(bw, clazz, 'W');
+      }
+      for (ClassInfo clazz : layoutParams) {
+        writeClass(bw, clazz, 'P');
+      }
+      for (ClassInfo clazz : layouts) {
+        writeClass(bw, clazz, 'L');
+      }
+    } catch (IOException e) {
+      // pass for now
+    } finally {
+      try {
+        if (bw != null) bw.close();
+      } catch (IOException e) {
+        // pass for now
+      }
+      try {
+        if (fw != null) fw.close();
+      } catch (IOException e) {
+        // pass for now
+      }
+    }
+  }
+
+  /**
+   * Writes a class name and its super class names into a {@link BufferedWriter}.
+   * 
+   * @param writer the BufferedWriter to write into
+   * @param clazz the class to write
+   * @param prefix the prefix to put at the beginning of the line.
+   * @throws IOException
+   */
+  private static void writeClass(BufferedWriter writer, ClassInfo clazz, char prefix)
+      throws IOException {
+    writer.append(prefix).append(clazz.qualifiedName());
+    ClassInfo superClass = clazz;
+    while ((superClass = superClass.superclass()) != null) {
+      writer.append(' ').append(superClass.qualifiedName());
+    }
+    writer.append('\n');
+  }
+
+  /**
+   * Checks the inheritance of {@link ClassInfo} objects. This method return
+   * <ul>
+   * <li>{@link #TYPE_LAYOUT}: if the class extends <code>android.view.ViewGroup</code></li>
+   * <li>{@link #TYPE_WIDGET}: if the class extends <code>android.view.View</code></li>
+   * <li>{@link #TYPE_LAYOUT_PARAM}: if the class extends
+   * <code>android.view.ViewGroup$LayoutParams</code></li>
+   * <li>{@link #TYPE_NONE}: in all other cases</li>
+   * </ul>
+   * 
+   * @param clazz the {@link ClassInfo} to check.
+   */
+  private static int checkInheritance(ClassInfo clazz) {
+    if ("android.view.ViewGroup".equals(clazz.qualifiedName())) {
+      return TYPE_LAYOUT;
+    } else if ("android.view.View".equals(clazz.qualifiedName())) {
+      return TYPE_WIDGET;
+    } else if ("android.view.ViewGroup.LayoutParams".equals(clazz.qualifiedName())) {
+      return TYPE_LAYOUT_PARAM;
+    }
+
+    ClassInfo parent = clazz.superclass();
+    if (parent != null) {
+      return checkInheritance(parent);
+    }
+
+    return TYPE_NONE;
+  }
+}
diff --git a/src/com/google/doclava/DoclavaDiff.java b/src/com/google/doclava/DoclavaDiff.java
new file mode 100644
index 0000000..e043246
--- /dev/null
+++ b/src/com/google/doclava/DoclavaDiff.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.JSilver;
+import com.google.clearsilver.jsilver.data.Data;
+import com.google.clearsilver.jsilver.resourceloader.CompositeResourceLoader;
+import com.google.clearsilver.jsilver.resourceloader.FileSystemResourceLoader;
+import com.google.clearsilver.jsilver.resourceloader.ResourceLoader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This class is used to generate a web page highlighting the differences and
+ * similarities among various Java libraries.
+ *
+ */
+public final class DoclavaDiff {
+  private final String outputDir;
+  private final JSilver jSilver;
+  private final List<FederatedSite> sites = new ArrayList<FederatedSite>();
+  
+  public static void main(String[] args) {
+    new DoclavaDiff(args).generateSite();
+  }
+  
+  public DoclavaDiff(String[] args) {
+    // TODO: options parsing
+    try {
+      sites.add(new FederatedSite("Android", new URL("http://manatee/doclava/android")));
+      sites.add(new FederatedSite("GWT", new URL("http://manatee/doclava/gwt")));
+      //sites.add(new FederatedSite("Crore", new URL("http://manatee/doclava/crore")));
+      outputDir = "build";
+    } catch (Exception e) {
+      throw new AssertionError(e);
+    }
+    
+    // TODO: accept external templates
+    List<ResourceLoader> resourceLoaders = new ArrayList<ResourceLoader>();
+    resourceLoaders.add(new FileSystemResourceLoader("assets/templates"));
+
+    ResourceLoader compositeResourceLoader = new CompositeResourceLoader(resourceLoaders);
+    jSilver = new JSilver(compositeResourceLoader);
+  }
+  
+  public void generateSite() {    
+    Data data = generateHdf();
+    generateHtml("diff.cs", data, new File(outputDir + "/diff.html"));
+  }
+  
+  /**
+   * Creates an HDF with this structure:
+   * <pre>
+   * sites.0.name = Android
+   * sites.0.url = http://developer.android.com/reference
+   * sites.1.name = GWT
+   * sites.1.url = http://gwt.googlecode.com
+   * packages.0.name = java.lang
+   * packages.0.sites.0.hasPackage = 1
+   * packages.0.sites.0.link = http://developer.android.com/reference/java/lang
+   * packages.0.sites.1.hasPackage = 0
+   * packages.0.classes.0.qualifiedName = java.lang.Object
+   * packages.0.classes.0.sites.0.hasClass = 1
+   * packages.0.classes.0.sites.0.link = http://developer.android.com/reference/java/lang/Object
+   * packages.0.classes.0.sites.1.hasClass = 0 
+   * packages.0.classes.0.methods.0.signature = wait()
+   * packages.0.classes.0.methods.0.sites.0.hasMethod = 1
+   * packages.0.classes.0.methods.0.sites.0.link = http://developer.android.com/reference/java/lang/Object#wait
+   * packages.0.classes.0.methods.0.sites.1.hasMethod = 0
+   * </pre>
+   */
+  private Data generateHdf() {
+    Data data = jSilver.createData();
+    
+    data.setValue("triangle.opened", "../assets/templates/assets/images/triangle-opened.png");
+    data.setValue("triangle.closed", "../assets/templates/assets/images/triangle-closed.png");
+    
+    int i = 0;
+    for (FederatedSite site : sites) {
+      String base = "sites." + (i++);
+      data.setValue(base + ".name", site.name());
+      data.setValue(base + ".url", site.baseUrl().toString());
+    }
+    
+    List<String> allPackages = knownPackages(sites);
+    
+    int p = 0;
+    for (String pkg : allPackages) {
+      PackageInfo packageInfo = new PackageInfo(pkg);
+      String packageBase = "packages." + (p++);
+      data.setValue(packageBase + ".name", pkg);
+      
+      int s = 0;
+      for (FederatedSite site : sites) {
+        String siteBase = packageBase + ".sites." + (s++);
+        if (site.apiInfo().getPackages().containsKey(pkg)) {
+          data.setValue(siteBase + ".hasPackage", "1");
+          data.setValue(siteBase + ".link", site.linkFor(packageInfo.htmlPage()));
+        } else {
+          data.setValue(siteBase + ".hasPackage", "0");
+        }
+      }
+      
+      if (packageUniqueToSite(pkg, sites)) {
+        continue;
+      }
+            
+      List<String> packageClasses = knownClassesForPackage(pkg, sites);
+      int c = 0;
+      for (String qualifiedClassName : packageClasses) {
+        String classBase = packageBase + ".classes." + (c++);
+        data.setValue(classBase + ".qualifiedName", qualifiedClassName);
+        
+        s = 0;
+        for (FederatedSite site : sites) {
+          String siteBase = classBase + ".sites." + (s++);
+          ClassInfo classInfo = site.apiInfo().findClass(qualifiedClassName);
+          if (classInfo != null) {
+            data.setValue(siteBase + ".hasClass", "1");
+            data.setValue(siteBase + ".link", site.linkFor(classInfo.htmlPage()));
+          } else {
+            data.setValue(siteBase + ".hasClass", "0");
+          }
+        }
+        
+        if (agreeOnClass(qualifiedClassName, sites)) {
+          continue;
+        }
+        
+        if (classUniqueToSite(qualifiedClassName, sites)) {
+          continue;
+        }
+        
+        int m = 0;
+        List<MethodInfo> methods = knownMethodsForClass(qualifiedClassName, sites);
+        for (MethodInfo method : methods) {
+          if (agreeOnMethod(qualifiedClassName, method, sites)) {
+            continue;
+          }
+          
+          String methodBase = classBase + ".methods." + (m++);
+          data.setValue(methodBase + ".signature", method.prettySignature());
+          int k = 0;
+          for (FederatedSite site : sites) {
+            String siteBase = methodBase + ".sites." + (k++);
+            if (site.apiInfo().findClass(qualifiedClassName) == null) {
+              data.setValue(siteBase + ".hasMethod", "0");
+              continue;
+            }
+            Map<String,MethodInfo> siteMethods
+                = site.apiInfo().findClass(qualifiedClassName).allMethods();
+            if (siteMethods.containsKey(method.getHashableName())) {
+              data.setValue(siteBase + ".hasMethod", "1");
+              data.setValue(siteBase + ".link", site.linkFor(method.htmlPage()));
+            } else {
+              data.setValue(siteBase + ".hasMethod", "0");
+            }
+          }
+        }
+      }
+    }
+    
+    return data;
+  }
+  
+  /**
+   * Returns a list of all known packages from all sites.
+   */
+  private List<String> knownPackages(List<FederatedSite> sites) {
+    Set<String> allPackages = new LinkedHashSet<String>();
+    for (FederatedSite site : sites) {
+      Map<String, PackageInfo> packages = site.apiInfo().getPackages();
+      for (String pkg : packages.keySet()) {
+        allPackages.add(pkg);
+      }
+    }
+    
+    List<String> packages = new ArrayList<String>(allPackages);
+    Collections.sort(packages);
+    return packages;
+  }
+  
+  /**
+   * Returns all known classes from all sites for a given package.
+   */
+  private List<String> knownClassesForPackage(String pkg, List<FederatedSite> sites) {
+    Set<String> allClasses = new LinkedHashSet<String>();
+    for (FederatedSite site : sites) {
+      PackageInfo packageInfo = site.apiInfo().getPackages().get(pkg);
+      if (packageInfo == null) {
+        continue;
+      }
+      HashMap<String, ClassInfo> classes = packageInfo.allClasses();
+      for (Map.Entry<String, ClassInfo> entry : classes.entrySet()) {
+        allClasses.add(entry.getValue().qualifiedName());
+      }
+    }
+    
+    List<String> classes = new ArrayList<String>(allClasses);
+    Collections.sort(classes);
+    return classes;
+  }
+  
+  /**
+   * Returns all known methods from all sites for a given class.
+   */
+  private List<MethodInfo> knownMethodsForClass(String qualifiedClassName,
+      List<FederatedSite> sites) {
+    
+    Map<String, MethodInfo> allMethods = new HashMap<String, MethodInfo>();
+    for (FederatedSite site : sites) {
+      ClassInfo classInfo = site.apiInfo().findClass(qualifiedClassName);
+      if (classInfo == null) {
+        continue;
+      }
+      
+      for (Map.Entry<String, MethodInfo> entry: classInfo.allMethods().entrySet()) {
+        allMethods.put(entry.getKey(), entry.getValue());
+      }
+    }
+    
+    List<MethodInfo> methods = new ArrayList<MethodInfo>();
+    methods.addAll(allMethods.values());
+    return methods;
+  }
+  
+  /**
+   * Returns true if the list of sites all completely agree on the given
+   * package. All sites must possess the package, all classes it contains, and
+   * all methods of each class.
+   */
+  private boolean agreeOnPackage(String pkg, List<FederatedSite> sites) {
+    for (FederatedSite site : sites) {
+      if (site.apiInfo().getPackages().get(pkg) == null) {
+        return false;
+      }
+    }
+    
+    List<String> classes = knownClassesForPackage(pkg, sites);
+    for (String clazz : classes) {
+      if (!agreeOnClass(clazz, sites)) {
+        return false;
+      }
+    }
+    return true;
+  }
+  
+  /**
+   * Returns true if the list of sites all agree on the given class. Each site
+   * must have the class and agree on its methods.
+   */
+  private boolean agreeOnClass(String qualifiedClassName, List<FederatedSite> sites) {
+    List<MethodInfo> methods = knownMethodsForClass(qualifiedClassName, sites);
+    for (MethodInfo method : methods) {
+      if (!agreeOnMethod(qualifiedClassName, method, sites)) {
+        return false;
+      }
+    }
+    return true;
+  }
+  
+  /**
+   * Returns true if the list of sites all contain the given method.
+   */
+  private boolean agreeOnMethod(String qualifiedClassName, MethodInfo method,
+      List<FederatedSite> sites) {
+    
+    for (FederatedSite site : sites) {
+      ClassInfo siteClass = site.apiInfo().findClass(qualifiedClassName);
+      if (siteClass == null) {
+        return false;
+      }
+      
+      if (!siteClass.supportsMethod(method)) {
+        return false;
+      }
+    }
+    return true;
+  }
+  
+  /**
+   * Returns true if the given package is known to exactly one of the given sites.
+   */
+  private boolean packageUniqueToSite(String pkg, List<FederatedSite> sites) {
+    int numSites = 0;
+    for (FederatedSite site : sites) {
+      if (site.apiInfo().getPackages().containsKey(pkg)) {
+        numSites++;
+      }
+    }
+    return numSites == 1;
+  }
+  
+  /**
+   * Returns true if the given class is known to exactly one of the given sites.
+   */
+  private boolean classUniqueToSite(String qualifiedClassName, List<FederatedSite> sites) {
+    int numSites = 0;
+    for (FederatedSite site : sites) {
+      if (site.apiInfo().findClass(qualifiedClassName) != null) {
+        numSites++;
+      }
+    }
+    return numSites == 1;
+  }
+  
+  private void generateHtml(String template, Data data, File file) {
+    ClearPage.ensureDirectory(file);
+    
+    OutputStreamWriter stream = null;
+    try {
+      stream = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
+      String rendered = jSilver.render(template, data);
+      stream.write(rendered, 0, rendered.length());
+    } catch (IOException e) {
+      System.out.println("error: " + e.getMessage() + "; when writing file: " + file.getAbsolutePath());
+    } finally {
+      if (stream != null) {
+        try {
+          stream.close();
+        } catch (IOException ignored) {}
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/com/google/doclava/Errors.java b/src/com/google/doclava/Errors.java
new file mode 100644
index 0000000..6a257fe
--- /dev/null
+++ b/src/com/google/doclava/Errors.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+public class Errors {
+  public static boolean hadError = false;
+  private static boolean warningsAreErrors = false;
+  private static TreeSet<ErrorMessage> allErrors = new TreeSet<ErrorMessage>();
+
+  public static class ErrorMessage implements Comparable {
+    Error error;
+    SourcePositionInfo pos;
+    String msg;
+
+    ErrorMessage(Error e, SourcePositionInfo p, String m) {
+      error = e;
+      pos = p;
+      msg = m;
+    }
+
+    public int compareTo(Object o) {
+      ErrorMessage that = (ErrorMessage) o;
+      int r = this.pos.compareTo(that.pos);
+      if (r != 0) return r;
+      return this.msg.compareTo(that.msg);
+    }
+
+    @Override
+    public String toString() {
+      String whereText = this.pos == null ? "unknown: " : this.pos.toString() + ':';
+      return whereText + this.msg;
+    }
+    
+    public Error error() {
+      return error;
+    }
+  }
+
+  public static void error(Error error, SourcePositionInfo where, String text) {
+    if (error.level == HIDDEN) {
+      return;
+    }
+
+    int level = (!warningsAreErrors && error.level == WARNING) ? WARNING : ERROR;
+    String which = level == WARNING ? " warning " : " error ";
+    String message = which + error.code + ": " + text;
+
+    if (where == null) {
+      where = new SourcePositionInfo("unknown", 0, 0);
+    }
+
+    allErrors.add(new ErrorMessage(error, where, message));
+
+    if (error.level == ERROR || (warningsAreErrors && error.level == WARNING)) {
+      hadError = true;
+    }
+  }
+  
+  public static void clearErrors() {
+    hadError = false;
+    allErrors.clear();
+  }
+
+  public static void printErrors() {
+    printErrors(allErrors);
+  }
+  
+  public static void printErrors(Set<ErrorMessage> errors) {
+    for (ErrorMessage m : errors) {
+      if (m.error.level == WARNING) {
+        System.err.println(m.toString());
+      }
+    }
+    for (ErrorMessage m : errors) {
+      if (m.error.level == ERROR) {
+        System.err.println(m.toString());
+      }
+    }
+  }
+  
+  public static Set<ErrorMessage> getErrors() {
+    return allErrors;
+  }
+
+  public static int HIDDEN = 0;
+  public static int WARNING = 1;
+  public static int ERROR = 2;
+
+  public static void setWarningsAreErrors(boolean val) {
+    warningsAreErrors = val;
+  }
+
+  public static class Error {
+    public int code;
+    public int level;
+
+    public Error(int code, int level) {
+      this.code = code;
+      this.level = level;
+    }
+    
+    public String toString() {
+      return "Error #" + this.code;
+    }
+  }
+
+  public static final Error UNRESOLVED_LINK = new Error(1, WARNING);
+  public static final Error BAD_INCLUDE_TAG = new Error(2, WARNING);
+  public static final Error UNKNOWN_TAG = new Error(3, WARNING);
+  public static final Error UNKNOWN_PARAM_TAG_NAME = new Error(4, WARNING);
+  public static final Error UNDOCUMENTED_PARAMETER = new Error(5, HIDDEN);
+  public static final Error BAD_ATTR_TAG = new Error(6, ERROR);
+  public static final Error BAD_INHERITDOC = new Error(7, HIDDEN);
+  public static final Error HIDDEN_LINK = new Error(8, WARNING);
+  public static final Error HIDDEN_CONSTRUCTOR = new Error(9, WARNING);
+  public static final Error UNAVAILABLE_SYMBOL = new Error(10, ERROR);
+  public static final Error HIDDEN_SUPERCLASS = new Error(11, WARNING);
+  public static final Error DEPRECATED = new Error(12, HIDDEN);
+  public static final Error DEPRECATION_MISMATCH = new Error(13, WARNING);
+  public static final Error MISSING_COMMENT = new Error(14, WARNING);
+  public static final Error IO_ERROR = new Error(15, HIDDEN);
+  public static final Error NO_SINCE_DATA = new Error(16, HIDDEN);
+  public static final Error NO_FEDERATION_DATA = new Error(17, WARNING);
+
+  public static final Error PARSE_ERROR = new Error(18, ERROR); // Apicheck error code 1
+  public static final Error ADDED_PACKAGE = new Error(19, WARNING); // Apicheck error code 2
+  public static final Error ADDED_CLASS = new Error(20, WARNING); // Apicheck error code 3
+  public static final Error ADDED_METHOD = new Error(21, WARNING); // Apicheck error code 4
+  public static final Error ADDED_FIELD = new Error(22, WARNING); // Apicheck error code 5
+  public static final Error ADDED_INTERFACE = new Error(23, WARNING); // Apicheck error code 6
+  public static final Error REMOVED_PACKAGE = new Error(24, WARNING); // Apicheck error code 7
+  public static final Error REMOVED_CLASS = new Error(25, WARNING); // Apicheck error code 8
+  public static final Error REMOVED_METHOD = new Error(26, WARNING); // Apicheck error code 9
+  public static final Error REMOVED_FIELD = new Error(27, WARNING); // Apicheck error code 10
+  public static final Error REMOVED_INTERFACE = new Error(28, WARNING); // Apicheck error code 11
+  public static final Error CHANGED_STATIC = new Error(29, WARNING); // Apicheck error code 12
+  public static final Error CHANGED_FINAL = new Error(30, WARNING); // Apicheck error code 13
+  public static final Error CHANGED_TRANSIENT = new Error(31, WARNING); // Apicheck error code 14
+  public static final Error CHANGED_VOLATILE = new Error(32, WARNING); // Apicheck error code 15
+  public static final Error CHANGED_TYPE = new Error(33, WARNING); // Apicheck error code 16
+  public static final Error CHANGED_VALUE = new Error(34, WARNING); // Apicheck error code 17
+  public static final Error CHANGED_SUPERCLASS = new Error(35, WARNING); // Apicheck error code 18
+  public static final Error CHANGED_SCOPE = new Error(36, WARNING); // Apicheck error code 19
+  public static final Error CHANGED_ABSTRACT = new Error(37, WARNING); // Apicheck error code 20
+  public static final Error CHANGED_THROWS = new Error(38, WARNING); // Apicheck error code 21
+  public static final Error CHANGED_NATIVE = new Error(39, HIDDEN); // Apicheck error code 22
+  public static final Error CHANGED_CLASS = new Error(40, WARNING); // Apicheck error code 23
+  public static final Error CHANGED_DEPRECATED = new Error(41, WARNING); // Apicheck error code 24
+  public static final Error CHANGED_SYNCHRONIZED = new Error(42, ERROR); // Apicheck error code 25
+  
+  public static final Error[] ERRORS =
+      {UNRESOLVED_LINK, BAD_INCLUDE_TAG, UNKNOWN_TAG, UNKNOWN_PARAM_TAG_NAME,
+          UNDOCUMENTED_PARAMETER, BAD_ATTR_TAG, BAD_INHERITDOC, HIDDEN_LINK, HIDDEN_CONSTRUCTOR,
+          UNAVAILABLE_SYMBOL, HIDDEN_SUPERCLASS, DEPRECATED, IO_ERROR, NO_SINCE_DATA,
+          NO_FEDERATION_DATA, PARSE_ERROR, ADDED_PACKAGE, ADDED_CLASS, ADDED_METHOD, ADDED_FIELD,
+          ADDED_INTERFACE, REMOVED_PACKAGE, REMOVED_CLASS, REMOVED_METHOD, REMOVED_FIELD,
+          REMOVED_INTERFACE, CHANGED_STATIC, CHANGED_FINAL, CHANGED_TRANSIENT, CHANGED_VOLATILE,
+          CHANGED_TYPE, CHANGED_VALUE, CHANGED_SUPERCLASS, CHANGED_SCOPE, CHANGED_ABSTRACT,
+          CHANGED_THROWS, CHANGED_NATIVE, CHANGED_CLASS, CHANGED_DEPRECATED, CHANGED_SYNCHRONIZED};
+
+  public static boolean setErrorLevel(int code, int level) {
+    for (Error e : ERRORS) {
+      if (e.code == code) {
+        e.level = level;
+        return true;
+      }
+    }
+    return false;
+  }
+}
diff --git a/src/com/google/doclava/FederatedSite.java b/src/com/google/doclava/FederatedSite.java
new file mode 100644
index 0000000..2aa12cf
--- /dev/null
+++ b/src/com/google/doclava/FederatedSite.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.doclava.apicheck.ApiCheck;
+import com.google.doclava.apicheck.ApiInfo;
+import com.google.doclava.apicheck.ApiParseException;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * A remote source of documentation that can be linked against. A federated
+ * site represents a library that has packages, classes, and members that may
+ * be referenced or shared across codebases.
+ */
+public final class FederatedSite {
+  private final String name;
+  private final URL baseUrl;
+  private final ApiInfo apiInfo;
+  
+  public FederatedSite(String name, URL baseUrl) throws ApiParseException {
+    this.name = name;
+    this.baseUrl = baseUrl;
+    
+    try {
+      URL xmlUrl = new URL(baseUrl + "/xml/current.xml");
+      this.apiInfo = new ApiCheck().parseApi(xmlUrl);
+    } catch (MalformedURLException e) {
+      throw new AssertionError(e);
+    }
+  }
+  
+  public String linkFor(String htmlPage) {
+    return baseUrl + "/" + htmlPage;
+  }
+
+  public String name() {
+    return name;
+  }
+
+  public ApiInfo apiInfo() {
+    return apiInfo;
+  }
+  
+  public URL baseUrl() {
+    return baseUrl;
+  }
+}
\ No newline at end of file
diff --git a/src/com/google/doclava/FederationTagger.java b/src/com/google/doclava/FederationTagger.java
new file mode 100644
index 0000000..2b54d9e
--- /dev/null
+++ b/src/com/google/doclava/FederationTagger.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.doclava.apicheck.ApiCheck;
+import com.google.doclava.apicheck.ApiInfo;
+import com.google.doclava.apicheck.ApiParseException;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Cross-references documentation among different libraries. A FederationTagger
+ * is populated with a list of {@link FederatedSite} objects which are linked
+ * against when overlapping content is discovered.
+ */
+public final class FederationTagger {
+  private final List<FederatedSite> federatedSites = new ArrayList<FederatedSite>();
+  
+  /**
+   * Adds a Doclava documentation site for federation. Accepts the base URL of
+   * the remote API.
+   */
+  public void addSite(String name, URL site) {
+    try {
+      federatedSites.add(new FederatedSite(name, site));
+    } catch (ApiParseException e) {
+      String error = "Could not add site for federation: " + site;
+      if (e.getMessage() != null) {
+        error += ": " + e.getMessage();
+      }
+      Errors.error(Errors.NO_FEDERATION_DATA, null, error);
+    }
+  }
+  
+  public void tagAll(ClassInfo[] classDocs) {
+    for (FederatedSite site : federatedSites) {
+      applyFederation(site, classDocs);
+    }
+  }
+  
+  private void applyFederation(FederatedSite federationSource, ClassInfo[] classDocs) {
+    for (ClassInfo classDoc : classDocs) {
+      PackageInfo packageSpec
+          = federationSource.apiInfo().getPackages().get(classDoc.containingPackage().name());
+
+      if (packageSpec == null) {
+        continue;
+      }
+
+      ClassInfo classSpec = packageSpec.allClasses().get(classDoc.name());
+      
+      if (classSpec == null) {
+        continue;
+      }
+      
+      federateMethods(federationSource, classSpec, classDoc);
+      federateConstructors(federationSource, classSpec, classDoc);
+      federateFields(federationSource, classSpec, classDoc);
+      federateClass(federationSource, classDoc);
+      federatePackage(federationSource, classDoc.containingPackage());
+    }
+  }
+
+  private void federateMethods(FederatedSite site, ClassInfo federatedClass, ClassInfo localClass) {
+    for (MethodInfo method : localClass.methods()) {
+      for (ClassInfo superclass : federatedClass.hierarchy()) {
+        if (superclass.allMethods().containsKey(method.getHashableName())) {
+          method.addFederatedReference(site);
+          break;
+        }
+      }
+    }
+  }
+  
+  private void federateConstructors(FederatedSite site, ClassInfo federatedClass,
+      ClassInfo localClass) {
+    for (MethodInfo constructor : localClass.constructors()) {
+      if (federatedClass.hasConstructor(constructor)) {
+        constructor.addFederatedReference(site);
+      }
+    }
+  }
+  
+  private void federateFields(FederatedSite site, ClassInfo federatedClass, ClassInfo localClass) {
+    for (FieldInfo field : localClass.fields()) {
+      if (federatedClass.allFields().containsKey(field.name())) {
+        field.addFederatedReference(site);
+      }
+    }
+  }
+  
+  private void federateClass(FederatedSite source, ClassInfo doc) {
+    doc.addFederatedReference(source);
+  }
+  
+  private void federatePackage(FederatedSite source, PackageInfo pkg) {
+    pkg.addFederatedReference(source);
+  }
+}
\ No newline at end of file
diff --git a/src/com/google/doclava/FieldInfo.java b/src/com/google/doclava/FieldInfo.java
new file mode 100644
index 0000000..112b6cf
--- /dev/null
+++ b/src/com/google/doclava/FieldInfo.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+import java.util.Comparator;
+
+public class FieldInfo extends MemberInfo {
+  public static final Comparator<FieldInfo> comparator = new Comparator<FieldInfo>() {
+    public int compare(FieldInfo a, FieldInfo b) {
+      return a.name().compareTo(b.name());
+    }
+  };
+
+  public FieldInfo(String name, ClassInfo containingClass, ClassInfo realContainingClass,
+      boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate,
+      boolean isFinal, boolean isStatic, boolean isTransient, boolean isVolatile,
+      boolean isSynthetic, TypeInfo type, String rawCommentText, Object constantValue,
+      SourcePositionInfo position, AnnotationInstanceInfo[] annotations) {
+    super(rawCommentText, name, null, containingClass, realContainingClass, isPublic, isProtected,
+        isPackagePrivate, isPrivate, isFinal, isStatic, isSynthetic, chooseKind(isFinal, isStatic),
+        position, annotations);
+    mIsTransient = isTransient;
+    mIsVolatile = isVolatile;
+    mType = type;
+    mConstantValue = constantValue;
+  }
+
+  public FieldInfo cloneForClass(ClassInfo newContainingClass) {
+    return new FieldInfo(name(), newContainingClass, realContainingClass(), isPublic(),
+        isProtected(), isPackagePrivate(), isPrivate(), isFinal(), isStatic(), isTransient(),
+        isVolatile(), isSynthetic(), mType, getRawCommentText(), mConstantValue, position(),
+        annotations());
+  }
+
+  static String chooseKind(boolean isFinal, boolean isStatic) {
+    if (isStatic && isFinal) {
+      return "constant";
+    } else {
+      return "field";
+    }
+  }
+  
+  public String qualifiedName() {
+    String parentQName
+        = (containingClass() != null) ? (containingClass().qualifiedName() + ".") : "";
+    return parentQName + name();
+  }
+
+  public TypeInfo type() {
+    return mType;
+  }
+
+  public boolean isConstant() {
+    return isStatic() && isFinal();
+  }
+
+  public TagInfo[] firstSentenceTags() {
+    return comment().briefTags();
+  }
+
+  public TagInfo[] inlineTags() {
+    return comment().tags();
+  }
+
+  public Object constantValue() {
+    return mConstantValue;
+  }
+
+  public String constantLiteralValue() {
+    return constantLiteralValue(mConstantValue);
+  }
+
+  public void setDeprecated(boolean deprecated) {
+    mDeprecatedKnown = true;
+    mIsDeprecated = deprecated;
+  }
+  
+  public boolean isDeprecated() {
+    if (!mDeprecatedKnown) {
+      boolean commentDeprecated = comment().isDeprecated();
+      boolean annotationDeprecated = false;
+      for (AnnotationInstanceInfo annotation : annotations()) {
+        if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) {
+          annotationDeprecated = true;
+          break;
+        }
+      }
+
+      if (commentDeprecated != annotationDeprecated) {
+        Errors.error(Errors.DEPRECATION_MISMATCH, position(), "Field "
+            + mContainingClass.qualifiedName() + "." + name()
+            + ": @Deprecated annotation and @deprecated comment do not match");
+      }
+
+      mIsDeprecated = commentDeprecated | annotationDeprecated;
+      mDeprecatedKnown = true;
+    }
+    return mIsDeprecated;
+  }
+
+  public static String constantLiteralValue(Object val) {
+    String str = null;
+    if (val != null) {
+      if (val instanceof Boolean || val instanceof Byte || val instanceof Short
+          || val instanceof Integer) {
+        str = val.toString();
+      }
+      // catch all special values
+      else if (val instanceof Double) {
+        Double dbl = (Double) val;
+        if (dbl.toString().equals("Infinity")) {
+          str = "(1.0 / 0.0)";
+        } else if (dbl.toString().equals("-Infinity")) {
+          str = "(-1.0 / 0.0)";
+        } else if (dbl.isNaN()) {
+          str = "(0.0 / 0.0)";
+        } else {
+          str = dbl.toString();
+        }
+      } else if (val instanceof Long) {
+        str = val.toString() + "L";
+      } else if (val instanceof Float) {
+        Float fl = (Float) val;
+        if (fl.toString().equals("Infinity")) {
+          str = "(1.0f / 0.0f)";
+        } else if (fl.toString().equals("-Infinity")) {
+          str = "(-1.0f / 0.0f)";
+        } else if (fl.isNaN()) {
+          str = "(0.0f / 0.0f)";
+        } else {
+          str = val.toString() + "f";
+        }
+      } else if (val instanceof Character) {
+        str = String.format("\'\\u%04x\'", val);
+      } else if (val instanceof String) {
+        str = "\"" + javaEscapeString((String) val) + "\"";
+      } else {
+        str = "<<<<" + val.toString() + ">>>>";
+      }
+    }
+    if (str == null) {
+      str = "null";
+    }
+    return str;
+  }
+
+  public static String javaEscapeString(String str) {
+    String result = "";
+    final int N = str.length();
+    for (int i = 0; i < N; i++) {
+      char c = str.charAt(i);
+      if (c == '\\') {
+        result += "\\\\";
+      } else if (c == '\t') {
+        result += "\\t";
+      } else if (c == '\b') {
+        result += "\\b";
+      } else if (c == '\r') {
+        result += "\\r";
+      } else if (c == '\n') {
+        result += "\\n";
+      } else if (c == '\f') {
+        result += "\\f";
+      } else if (c == '\'') {
+        result += "\\'";
+      } else if (c == '\"') {
+        result += "\\\"";
+      } else if (c >= ' ' && c <= '~') {
+        result += c;
+      } else {
+        result += String.format("\\u%04x", new Integer((int) c));
+      }
+    }
+    return result;
+  }
+
+
+  public void makeHDF(Data data, String base) {
+    data.setValue(base + ".kind", kind());
+    type().makeHDF(data, base + ".type");
+    data.setValue(base + ".name", name());
+    data.setValue(base + ".href", htmlPage());
+    data.setValue(base + ".anchor", anchor());
+    TagInfo.makeHDF(data, base + ".shortDescr", firstSentenceTags());
+    TagInfo.makeHDF(data, base + ".descr", inlineTags());
+    TagInfo.makeHDF(data, base + ".deprecated", comment().deprecatedTags());
+    TagInfo.makeHDF(data, base + ".seeAlso", comment().seeTags());
+    data.setValue(base + ".since", getSince());
+    data.setValue(base + ".final", isFinal() ? "final" : "");
+    data.setValue(base + ".static", isStatic() ? "static" : "");
+    if (isPublic()) {
+      data.setValue(base + ".scope", "public");
+    } else if (isProtected()) {
+      data.setValue(base + ".scope", "protected");
+    } else if (isPackagePrivate()) {
+      data.setValue(base + ".scope", "");
+    } else if (isPrivate()) {
+      data.setValue(base + ".scope", "private");
+    }
+    Object val = mConstantValue;
+    if (val != null) {
+      String dec = null;
+      String hex = null;
+      String str = null;
+
+      if (val instanceof Boolean) {
+        str = ((Boolean) val).toString();
+      } else if (val instanceof Byte) {
+        dec = String.format("%d", val);
+        hex = String.format("0x%02x", val);
+      } else if (val instanceof Character) {
+        dec = String.format("\'%c\'", val);
+        hex = String.format("0x%04x", val);
+      } else if (val instanceof Double) {
+        str = ((Double) val).toString();
+      } else if (val instanceof Float) {
+        str = ((Float) val).toString();
+      } else if (val instanceof Integer) {
+        dec = String.format("%d", val);
+        hex = String.format("0x%08x", val);
+      } else if (val instanceof Long) {
+        dec = String.format("%d", val);
+        hex = String.format("0x%016x", val);
+      } else if (val instanceof Short) {
+        dec = String.format("%d", val);
+        hex = String.format("0x%04x", val);
+      } else if (val instanceof String) {
+        str = "\"" + ((String) val) + "\"";
+      } else {
+        str = "";
+      }
+
+      if (dec != null && hex != null) {
+        data.setValue(base + ".constantValue.dec", Doclava.escape(dec));
+        data.setValue(base + ".constantValue.hex", Doclava.escape(hex));
+      } else {
+        data.setValue(base + ".constantValue.str", Doclava.escape(str));
+        data.setValue(base + ".constantValue.isString", "1");
+      }
+    }
+    
+    setFederatedReferences(data, base);
+  }
+
+  @Override
+  public boolean isExecutable() {
+    return false;
+  }
+
+  public boolean isTransient() {
+    return mIsTransient;
+  }
+
+  public boolean isVolatile() {
+    return mIsVolatile;
+  }
+  
+  // Check the declared value with a typed comparison, not a string comparison,
+  // to accommodate toolchains with different fp -> string conversions.
+  private boolean valueEquals(FieldInfo other) {
+    if ((mConstantValue == null) != (other.mConstantValue == null)) {
+      return false;
+    }
+    
+    // Null values are considered equal
+    if (mConstantValue == null) {
+      return true;
+    }
+    
+    // TODO: This method is called through from an XML comparison only right now,
+    // and mConstantValue is always a String. Get rid of this assertion.
+    if (!(mConstantValue instanceof String && other.mConstantValue instanceof String)) {
+      throw new AssertionError("Bad type for field value");
+    }
+    
+    String mValue = (String)mConstantValue;
+    String oValue = (String)other.mConstantValue;
+    // Type mismatch means nonequal
+    if (!mType.equals(other.mType)) {
+      return false;
+    }
+
+    // Floating point gets an implementation-type comparison; all others just use the string
+    // If float/double parse fails, fall back to string comparison -- it means that it's a
+    // canonical droiddoc-generated constant expression that represents a NaN.
+    try {
+      if (mType.equals("float")) {
+        float val = Float.parseFloat(mValue);
+        float otherVal = Float.parseFloat(oValue);
+        return (val == otherVal);
+      } else if (mType.equals("double")) {
+        double val = Double.parseDouble(mValue);
+        double otherVal = Double.parseDouble(oValue);
+        return (val == otherVal);
+      }
+    } catch (NumberFormatException e) {
+      // fall through
+    }
+
+    return mValue.equals(oValue);
+  }
+  
+  public boolean isConsistent(FieldInfo fInfo) {
+    boolean consistent = true;
+    if (!mType.equals(fInfo.mType)) {
+      Errors.error(Errors.CHANGED_TYPE, fInfo.position(), "Field " + fInfo.qualifiedName()
+          + " has changed type");
+      consistent = false;
+    } else if (!this.valueEquals(fInfo)) {
+      Errors.error(Errors.CHANGED_VALUE, fInfo.position(), "Field " + fInfo.qualifiedName()
+          + " has changed value from " + mConstantValue + " to " + fInfo.mConstantValue);
+      consistent = false;
+    }
+
+    if (!scope().equals(fInfo.scope())) {
+      Errors.error(Errors.CHANGED_SCOPE, fInfo.position(), "Method " + fInfo.qualifiedName()
+          + " changed scope from " + this.scope() + " to " + fInfo.scope());
+      consistent = false;
+    }
+
+    if (mIsStatic != fInfo.mIsStatic) {
+      Errors.error(Errors.CHANGED_STATIC, fInfo.position(), "Field " + fInfo.qualifiedName()
+          + " has changed 'static' qualifier");
+      consistent = false;
+    }
+
+    if (mIsFinal != fInfo.mIsFinal) {
+      Errors.error(Errors.CHANGED_FINAL, fInfo.position(), "Field " + fInfo.qualifiedName()
+          + " has changed 'final' qualifier");
+      consistent = false;
+    }
+
+    if (mIsTransient != fInfo.mIsTransient) {
+      Errors.error(Errors.CHANGED_TRANSIENT, fInfo.position(), "Field " + fInfo.qualifiedName()
+          + " has changed 'transient' qualifier");
+      consistent = false;
+    }
+
+    if (mIsVolatile != fInfo.mIsVolatile) {
+      Errors.error(Errors.CHANGED_VOLATILE, fInfo.position(), "Field " + fInfo.qualifiedName()
+          + " has changed 'volatile' qualifier");
+      consistent = false;
+    }
+
+    if (isDeprecated() != fInfo.isDeprecated()) {
+      Errors.error(Errors.CHANGED_DEPRECATED, fInfo.position(), "Field " + fInfo.qualifiedName()
+          + " has changed deprecation state");
+      consistent = false;
+    }
+
+    return consistent;
+  }
+
+  boolean mIsTransient;
+  boolean mIsVolatile;
+  boolean mDeprecatedKnown;
+  boolean mIsDeprecated;
+  TypeInfo mType;
+  Object mConstantValue;
+}
diff --git a/src/com/google/doclava/Hierarchy.java b/src/com/google/doclava/Hierarchy.java
new file mode 100755
index 0000000..0887b63
--- /dev/null
+++ b/src/com/google/doclava/Hierarchy.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.util.HashMap;
+import java.util.TreeSet;
+import java.util.Set;
+
+public class Hierarchy {
+  public static void makeHierarchy(Data hdf, ClassInfo[] classes) {
+    HashMap<String, TreeSet<String>> nodes = new HashMap<String, TreeSet<String>>();
+
+    for (ClassInfo cl : classes) {
+      String name = cl.qualifiedName();
+
+      TreeSet<String> me = nodes.get(name);
+      if (me == null) {
+        me = new TreeSet<String>();
+        nodes.put(name, me);
+      }
+
+      ClassInfo superclass = cl.superclass();
+      String sname = superclass != null ? superclass.qualifiedName() : null;
+      if (sname != null) {
+        TreeSet<String> s = nodes.get(sname);
+        if (s == null) {
+          s = new TreeSet<String>();
+          nodes.put(sname, s);
+        }
+        s.add(name);
+      }
+    }
+
+    /*
+     * Set<String> keys = nodes.keySet(); for (String n: keys) { System.out.println("class: " + n);
+     * 
+     * TreeSet<String> values = nodes.get(n); for (String v: values) {
+     * System.out.println("       - " + v); } }
+     */
+
+    int depth = depth(nodes, "java.lang.Object");
+
+    hdf.setValue("classes.0", "");
+    hdf.setValue("colspan", "" + depth);
+
+    recurse(nodes, "java.lang.Object", hdf.getChild("classes.0"), depth, depth);
+
+    if (false) {
+      Set<String> keys = nodes.keySet();
+      if (keys.size() > 0) {
+        System.err.println("The following classes are hidden but"
+            + " are superclasses of not-hidden classes");
+        for (String n : keys) {
+          System.err.println("  " + n);
+        }
+      }
+    }
+  }
+
+  private static int depth(HashMap<String, TreeSet<String>> nodes, String name) {
+    int d = 0;
+    TreeSet<String> derived = nodes.get(name);
+    if (derived != null && derived.size() > 0) {
+      for (String s : derived) {
+        int n = depth(nodes, s);
+        if (n > d) {
+          d = n;
+        }
+      }
+    }
+    return d + 1;
+  }
+
+  private static boolean exists(ClassInfo cl) {
+    return cl != null && !cl.isHidden() && cl.isIncluded();
+  }
+
+  private static void recurse(HashMap<String, TreeSet<String>> nodes, String name, Data hdf,
+      int totalDepth, int remainingDepth) {
+    int i;
+
+    hdf.setValue("indent", "" + (totalDepth - remainingDepth - 1));
+    hdf.setValue("colspan", "" + remainingDepth);
+
+    ClassInfo cl = Converter.obtainClass(name);
+
+    hdf.setValue("class.label", cl.name());
+    hdf.setValue("class.qualified", cl.qualifiedName());
+    if (cl.checkLevel()) {
+      hdf.setValue("class.link", cl.htmlPage());
+    }
+
+    if (exists(cl)) {
+      hdf.setValue("exists", "1");
+    }
+
+    i = 0;
+    for (ClassInfo iface : cl.interfaces()) {
+      hdf.setValue("interfaces." + i + ".class.label", iface.name());
+      hdf.setValue("interfaces." + i + ".class.qualified", iface.qualifiedName());
+      if (iface.checkLevel()) {
+        hdf.setValue("interfaces." + i + ".class.link", iface.htmlPage());
+      }
+      if (exists(cl)) {
+        hdf.setValue("interfaces." + i + ".exists", "1");
+      }
+      i++;
+    }
+
+    TreeSet<String> derived = nodes.get(name);
+    if (derived != null && derived.size() > 0) {
+      hdf.setValue("derived", "");
+      Data children = hdf.getChild("derived");
+      i = 0;
+      remainingDepth--;
+      for (String s : derived) {
+        String index = "" + i;
+        children.setValue(index, "");
+        recurse(nodes, s, children.getChild(index), totalDepth, remainingDepth);
+        i++;
+      }
+    }
+
+    nodes.remove(name);
+  }
+}
diff --git a/src/com/google/doclava/InheritedTags.java b/src/com/google/doclava/InheritedTags.java
new file mode 100644
index 0000000..1915721
--- /dev/null
+++ b/src/com/google/doclava/InheritedTags.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+public interface InheritedTags {
+  TagInfo[] tags();
+
+  InheritedTags inherited();
+}
diff --git a/src/com/google/doclava/JarUtils.java b/src/com/google/doclava/JarUtils.java
new file mode 100644
index 0000000..a5925ec
--- /dev/null
+++ b/src/com/google/doclava/JarUtils.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+public class JarUtils {
+  /**
+   * Returns the jar file used to load class clazz, or defaultJar if clazz was not loaded from a
+   * jar.
+   */
+  public static JarFile jarForClass(Class<?> clazz, JarFile defaultJar) {
+    String path = "/" + clazz.getName().replace('.', '/') + ".class";
+    URL jarUrl = clazz.getResource(path);
+    if (jarUrl == null) {
+      return defaultJar;
+    }
+
+    String url = jarUrl.toString();
+    int bang = url.indexOf("!");
+    String JAR_URI_PREFIX = "jar:file:";
+    if (url.startsWith(JAR_URI_PREFIX) && bang != -1) {
+      try {
+        return new JarFile(url.substring(JAR_URI_PREFIX.length(), bang));
+      } catch (IOException e) {
+        throw new IllegalStateException("Error loading jar file.", e);
+      }
+    } else {
+      return defaultJar;
+    }
+  }
+
+  /**
+   * Copies a directory from a jar file to an external directory.
+   */
+  public static void copyResourcesToDirectory(JarFile fromJar, String jarDir, String destDir)
+      throws IOException {
+    for (Enumeration<JarEntry> entries = fromJar.entries(); entries.hasMoreElements();) {
+      JarEntry entry = entries.nextElement();
+      if (entry.getName().startsWith(jarDir + "/") && !entry.isDirectory()) {
+        File dest = new File(destDir + "/" + entry.getName().substring(jarDir.length() + 1));
+        File parent = dest.getParentFile();
+        if (parent != null) {
+          parent.mkdirs();
+        }
+
+        FileOutputStream out = new FileOutputStream(dest);
+        InputStream in = fromJar.getInputStream(entry);
+
+        try {
+          byte[] buffer = new byte[8 * 1024];
+
+          int s = 0;
+          while ((s = in.read(buffer)) > 0) {
+            out.write(buffer, 0, s);
+          }
+        } catch (IOException e) {
+          throw new IOException("Could not copy asset from jar file", e);
+        } finally {
+          try {
+            in.close();
+          } catch (IOException ignored) {}
+          try {
+            out.close();
+          } catch (IOException ignored) {}
+        }
+      }
+    }
+
+  }
+
+  private JarUtils() {} // non-instantiable
+}
diff --git a/src/com/google/doclava/KeywordEntry.java b/src/com/google/doclava/KeywordEntry.java
new file mode 100644
index 0000000..28f2d47
--- /dev/null
+++ b/src/com/google/doclava/KeywordEntry.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+class KeywordEntry implements Comparable {
+  KeywordEntry(String label, String href, String comment) {
+    this.label = label;
+    this.href = href;
+    this.comment = comment;
+  }
+
+  public void makeHDF(Data data, String base) {
+    data.setValue(base + ".label", this.label);
+    data.setValue(base + ".href", this.href);
+    data.setValue(base + ".comment", this.comment);
+  }
+
+  public char firstChar() {
+    return Character.toUpperCase(this.label.charAt(0));
+  }
+
+  public int compareTo(Object that) {
+    return this.label.compareToIgnoreCase(((KeywordEntry) that).label);
+  }
+
+  private String label;
+  private String href;
+  private String comment;
+}
diff --git a/src/com/google/doclava/LinkReference.java b/src/com/google/doclava/LinkReference.java
new file mode 100644
index 0000000..8afba0b
--- /dev/null
+++ b/src/com/google/doclava/LinkReference.java
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.ArrayList;
+
+/**
+ * Class that represents what you see in an link or see tag. This is factored out of SeeTagInfo so
+ * it can be used elsewhere (like AttrTagInfo).
+ */
+public class LinkReference {
+
+  /** The original text. */
+  public String text;
+
+  /** The kind of this tag, if we have a new suggestion after parsing. */
+  public String kind;
+
+  /** The user visible text. */
+  public String label;
+
+  /** The link. */
+  public String href;
+
+  /** The {@link PackageInfo} if any. */
+  public PackageInfo packageInfo;
+
+  /** The {@link ClassInfo} if any. */
+  public ClassInfo classInfo;
+
+  /** The {@link MemberInfo} if any. */
+  public MemberInfo memberInfo;
+
+  /** The name of the referenced member PackageInfo} if any. */
+  public String referencedMemberName;
+
+  /** Set to true if everything is a-ok */
+  public boolean good;
+
+  /**
+   * regex pattern to use when matching explicit "<a href" reference text
+   */
+  private static final Pattern HREF_PATTERN =
+      Pattern.compile("^<a href=\"([^\"]*)\">([^<]*)</a>[ \n\r\t]*$", Pattern.CASE_INSENSITIVE);
+
+  /**
+   * regex pattern to use when matching double-quoted reference text
+   */
+  private static final Pattern QUOTE_PATTERN = Pattern.compile("^\"([^\"]*)\"[ \n\r\t]*$");
+
+  /**
+   * Parse and resolve a link string.
+   * 
+   * @param text the original text
+   * @param base the class or whatever that this link is on
+   * @param pos the original position in the source document
+   * @return a new link reference. It always returns something. If there was an error, it logs it
+   *         and fills in href and label with error text.
+   */
+  public static LinkReference parse(String text, ContainerInfo base, SourcePositionInfo pos,
+      boolean printOnErrors) {
+    LinkReference result = new LinkReference();
+    result.text = text;
+
+    int index;
+    int len = text.length();
+    int pairs = 0;
+    int pound = -1;
+    // split the string
+    done: {
+      for (index = 0; index < len; index++) {
+        char c = text.charAt(index);
+        switch (c) {
+          case '(':
+            pairs++;
+            break;
+          case '[':
+            pairs++;
+            break;
+          case ')':
+            pairs--;
+            break;
+          case ']':
+            pairs--;
+            break;
+          case ' ':
+          case '\t':
+          case '\r':
+          case '\n':
+            if (pairs == 0) {
+              break done;
+            }
+            break;
+          case '#':
+            if (pound < 0) {
+              pound = index;
+            }
+            break;
+        }
+      }
+    }
+    if (index == len && pairs != 0) {
+      Errors.error(Errors.UNRESOLVED_LINK, pos, "unable to parse link/see tag: " + text.trim());
+      return result;
+    }
+
+    int linkend = index;
+
+    for (; index < len; index++) {
+      char c = text.charAt(index);
+      if (!(c == ' ' || c == '\t' || c == '\r' || c == '\n')) {
+        break;
+      }
+    }
+
+    result.label = text.substring(index);
+
+    String ref;
+    String mem;
+    if (pound == 0) {
+      ref = null;
+      mem = text.substring(1, linkend);
+    } else if (pound > 0) {
+      ref = text.substring(0, pound);
+      mem = text.substring(pound + 1, linkend);
+    } else {
+      ref = text.substring(0, linkend);
+      mem = null;
+    }
+
+    // parse parameters, if any
+    String[] params = null;
+    String[] paramDimensions = null;
+    boolean varargs = false;
+    if (mem != null) {
+      index = mem.indexOf('(');
+      if (index > 0) {
+        ArrayList<String> paramList = new ArrayList<String>();
+        ArrayList<String> paramDimensionList = new ArrayList<String>();
+        len = mem.length();
+        int start = index + 1;
+        final int START = 0;
+        final int TYPE = 1;
+        final int NAME = 2;
+        int dimension = 0;
+        int arraypair = 0;
+        int state = START;
+        int typestart = 0;
+        int typeend = -1;
+        for (int i = start; i < len; i++) {
+          char c = mem.charAt(i);
+          switch (state) {
+            case START:
+              if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
+                state = TYPE;
+                typestart = i;
+              }
+              break;
+            case TYPE:
+              if (c == '.') {
+                if (mem.length() > i+2 && mem.charAt(i+1) == '.' && mem.charAt(i+2) == '.') {
+                  if (typeend < 0) {
+                    typeend = i;
+                  }
+                  varargs = true;
+                }
+              } else if (c == '[') {
+                if (typeend < 0) {
+                  typeend = i;
+                }
+                dimension++;
+                arraypair++;
+              } else if (c == ']') {
+                arraypair--;
+              } else if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+                if (typeend < 0) {
+                  typeend = i;
+                }
+              } else {
+                if (typeend >= 0 || c == ')' || c == ',') {
+                  if (typeend < 0) {
+                    typeend = i;
+                  }
+                  String s = mem.substring(typestart, typeend);
+                  paramList.add(s);
+                  s = "";
+                  for (int j = 0; j < dimension; j++) {
+                    s += "[]";
+                  }
+                  paramDimensionList.add(s);
+                  state = START;
+                  typeend = -1;
+                  dimension = 0;
+                  if (c == ',' || c == ')') {
+                    state = START;
+                  } else {
+                    state = NAME;
+                  }
+                }
+              }
+              break;
+            case NAME:
+              if (c == ',' || c == ')') {
+                state = START;
+              }
+              break;
+          }
+
+        }
+        params = paramList.toArray(new String[paramList.size()]);
+        paramDimensions = paramDimensionList.toArray(new String[paramList.size()]);
+        mem = mem.substring(0, index);
+      }
+    }
+
+    ClassInfo cl = null;
+    if (base instanceof ClassInfo) {
+      cl = (ClassInfo) base;
+    }
+
+    if (ref == null) {
+      // no class or package was provided, assume it's this class
+      if (cl != null) {
+        result.classInfo = cl;
+      }
+    } else {
+      // they provided something, maybe it's a class or a package
+      if (cl != null) {
+        result.classInfo = cl.extendedFindClass(ref);
+        if (result.classInfo == null) {
+          result.classInfo = cl.findClass(ref);
+        }
+        if (result.classInfo == null) {
+          result.classInfo = cl.findInnerClass(ref);
+        }
+      }
+      if (result.classInfo == null) {
+        result.classInfo = Converter.obtainClass(ref);
+      }
+      if (result.classInfo == null) {
+        result.packageInfo = Converter.obtainPackage(ref);
+      }
+    }
+
+    if (result.classInfo != null && mem != null) {
+      // it's either a field or a method, prefer a field
+      if (params == null) {
+        FieldInfo field = result.classInfo.findField(mem);
+        // findField looks in containing classes, so it might actually
+        // be somewhere else; link to where it really is, not what they
+        // typed.
+        if (field != null) {
+          result.classInfo = field.containingClass();
+          result.memberInfo = field;
+        }
+      }
+      if (result.memberInfo == null) {
+        MethodInfo method = result.classInfo.findMethod(mem, params, paramDimensions, varargs);
+        if (method != null) {
+          result.classInfo = method.containingClass();
+          result.memberInfo = method;
+        }
+      }
+    }
+
+    result.referencedMemberName = mem;
+    if (params != null) {
+      result.referencedMemberName = result.referencedMemberName + '(';
+      len = params.length;
+      if (len > 0) {
+        len--;
+        for (int i = 0; i < len; i++) {
+          result.referencedMemberName =
+              result.referencedMemberName + params[i] + paramDimensions[i] + ", ";
+        }
+        result.referencedMemberName =
+            result.referencedMemberName + params[len] + paramDimensions[len];
+      }
+      result.referencedMemberName = result.referencedMemberName + ")";
+    }
+
+    // debugging spew
+    if (false) {
+      result.label = result.label + "/" + ref + "/" + mem + '/';
+      if (params != null) {
+        for (int i = 0; i < params.length; i++) {
+          result.label += params[i] + "|";
+        }
+      }
+
+      FieldInfo f = (result.memberInfo instanceof FieldInfo) ? (FieldInfo) result.memberInfo : null;
+      MethodInfo m =
+          (result.memberInfo instanceof MethodInfo) ? (MethodInfo) result.memberInfo : null;
+      result.label =
+          result.label + "/package="
+              + (result.packageInfo != null ? result.packageInfo.name() : "") + "/class="
+              + (result.classInfo != null ? result.classInfo.qualifiedName() : "") + "/field="
+              + (f != null ? f.name() : "") + "/method=" + (m != null ? m.name() : "");
+
+    }
+
+    MethodInfo method = null;
+    boolean skipHref = false;
+
+    if (result.memberInfo != null && result.memberInfo.isExecutable()) {
+      method = (MethodInfo) result.memberInfo;
+    }
+
+    if (text.startsWith("\"")) {
+      // literal quoted reference (e.g., a book title)
+      Matcher matcher = QUOTE_PATTERN.matcher(text);
+      if (!matcher.matches()) {
+        Errors.error(Errors.UNRESOLVED_LINK, pos, "unbalanced quoted link/see tag: " + text.trim());
+        result.makeError();
+        return result;
+      }
+      skipHref = true;
+      result.label = matcher.group(1);
+      result.kind = "@seeJustLabel";
+    } else if (text.startsWith("<")) {
+      // explicit "<a href" form
+      Matcher matcher = HREF_PATTERN.matcher(text);
+      if (!matcher.matches()) {
+        Errors.error(Errors.UNRESOLVED_LINK, pos, "invalid <a> link/see tag: " + text.trim());
+        result.makeError();
+        return result;
+      }
+      result.href = matcher.group(1);
+      result.label = matcher.group(2);
+      result.kind = "@seeHref";
+    } else if (result.packageInfo != null) {
+      result.href = result.packageInfo.htmlPage();
+      if (result.label.length() == 0) {
+        result.href = result.packageInfo.htmlPage();
+        result.label = result.packageInfo.name();
+      }
+    } else if (result.classInfo != null && result.referencedMemberName == null) {
+      // class reference
+      if (result.label.length() == 0) {
+        result.label = result.classInfo.name();
+      }
+      result.href = result.classInfo.htmlPage();
+    } else if (result.memberInfo != null) {
+      // member reference
+      ClassInfo containing = result.memberInfo.containingClass();
+      if (result.memberInfo.isExecutable()) {
+        if (result.referencedMemberName.indexOf('(') < 0) {
+          result.referencedMemberName += method.flatSignature();
+        }
+      }
+      if (result.label.length() == 0) {
+        result.label = result.referencedMemberName;
+      }
+      result.href = containing.htmlPage() + '#' + result.memberInfo.anchor();
+    }
+
+    if (result.href == null && !skipHref) {
+      if (printOnErrors && (base == null || base.checkLevel())) {
+        Errors.error(Errors.UNRESOLVED_LINK, pos, "Unresolved link/see tag \"" + text.trim()
+            + "\" in " + ((base != null) ? base.qualifiedName() : "[null]"));
+      }
+      result.makeError();
+    } else if (result.memberInfo != null && !result.memberInfo.checkLevel()) {
+      if (printOnErrors && (base == null || base.checkLevel())) {
+        Errors.error(Errors.HIDDEN_LINK, pos, "Link to hidden member: " + text.trim());
+        result.href = null;
+      }
+      result.kind = "@seeJustLabel";
+    } else if (result.classInfo != null && !result.classInfo.checkLevel()) {
+      if (printOnErrors && (base == null || base.checkLevel())) {
+        Errors.error(Errors.HIDDEN_LINK, pos, "Link to hidden class: " + text.trim() + " label="
+            + result.label);
+        result.href = null;
+      }
+      result.kind = "@seeJustLabel";
+    } else if (result.packageInfo != null && !result.packageInfo.checkLevel()) {
+      if (printOnErrors && (base == null || base.checkLevel())) {
+        Errors.error(Errors.HIDDEN_LINK, pos, "Link to hidden package: " + text.trim());
+        result.href = null;
+      }
+      result.kind = "@seeJustLabel";
+    }
+
+    result.good = true;
+
+    return result;
+  }
+
+  public boolean checkLevel() {
+    if (memberInfo != null) {
+      return memberInfo.checkLevel();
+    }
+    if (classInfo != null) {
+      return classInfo.checkLevel();
+    }
+    if (packageInfo != null) {
+      return packageInfo.checkLevel();
+    }
+    return false;
+  }
+
+  /** turn this LinkReference into one with an error message */
+  private void makeError() {
+    // this.href = "ERROR(" + this.text.trim() + ")";
+    this.href = null;
+    if (this.label == null) {
+      this.label = "";
+    }
+    this.label = "ERROR(" + this.label + "/" + text.trim() + ")";
+  }
+
+  /** private. **/
+  private LinkReference() {}
+}
diff --git a/src/com/google/doclava/LiteralTagInfo.java b/src/com/google/doclava/LiteralTagInfo.java
new file mode 100644
index 0000000..1feb276
--- /dev/null
+++ b/src/com/google/doclava/LiteralTagInfo.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+public class LiteralTagInfo extends TagInfo {
+  private static String encode(String t) {
+    t = t.replace("&", "&amp;");
+    t = t.replace("<", "&lt;");
+    t = t.replace(">", "&gt;");
+    return t;
+  }
+
+  public LiteralTagInfo(String text, SourcePositionInfo sp) {
+    super("Text", "Text", encode(text), sp);
+  }
+}
diff --git a/src/com/google/doclava/MemberInfo.java b/src/com/google/doclava/MemberInfo.java
new file mode 100644
index 0000000..9855e01
--- /dev/null
+++ b/src/com/google/doclava/MemberInfo.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+public abstract class MemberInfo extends DocInfo implements Comparable, Scoped {
+  public MemberInfo(String rawCommentText, String name, String signature,
+      ClassInfo containingClass, ClassInfo realContainingClass, boolean isPublic,
+      boolean isProtected, boolean isPackagePrivate, boolean isPrivate, boolean isFinal,
+      boolean isStatic, boolean isSynthetic, String kind, SourcePositionInfo position,
+      AnnotationInstanceInfo[] annotations) {
+    super(rawCommentText, position);
+    mName = name;
+    mSignature = signature;
+    mContainingClass = containingClass;
+    mRealContainingClass = realContainingClass;
+    mIsPublic = isPublic;
+    mIsProtected = isProtected;
+    mIsPackagePrivate = isPackagePrivate;
+    mIsPrivate = isPrivate;
+    mIsFinal = isFinal;
+    mIsStatic = isStatic;
+    mIsSynthetic = isSynthetic;
+    mKind = kind;
+    mAnnotations = annotations;
+  }
+
+  public abstract boolean isExecutable();
+
+  public String anchor() {
+    if (mSignature != null) {
+      return mName + mSignature;
+    } else {
+      return mName;
+    }
+  }
+
+  public String htmlPage() {
+    return mContainingClass.htmlPage() + "#" + anchor();
+  }
+
+  public int compareTo(Object that) {
+    return this.htmlPage().compareTo(((MemberInfo) that).htmlPage());
+  }
+
+  public String name() {
+    return mName;
+  }
+
+  public String signature() {
+    return mSignature;
+  }
+
+  public ClassInfo realContainingClass() {
+    return mRealContainingClass;
+  }
+
+  public ClassInfo containingClass() {
+    return mContainingClass;
+  }
+
+  public boolean isPublic() {
+    return mIsPublic;
+  }
+
+  public boolean isProtected() {
+    return mIsProtected;
+  }
+
+  public boolean isPackagePrivate() {
+    return mIsPackagePrivate;
+  }
+
+  public boolean isPrivate() {
+    return mIsPrivate;
+  }
+  
+  public String scope() {
+    if (isPublic()) {
+      return "public";
+    } else if (isProtected()) {
+      return "protected";
+    } else if (isPackagePrivate()) {
+      return "";
+    } else if (isPrivate()) {
+      return "private";
+    } else {
+      throw new RuntimeException("invalid scope for object " + this);
+    }
+  }
+
+  public boolean isStatic() {
+    return mIsStatic;
+  }
+
+  public boolean isFinal() {
+    return mIsFinal;
+  }
+
+  public boolean isSynthetic() {
+    return mIsSynthetic;
+  }
+
+  @Override
+  public ContainerInfo parent() {
+    return mContainingClass;
+  }
+
+  public boolean checkLevel() {
+    return Doclava.checkLevel(mIsPublic, mIsProtected, mIsPackagePrivate, mIsPrivate, isHidden());
+  }
+
+  public String kind() {
+    return mKind;
+  }
+
+  public AnnotationInstanceInfo[] annotations() {
+    return mAnnotations;
+  }
+
+  ClassInfo mContainingClass;
+  ClassInfo mRealContainingClass;
+  String mName;
+  String mSignature;
+  boolean mIsPublic;
+  boolean mIsProtected;
+  boolean mIsPackagePrivate;
+  boolean mIsPrivate;
+  boolean mIsFinal;
+  boolean mIsStatic;
+  boolean mIsSynthetic;
+  String mKind;
+  private AnnotationInstanceInfo[] mAnnotations;
+
+}
diff --git a/src/com/google/doclava/MethodInfo.java b/src/com/google/doclava/MethodInfo.java
new file mode 100644
index 0000000..c7e2304
--- /dev/null
+++ b/src/com/google/doclava/MethodInfo.java
@@ -0,0 +1,810 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+import com.google.doclava.apicheck.AbstractMethodInfo;
+
+import java.util.*;
+
+public class MethodInfo extends MemberInfo implements AbstractMethodInfo {
+  public static final Comparator<MethodInfo> comparator = new Comparator<MethodInfo>() {
+    public int compare(MethodInfo a, MethodInfo b) {
+      return a.name().compareTo(b.name());
+    }
+  };
+
+  private class InlineTags implements InheritedTags {
+    public TagInfo[] tags() {
+      return comment().tags();
+    }
+
+    public InheritedTags inherited() {
+      MethodInfo m = findOverriddenMethod(name(), signature());
+      if (m != null) {
+        return m.inlineTags();
+      } else {
+        return null;
+      }
+    }
+  }
+
+  private static void addInterfaces(ClassInfo[] ifaces, ArrayList<ClassInfo> queue) {
+    for (ClassInfo i : ifaces) {
+      queue.add(i);
+    }
+    for (ClassInfo i : ifaces) {
+      addInterfaces(i.interfaces(), queue);
+    }
+  }
+
+  // first looks for a superclass, and then does a breadth first search to
+  // find the least far away match
+  public MethodInfo findOverriddenMethod(String name, String signature) {
+    if (mReturnType == null) {
+      // ctor
+      return null;
+    }
+    if (mOverriddenMethod != null) {
+      return mOverriddenMethod;
+    }
+
+    ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
+    addInterfaces(containingClass().interfaces(), queue);
+    for (ClassInfo iface : queue) {
+      for (MethodInfo me : iface.methods()) {
+        if (me.name().equals(name) && me.signature().equals(signature)
+            && me.inlineTags().tags() != null && me.inlineTags().tags().length > 0) {
+          return me;
+        }
+      }
+    }
+    return null;
+  }
+
+  private static void addRealInterfaces(ClassInfo[] ifaces, ArrayList<ClassInfo> queue) {
+    for (ClassInfo i : ifaces) {
+      queue.add(i);
+      if (i.realSuperclass() != null && i.realSuperclass().isAbstract()) {
+        queue.add(i.superclass());
+      }
+    }
+    for (ClassInfo i : ifaces) {
+      addInterfaces(i.realInterfaces(), queue);
+    }
+  }
+
+  public MethodInfo findRealOverriddenMethod(String name, String signature, HashSet notStrippable) {
+    if (mReturnType == null) {
+      // ctor
+      return null;
+    }
+    if (mOverriddenMethod != null) {
+      return mOverriddenMethod;
+    }
+
+    ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
+    if (containingClass().realSuperclass() != null
+        && containingClass().realSuperclass().isAbstract()) {
+      queue.add(containingClass());
+    }
+    addInterfaces(containingClass().realInterfaces(), queue);
+    for (ClassInfo iface : queue) {
+      for (MethodInfo me : iface.methods()) {
+        if (me.name().equals(name) && me.signature().equals(signature)
+            && me.inlineTags().tags() != null && me.inlineTags().tags().length > 0
+            && notStrippable.contains(me.containingClass())) {
+          return me;
+        }
+      }
+    }
+    return null;
+  }
+
+  public MethodInfo findSuperclassImplementation(HashSet notStrippable) {
+    if (mReturnType == null) {
+      // ctor
+      return null;
+    }
+    if (mOverriddenMethod != null) {
+      // Even if we're told outright that this was the overridden method, we want to
+      // be conservative and ignore mismatches of parameter types -- they arise from
+      // extending generic specializations, and we want to consider the derived-class
+      // method to be a non-override.
+      if (this.signature().equals(mOverriddenMethod.signature())) {
+        return mOverriddenMethod;
+      }
+    }
+
+    ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
+    if (containingClass().realSuperclass() != null
+        && containingClass().realSuperclass().isAbstract()) {
+      queue.add(containingClass());
+    }
+    addInterfaces(containingClass().realInterfaces(), queue);
+    for (ClassInfo iface : queue) {
+      for (MethodInfo me : iface.methods()) {
+        if (me.name().equals(this.name()) && me.signature().equals(this.signature())
+            && notStrippable.contains(me.containingClass())) {
+          return me;
+        }
+      }
+    }
+    return null;
+  }
+
+  public ClassInfo findRealOverriddenClass(String name, String signature) {
+    if (mReturnType == null) {
+      // ctor
+      return null;
+    }
+    if (mOverriddenMethod != null) {
+      return mOverriddenMethod.mRealContainingClass;
+    }
+
+    ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
+    if (containingClass().realSuperclass() != null
+        && containingClass().realSuperclass().isAbstract()) {
+      queue.add(containingClass());
+    }
+    addInterfaces(containingClass().realInterfaces(), queue);
+    for (ClassInfo iface : queue) {
+      for (MethodInfo me : iface.methods()) {
+        if (me.name().equals(name) && me.signature().equals(signature)
+            && me.inlineTags().tags() != null && me.inlineTags().tags().length > 0) {
+          return iface;
+        }
+      }
+    }
+    return null;
+  }
+
+  private class FirstSentenceTags implements InheritedTags {
+    public TagInfo[] tags() {
+      return comment().briefTags();
+    }
+
+    public InheritedTags inherited() {
+      MethodInfo m = findOverriddenMethod(name(), signature());
+      if (m != null) {
+        return m.firstSentenceTags();
+      } else {
+        return null;
+      }
+    }
+  }
+
+  private class ReturnTags implements InheritedTags {
+    public TagInfo[] tags() {
+      return comment().returnTags();
+    }
+
+    public InheritedTags inherited() {
+      MethodInfo m = findOverriddenMethod(name(), signature());
+      if (m != null) {
+        return m.returnTags();
+      } else {
+        return null;
+      }
+    }
+  }
+
+  public boolean isDeprecated() {
+    boolean deprecated = false;
+    if (!mDeprecatedKnown) {
+      boolean commentDeprecated = comment().isDeprecated();
+      boolean annotationDeprecated = false;
+      for (AnnotationInstanceInfo annotation : annotations()) {
+        if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) {
+          annotationDeprecated = true;
+          break;
+        }
+      }
+
+      if (commentDeprecated != annotationDeprecated) {
+        Errors.error(Errors.DEPRECATION_MISMATCH, position(), "Method "
+            + mContainingClass.qualifiedName() + "." + name()
+            + ": @Deprecated annotation and @deprecated doc tag do not match");
+      }
+
+      mIsDeprecated = commentDeprecated | annotationDeprecated;
+      mDeprecatedKnown = true;
+    }
+    return mIsDeprecated;
+  }
+  
+  public void setDeprecated(boolean deprecated) {
+    mDeprecatedKnown = true;
+    mIsDeprecated = deprecated;
+  }
+
+  public TypeInfo[] getTypeParameters() {
+    return mTypeParameters;
+  }
+
+  public MethodInfo cloneForClass(ClassInfo newContainingClass) {
+    MethodInfo result =
+        new MethodInfo(getRawCommentText(), mTypeParameters, name(), signature(),
+            newContainingClass, realContainingClass(), isPublic(), isProtected(),
+            isPackagePrivate(), isPrivate(), isFinal(), isStatic(), isSynthetic(), mIsAbstract,
+            mIsSynchronized, mIsNative, mIsAnnotationElement, kind(), mFlatSignature,
+            mOverriddenMethod, mReturnType, mParameters, mThrownExceptions, position(),
+            annotations());
+    result.init(mDefaultAnnotationElementValue);
+    return result;
+  }
+
+  public MethodInfo(String rawCommentText, TypeInfo[] typeParameters, String name,
+      String signature, ClassInfo containingClass, ClassInfo realContainingClass, boolean isPublic,
+      boolean isProtected, boolean isPackagePrivate, boolean isPrivate, boolean isFinal,
+      boolean isStatic, boolean isSynthetic, boolean isAbstract, boolean isSynchronized,
+      boolean isNative, boolean isAnnotationElement, String kind, String flatSignature,
+      MethodInfo overriddenMethod, TypeInfo returnType, ParameterInfo[] parameters,
+      ClassInfo[] thrownExceptions, SourcePositionInfo position,
+      AnnotationInstanceInfo[] annotations) {
+    // Explicitly coerce 'final' state of Java6-compiled enum values() method, to match
+    // the Java5-emitted base API description.
+    super(rawCommentText, name, signature, containingClass, realContainingClass, isPublic,
+        isProtected, isPackagePrivate, isPrivate, ((name.equals("values") && containingClass
+            .isEnum()) ? true : isFinal), isStatic, isSynthetic, kind, position, annotations);
+
+    // The underlying MethodDoc for an interface's declared methods winds up being marked
+    // non-abstract. Correct that here by looking at the immediate-parent class, and marking
+    // this method abstract if it is an unimplemented interface method.
+    if (containingClass.isInterface()) {
+      isAbstract = true;
+    }
+
+    mReasonOpened = "0:0";
+    mIsAnnotationElement = isAnnotationElement;
+    mTypeParameters = typeParameters;
+    mIsAbstract = isAbstract;
+    mIsSynchronized = isSynchronized;
+    mIsNative = isNative;
+    mFlatSignature = flatSignature;
+    mOverriddenMethod = overriddenMethod;
+    mReturnType = returnType;
+    mParameters = parameters;
+    mThrownExceptions = thrownExceptions;
+  }
+
+  public void init(AnnotationValueInfo defaultAnnotationElementValue) {
+    mDefaultAnnotationElementValue = defaultAnnotationElementValue;
+  }
+
+  public boolean isAbstract() {
+    return mIsAbstract;
+  }
+
+  public boolean isSynchronized() {
+    return mIsSynchronized;
+  }
+
+  public boolean isNative() {
+    return mIsNative;
+  }
+
+  public String flatSignature() {
+    return mFlatSignature;
+  }
+
+  public InheritedTags inlineTags() {
+    return new InlineTags();
+  }
+
+  public InheritedTags firstSentenceTags() {
+    return new FirstSentenceTags();
+  }
+
+  public InheritedTags returnTags() {
+    return new ReturnTags();
+  }
+
+  public TypeInfo returnType() {
+    return mReturnType;
+  }
+  
+  public String prettySignature() {
+    return name() + prettyParameters();
+  }
+  
+  /**
+   * Returns a printable version of the parameters of this method's signature.
+   */
+  public String prettyParameters() {
+    StringBuilder params = new StringBuilder("(");
+    for (ParameterInfo pInfo : mParameters) {
+      if (params.length() > 1) {
+        params.append(",");
+      }
+      params.append(pInfo.type().simpleTypeName());
+    }
+    
+    params.append(")");
+    return params.toString();
+  }
+
+  /**
+   * Returns a name consistent with the {@link com.google.doclava.MethodInfo#getHashableName()}.
+   */
+  public String getHashableName() {
+    StringBuilder result = new StringBuilder();
+    result.append(name());
+    for (int p = 0; p < mParameters.length; p++) {
+      result.append(":");
+      if (p == mParameters.length - 1 && isVarArgs()) {
+        // TODO: note that this does not attempt to handle hypothetical
+        // vararg methods whose last parameter is a list of arrays, e.g.
+        // "Object[]...".
+        result.append(mParameters[p].type().fullNameNoDimension(typeVariables())).append("...");
+      } else {
+        result.append(mParameters[p].type().fullName(typeVariables()));
+      }
+    }
+    return result.toString();
+  }
+
+  private boolean inList(ClassInfo item, ThrowsTagInfo[] list) {
+    int len = list.length;
+    String qn = item.qualifiedName();
+    for (int i = 0; i < len; i++) {
+      ClassInfo ex = list[i].exception();
+      if (ex != null && ex.qualifiedName().equals(qn)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public ThrowsTagInfo[] throwsTags() {
+    if (mThrowsTags == null) {
+      ThrowsTagInfo[] documented = comment().throwsTags();
+      ArrayList<ThrowsTagInfo> rv = new ArrayList<ThrowsTagInfo>();
+
+      int len = documented.length;
+      for (int i = 0; i < len; i++) {
+        rv.add(documented[i]);
+      }
+
+      ClassInfo[] all = mThrownExceptions;
+      len = all.length;
+      for (int i = 0; i < len; i++) {
+        ClassInfo cl = all[i];
+        if (documented == null || !inList(cl, documented)) {
+          rv.add(new ThrowsTagInfo("@throws", "@throws", cl.qualifiedName(), cl, "",
+              containingClass(), position()));
+        }
+      }
+      mThrowsTags = rv.toArray(new ThrowsTagInfo[rv.size()]);
+    }
+    return mThrowsTags;
+  }
+
+  private static int indexOfParam(String name, String[] list) {
+    final int N = list.length;
+    for (int i = 0; i < N; i++) {
+      if (name.equals(list[i])) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  public ParamTagInfo[] paramTags() {
+    if (mParamTags == null) {
+      final int N = mParameters.length;
+
+      String[] names = new String[N];
+      String[] comments = new String[N];
+      SourcePositionInfo[] positions = new SourcePositionInfo[N];
+
+      // get the right names so we can handle our names being different from
+      // our parent's names.
+      for (int i = 0; i < N; i++) {
+        names[i] = mParameters[i].name();
+        comments[i] = "";
+        positions[i] = mParameters[i].position();
+      }
+
+      // gather our comments, and complain about misnamed @param tags
+      for (ParamTagInfo tag : comment().paramTags()) {
+        int index = indexOfParam(tag.parameterName(), names);
+        if (index >= 0) {
+          comments[index] = tag.parameterComment();
+          positions[index] = tag.position();
+        } else {
+          Errors.error(Errors.UNKNOWN_PARAM_TAG_NAME, tag.position(),
+              "@param tag with name that doesn't match the parameter list: '" + tag.parameterName()
+                  + "'");
+        }
+      }
+
+      // get our parent's tags to fill in the blanks
+      MethodInfo overridden = this.findOverriddenMethod(name(), signature());
+      if (overridden != null) {
+        ParamTagInfo[] maternal = overridden.paramTags();
+        for (int i = 0; i < N; i++) {
+          if (comments[i].equals("")) {
+            comments[i] = maternal[i].parameterComment();
+            positions[i] = maternal[i].position();
+          }
+        }
+      }
+
+      // construct the results, and cache them for next time
+      mParamTags = new ParamTagInfo[N];
+      for (int i = 0; i < N; i++) {
+        mParamTags[i] =
+            new ParamTagInfo("@param", "@param", names[i] + " " + comments[i], parent(),
+                positions[i]);
+
+        // while we're here, if we find any parameters that are still undocumented at this
+        // point, complain. (this warning is off by default, because it's really, really
+        // common; but, it's good to be able to enforce it)
+        if (comments[i].equals("")) {
+          Errors.error(Errors.UNDOCUMENTED_PARAMETER, positions[i], "Undocumented parameter '"
+              + names[i] + "' on method '" + name() + "'");
+        }
+      }
+    }
+    return mParamTags;
+  }
+
+  public SeeTagInfo[] seeTags() {
+    SeeTagInfo[] result = comment().seeTags();
+    if (result == null) {
+      if (mOverriddenMethod != null) {
+        result = mOverriddenMethod.seeTags();
+      }
+    }
+    return result;
+  }
+
+  public TagInfo[] deprecatedTags() {
+    TagInfo[] result = comment().deprecatedTags();
+    if (result.length == 0) {
+      if (comment().undeprecateTags().length == 0) {
+        if (mOverriddenMethod != null) {
+          result = mOverriddenMethod.deprecatedTags();
+        }
+      }
+    }
+    return result;
+  }
+
+  public ParameterInfo[] parameters() {
+    return mParameters;
+  }
+
+
+  public boolean matchesParams(String[] params, String[] dimensions, boolean varargs) {
+    if (mParamStrings == null) {
+      ParameterInfo[] mine = mParameters;
+      int len = mine.length;
+      if (len != params.length) {
+        return false;
+      }
+      for (int i = 0; i < len; i++) {
+        if (!mine[i].matchesDimension(dimensions[i], varargs)) {
+          return false;
+        }
+        TypeInfo myType = mine[i].type();
+        String qualifiedName = myType.qualifiedTypeName();
+        String realType = myType.isPrimitive() ? "" : myType.asClassInfo().qualifiedName();
+        String s = params[i];
+        int slen = s.length();
+        int qnlen = qualifiedName.length();
+        
+        // Check for a matching generic name or best known type
+        if (!matchesType(qualifiedName, s) && !matchesType(realType, s)) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+  
+  /**
+   * Checks to see if a parameter from a method signature is
+   * compatible with a parameter given in a {@code @link} tag.
+   */
+  private boolean matchesType(String signatureParam, String callerParam) {
+    int signatureLength = signatureParam.length();
+    int callerLength = callerParam.length();
+    return ((signatureParam.equals(callerParam) || ((callerLength + 1) < signatureLength
+        && signatureParam.charAt(signatureLength - callerLength - 1) == '.'
+        && signatureParam.endsWith(callerParam))));
+  }
+
+  public void makeHDF(Data data, String base) {
+    data.setValue(base + ".kind", kind());
+    data.setValue(base + ".name", name());
+    data.setValue(base + ".href", htmlPage());
+    data.setValue(base + ".anchor", anchor());
+
+    if (mReturnType != null) {
+      returnType().makeHDF(data, base + ".returnType", false, typeVariables());
+      data.setValue(base + ".abstract", mIsAbstract ? "abstract" : "");
+    }
+
+    data.setValue(base + ".synchronized", mIsSynchronized ? "synchronized" : "");
+    data.setValue(base + ".final", isFinal() ? "final" : "");
+    data.setValue(base + ".static", isStatic() ? "static" : "");
+
+    TagInfo.makeHDF(data, base + ".shortDescr", firstSentenceTags());
+    TagInfo.makeHDF(data, base + ".descr", inlineTags());
+    TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags());
+    TagInfo.makeHDF(data, base + ".seeAlso", seeTags());
+    data.setValue(base + ".since", getSince());
+    ParamTagInfo.makeHDF(data, base + ".paramTags", paramTags());
+    AttrTagInfo.makeReferenceHDF(data, base + ".attrRefs", comment().attrTags());
+    ThrowsTagInfo.makeHDF(data, base + ".throws", throwsTags());
+    ParameterInfo.makeHDF(data, base + ".params", parameters(), isVarArgs(), typeVariables());
+    if (isProtected()) {
+      data.setValue(base + ".scope", "protected");
+    } else if (isPublic()) {
+      data.setValue(base + ".scope", "public");
+    }
+    TagInfo.makeHDF(data, base + ".returns", returnTags());
+
+    if (mTypeParameters != null) {
+      TypeInfo.makeHDF(data, base + ".generic.typeArguments", mTypeParameters, false);
+    }
+    
+    setFederatedReferences(data, base);
+  }
+
+  public HashSet<String> typeVariables() {
+    HashSet<String> result = TypeInfo.typeVariables(mTypeParameters);
+    ClassInfo cl = containingClass();
+    while (cl != null) {
+      TypeInfo[] types = cl.asTypeInfo().typeArguments();
+      if (types != null) {
+        TypeInfo.typeVariables(types, result);
+      }
+      cl = cl.containingClass();
+    }
+    return result;
+  }
+
+  @Override
+  public boolean isExecutable() {
+    return true;
+  }
+
+  public ClassInfo[] thrownExceptions() {
+    return mThrownExceptions;
+  }
+
+  public String typeArgumentsName(HashSet<String> typeVars) {
+    if (mTypeParameters == null || mTypeParameters.length == 0) {
+      return "";
+    } else {
+      return TypeInfo.typeArgumentsName(mTypeParameters, typeVars);
+    }
+  }
+
+  public boolean isAnnotationElement() {
+    return mIsAnnotationElement;
+  }
+
+  public AnnotationValueInfo defaultAnnotationElementValue() {
+    return mDefaultAnnotationElementValue;
+  }
+
+  public void setVarargs(boolean set) {
+    mIsVarargs = set;
+  }
+
+  public boolean isVarArgs() {
+    return mIsVarargs;
+  }
+
+  @Override
+  public String toString() {
+    return this.name();
+  }
+
+  public void setReason(String reason) {
+    mReasonOpened = reason;
+  }
+
+  public String getReason() {
+    return mReasonOpened;
+  }
+  
+  public void addException(String exec) {
+    ClassInfo exceptionClass = new ClassInfo(exec);
+    List<ClassInfo> exceptions = new ArrayList<ClassInfo>(mThrownExceptions.length + 1);
+    exceptions.addAll(Arrays.asList(mThrownExceptions));
+    exceptions.add(exceptionClass);
+    mThrownExceptions = new ClassInfo[exceptions.size()];
+    exceptions.toArray(mThrownExceptions);
+  }
+  
+  public void addParameter(ParameterInfo p) {
+    // Name information
+    ParameterInfo[] newParams;
+    int i = 0;
+    
+    if (mParameters == null) {
+      newParams = new ParameterInfo[1];
+    } else {
+      newParams = new ParameterInfo[mParameters.length+1];
+      for (ParameterInfo info : mParameters) {
+        newParams[i++] = info;
+      }
+    }
+    newParams[i] = p;
+    mParameters = newParams;
+    
+    // Type information
+    TypeInfo[] newTypes;
+    i = 0;
+    
+    if (mTypeParameters == null) {
+      newTypes = new TypeInfo[1];
+    } else {
+      newTypes = new TypeInfo[mTypeParameters.length+1];
+      for (TypeInfo info : mTypeParameters) {
+        newTypes[i++] = info;
+      }
+    }
+    newTypes[i] = p.mType;
+    mTypeParameters = newTypes;
+  }
+
+  private String mFlatSignature;
+  private MethodInfo mOverriddenMethod;
+  private TypeInfo mReturnType;
+  private boolean mIsAnnotationElement;
+  private boolean mIsAbstract;
+  private boolean mIsSynchronized;
+  private boolean mIsNative;
+  private boolean mIsVarargs;
+  private boolean mDeprecatedKnown;
+  private boolean mIsDeprecated;
+  private ParameterInfo[] mParameters;
+  private ClassInfo[] mThrownExceptions;
+  private String[] mParamStrings;
+  ThrowsTagInfo[] mThrowsTags;
+  private ParamTagInfo[] mParamTags;
+  private TypeInfo[] mTypeParameters;
+  private AnnotationValueInfo mDefaultAnnotationElementValue;
+  private String mReasonOpened;
+  
+  // TODO: merge with droiddoc version (above)  
+  public String qualifiedName() {
+    String parentQName = (containingClass() != null)
+        ? (containingClass().qualifiedName() + ".") : "";
+    return parentQName + name();
+  }
+
+  @Override
+  public String signature() {
+    if (mSignature == null) {
+      StringBuilder params = new StringBuilder("(");
+      for (ParameterInfo pInfo : mParameters) {
+        if (params.length() > 1) {
+          params.append(", ");
+        }
+        params.append(pInfo.type().fullName());
+      }
+      
+      params.append(")");
+      mSignature = params.toString();
+    }
+    return mSignature;
+  }
+
+  public boolean matches(MethodInfo other) {
+    return signature().equals(other.signature());
+  }
+
+  public boolean throwsException(ClassInfo exception) {
+    for (ClassInfo e : mThrownExceptions) {
+      if (e.qualifiedName().equals(exception.qualifiedName())) {
+        return true;
+      }
+    }
+    return false;
+  }
+  
+  public boolean isConsistent(MethodInfo mInfo) {
+    boolean consistent = true;
+    if (!this.mReturnType.equals(mInfo.mReturnType)) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_TYPE, mInfo.position(), "Method " + mInfo.qualifiedName()
+          + " has changed return type from " + mReturnType + " to " + mInfo.mReturnType);
+    }
+
+    if (mIsAbstract != mInfo.mIsAbstract) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_ABSTRACT, mInfo.position(), "Method " + mInfo.qualifiedName()
+          + " has changed 'abstract' qualifier");
+    }
+
+    if (mIsNative != mInfo.mIsNative) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_NATIVE, mInfo.position(), "Method " + mInfo.qualifiedName()
+          + " has changed 'native' qualifier");
+    }
+
+    if (mIsFinal != mInfo.mIsFinal) {
+      // Compiler-generated methods vary in their 'final' qual between versions of
+      // the compiler, so this check needs to be quite narrow. A change in 'final'
+      // status of a method is only relevant if (a) the method is not declared 'static'
+      // and (b) the method's class is not itself 'final'.
+      if (!mIsStatic) {
+        if ((containingClass() == null) || (!containingClass().isFinal())) {
+          consistent = false;
+          Errors.error(Errors.CHANGED_FINAL, mInfo.position(), "Method " + mInfo.qualifiedName()
+              + " has changed 'final' qualifier");
+        }
+      }
+    }
+
+    if (mIsStatic != mInfo.mIsStatic) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_STATIC, mInfo.position(), "Method " + mInfo.qualifiedName()
+          + " has changed 'static' qualifier");
+    }
+
+    if (!scope().equals(mInfo.scope())) {
+      consistent = false;
+      Errors.error(Errors.CHANGED_SCOPE, mInfo.position(), "Method " + mInfo.qualifiedName()
+          + " changed scope from " + scope() + " to " + mInfo.scope());
+    }
+
+    if (!isDeprecated() == mInfo.isDeprecated()) {
+      Errors.error(Errors.CHANGED_DEPRECATED, mInfo.position(), "Method " + mInfo.qualifiedName()
+          + " has changed deprecation state");
+      consistent = false;
+    }
+
+    if (mIsSynchronized != mInfo.mIsSynchronized) {
+      Errors.error(Errors.CHANGED_SYNCHRONIZED, mInfo.position(), "Method " + mInfo.qualifiedName()
+          + " has changed 'synchronized' qualifier from " + mIsSynchronized + " to "
+          + mInfo.mIsSynchronized);
+      consistent = false;
+    }
+
+    for (ClassInfo exception : thrownExceptions()) {
+      if (!mInfo.throwsException(exception)) {
+        // exclude 'throws' changes to finalize() overrides with no arguments
+        if (!name().equals("finalize") || (mParameters.length > 0)) {
+          Errors.error(Errors.CHANGED_THROWS, mInfo.position(), "Method " + mInfo.qualifiedName()
+              + " no longer throws exception " + exception.qualifiedName());
+          consistent = false;
+        }
+      }
+    }
+
+    for (ClassInfo exec : mInfo.thrownExceptions()) {
+      // exclude 'throws' changes to finalize() overrides with no arguments
+      if (!throwsException(exec)) {
+        if (!name().equals("finalize") || (mParameters.length > 0)) {
+          Errors.error(Errors.CHANGED_THROWS, mInfo.position(), "Method " + mInfo.qualifiedName()
+              + " added thrown exception " + exec.qualifiedName());
+          consistent = false;
+        }
+      }
+    }
+
+    return consistent;
+  }
+}
diff --git a/src/com/google/doclava/NavTree.java b/src/com/google/doclava/NavTree.java
new file mode 100644
index 0000000..5c3e53d
--- /dev/null
+++ b/src/com/google/doclava/NavTree.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NavTree {
+
+  public static void writeNavTree(String dir) {
+    List<Node> children = new ArrayList<Node>();
+    for (PackageInfo pkg : Doclava.choosePackages()) {
+      children.add(makePackageNode(pkg));
+    }
+    Node node = new Node("Reference", dir + "packages.html", children, null);
+
+    StringBuilder buf = new StringBuilder();
+    if (false) {
+      // if you want a root node
+      buf.append("[");
+      node.render(buf);
+      buf.append("]");
+    } else {
+      // if you don't want a root node
+      node.renderChildren(buf);
+    }
+
+    Data data = Doclava.makeHDF();
+    data.setValue("reference_tree", buf.toString());
+    ClearPage.write(data, "navtree_data.cs", "navtree_data.js");
+  }
+
+  private static Node makePackageNode(PackageInfo pkg) {
+    List<Node> children = new ArrayList<Node>();
+
+    children.add(new Node("Description", pkg.fullDescriptionHtmlPage(), null, null));
+
+    addClassNodes(children, "Interfaces", pkg.interfaces());
+    addClassNodes(children, "Classes", pkg.ordinaryClasses());
+    addClassNodes(children, "Enums", pkg.enums());
+    addClassNodes(children, "Exceptions", pkg.exceptions());
+    addClassNodes(children, "Errors", pkg.errors());
+
+    return new Node(pkg.name(), pkg.htmlPage(), children, pkg.getSince());
+  }
+
+  private static void addClassNodes(List<Node> parent, String label, ClassInfo[] classes) {
+    List<Node> children = new ArrayList<Node>();
+
+    for (ClassInfo cl : classes) {
+      if (cl.checkLevel()) {
+        children.add(new Node(cl.name(), cl.htmlPage(), null, cl.getSince()));
+      }
+    }
+
+    if (children.size() > 0) {
+      parent.add(new Node(label, null, children, null));
+    }
+  }
+
+  private static class Node {
+    private String mLabel;
+    private String mLink;
+    List<Node> mChildren;
+    private String mSince;
+
+    Node(String label, String link, List<Node> children, String since) {
+      mLabel = label;
+      mLink = link;
+      mChildren = children;
+      mSince = since;
+    }
+
+    static void renderString(StringBuilder buf, String s) {
+      if (s == null) {
+        buf.append("null");
+      } else {
+        buf.append('"');
+        final int N = s.length();
+        for (int i = 0; i < N; i++) {
+          char c = s.charAt(i);
+          if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
+            buf.append(c);
+          } else {
+            buf.append("\\u");
+            for (int j = 0; i < 4; i++) {
+              char x = (char) (c & 0x000f);
+              if (x > 10) {
+                x = (char) (x - 10 + 'a');
+              } else {
+                x = (char) (x + '0');
+              }
+              buf.append(x);
+              c >>= 4;
+            }
+          }
+        }
+        buf.append('"');
+      }
+    }
+
+    void renderChildren(StringBuilder buf) {
+      List<Node> list = mChildren;
+      if (list == null || list.size() == 0) {
+        // We output null for no children. That way empty lists here can just
+        // be a byproduct of how we generate the lists.
+        buf.append("null");
+      } else {
+        buf.append("[ ");
+        final int N = list.size();
+        for (int i = 0; i < N; i++) {
+          list.get(i).render(buf);
+          if (i != N - 1) {
+            buf.append(", ");
+          }
+        }
+        buf.append(" ]\n");
+      }
+    }
+
+    void render(StringBuilder buf) {
+      buf.append("[ ");
+      renderString(buf, mLabel);
+      buf.append(", ");
+      renderString(buf, mLink);
+      buf.append(", ");
+      renderChildren(buf);
+      buf.append(", ");
+      renderString(buf, mSince);
+      buf.append(" ]");
+    }
+  }
+}
diff --git a/src/com/google/doclava/PackageInfo.java b/src/com/google/doclava/PackageInfo.java
new file mode 100644
index 0000000..7651b5c
--- /dev/null
+++ b/src/com/google/doclava/PackageInfo.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import com.sun.javadoc.*;
+import java.util.*;
+
+public class PackageInfo extends DocInfo implements ContainerInfo {
+  public static final String DEFAULT_PACKAGE = "default package";
+  
+  public static final Comparator<PackageInfo> comparator = new Comparator<PackageInfo>() {
+    public int compare(PackageInfo a, PackageInfo b) {
+      return a.name().compareTo(b.name());
+    }
+  };
+
+  public PackageInfo(PackageDoc pkg, String name, SourcePositionInfo position) {
+    super(pkg.getRawCommentText(), position);
+    if (name.isEmpty()) {
+      mName = DEFAULT_PACKAGE;
+    } else {
+      mName = name;
+    }
+
+    mPackage = pkg;
+  }
+  
+  public PackageInfo(String name) {
+    super("", null);
+    mName = name;
+  }
+  
+  public PackageInfo(String name, SourcePositionInfo position) {
+    super("", position);
+    
+    if (name.isEmpty()) {
+      mName = "default package";
+    } else {
+      mName = name;
+    }
+  }
+
+  public String htmlPage() {
+    String s = mName;
+    s = s.replace('.', '/');
+    s += "/package-summary.html";
+    s = Doclava.javadocDir + s;
+    return s;
+  }
+
+  public String fullDescriptionHtmlPage() {
+    String s = mName;
+    s = s.replace('.', '/');
+    s += "/package-descr.html";
+    s = Doclava.javadocDir + s;
+    return s;
+  }
+
+  @Override
+  public ContainerInfo parent() {
+    return null;
+  }
+
+  @Override
+  public boolean isHidden() {
+    return comment().isHidden();
+  }
+
+  public boolean checkLevel() {
+    // TODO should return false if all classes are hidden but the package isn't.
+    // We don't have this so I'm not doing it now.
+    return !isHidden();
+  }
+
+  public String name() {
+    return mName;
+  }
+
+  public String qualifiedName() {
+    return mName;
+  }
+
+  public TagInfo[] inlineTags() {
+    return comment().tags();
+  }
+
+  public TagInfo[] firstSentenceTags() {
+    return comment().briefTags();
+  }
+
+  public static ClassInfo[] filterHidden(ClassInfo[] classes) {
+    ArrayList<ClassInfo> out = new ArrayList<ClassInfo>();
+
+    for (ClassInfo cl : classes) {
+      if (!cl.isHidden()) {
+        out.add(cl);
+      }
+    }
+
+    return out.toArray(new ClassInfo[0]);
+  }
+
+  public void makeLink(Data data, String base) {
+    if (checkLevel()) {
+      data.setValue(base + ".link", htmlPage());
+    }
+    data.setValue(base + ".name", name());
+    data.setValue(base + ".since", getSince());
+  }
+
+  public void makeClassLinkListHDF(Data data, String base) {
+    makeLink(data, base);
+    ClassInfo.makeLinkListHDF(data, base + ".interfaces", interfaces());
+    ClassInfo.makeLinkListHDF(data, base + ".classes", ordinaryClasses());
+    ClassInfo.makeLinkListHDF(data, base + ".enums", enums());
+    ClassInfo.makeLinkListHDF(data, base + ".exceptions", exceptions());
+    ClassInfo.makeLinkListHDF(data, base + ".errors", errors());
+    data.setValue(base + ".since", getSince());
+  }
+
+  public ClassInfo[] interfaces() {
+    if (mInterfaces == null) {
+      mInterfaces =
+          ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.interfaces())));
+    }
+    return mInterfaces;
+  }
+
+  public ClassInfo[] ordinaryClasses() {
+    if (mOrdinaryClasses == null) {
+      mOrdinaryClasses =
+          ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.ordinaryClasses())));
+    }
+    return mOrdinaryClasses;
+  }
+
+  public ClassInfo[] enums() {
+    if (mEnums == null) {
+      mEnums = ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.enums())));
+    }
+    return mEnums;
+  }
+
+  public ClassInfo[] exceptions() {
+    if (mExceptions == null) {
+      mExceptions =
+          ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.exceptions())));
+    }
+    return mExceptions;
+  }
+
+  public ClassInfo[] errors() {
+    if (mErrors == null) {
+      mErrors = ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.errors())));
+    }
+    return mErrors;
+  }
+
+  // in hashed containers, treat the name as the key
+  @Override
+  public int hashCode() {
+    return mName.hashCode();
+  }
+
+  private String mName;
+  private PackageDoc mPackage;
+  private ClassInfo[] mInterfaces;
+  private ClassInfo[] mOrdinaryClasses;
+  private ClassInfo[] mEnums;
+  private ClassInfo[] mExceptions;
+  private ClassInfo[] mErrors;
+  
+  // TODO: Leftovers from ApiCheck that should be better merged.
+  private HashMap<String, ClassInfo> mClasses = new HashMap<String, ClassInfo>();
+  
+  public void addClass(ClassInfo cl) {
+    mClasses.put(cl.name(), cl);
+  }
+
+  public HashMap<String, ClassInfo> allClasses() {
+    return mClasses;
+  }
+  
+  public boolean isConsistent(PackageInfo pInfo) {
+    boolean consistent = true;
+    for (ClassInfo cInfo : mClasses.values()) {
+      if (pInfo.mClasses.containsKey(cInfo.name())) {
+        if (!cInfo.isConsistent(pInfo.mClasses.get(cInfo.name()))) {
+          consistent = false;
+        }
+      } else {
+        Errors.error(Errors.REMOVED_CLASS, cInfo.position(), "Removed public class "
+            + cInfo.qualifiedName());
+        consistent = false;
+      }
+    }
+    for (ClassInfo cInfo : pInfo.mClasses.values()) {
+      if (!mClasses.containsKey(cInfo.name())) {
+        Errors.error(Errors.ADDED_CLASS, cInfo.position(), "Added class " + cInfo.name()
+            + " to package " + pInfo.name());
+        consistent = false;
+      }
+    }
+    return consistent;
+  }
+}
diff --git a/src/com/google/doclava/ParamTagInfo.java b/src/com/google/doclava/ParamTagInfo.java
new file mode 100644
index 0000000..f8329bc
--- /dev/null
+++ b/src/com/google/doclava/ParamTagInfo.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+public class ParamTagInfo extends ParsedTagInfo {
+  static final Pattern PATTERN = Pattern.compile("([^ \t\r\n]+)[ \t\r\n]+(.*)", Pattern.DOTALL);
+
+  private boolean mIsTypeParameter;
+  private String mParameterComment;
+  private String mParameterName;
+
+  ParamTagInfo(String name, String kind, String text, ContainerInfo base, SourcePositionInfo sp) {
+    super(name, kind, text, base, sp);
+
+    Matcher m = PATTERN.matcher(text);
+    if (m.matches()) {
+      mParameterName = m.group(1);
+      mParameterComment = m.group(2);
+      int len = mParameterName.length();
+      mIsTypeParameter =
+          len > 2 && mParameterName.charAt(0) == '<' && mParameterName.charAt(len - 1) == '>';
+    } else {
+      mParameterName = text.trim();
+      mParameterComment = "";
+      mIsTypeParameter = false;
+    }
+    setCommentText(mParameterComment);
+  }
+
+  ParamTagInfo(String name, String kind, String text, boolean isTypeParameter,
+      String parameterComment, String parameterName, ContainerInfo base, SourcePositionInfo sp) {
+    super(name, kind, text, base, sp);
+    mIsTypeParameter = isTypeParameter;
+    mParameterComment = parameterComment;
+    mParameterName = parameterName;
+  }
+
+  public boolean isTypeParameter() {
+    return mIsTypeParameter;
+  }
+
+  public String parameterComment() {
+    return mParameterComment;
+  }
+
+  public String parameterName() {
+    return mParameterName;
+  }
+
+  @Override
+  public void makeHDF(Data data, String base) {
+    data.setValue(base + ".name", parameterName());
+    data.setValue(base + ".isTypeParameter", isTypeParameter() ? "1" : "0");
+    TagInfo.makeHDF(data, base + ".comment", commentTags());
+  }
+
+  public static void makeHDF(Data data, String base, ParamTagInfo[] tags) {
+    for (int i = 0; i < tags.length; i++) {
+      // don't output if the comment is ""
+      if (!"".equals(tags[i].parameterComment())) {
+        tags[i].makeHDF(data, base + "." + i);
+      }
+    }
+  }
+}
diff --git a/src/com/google/doclava/ParameterInfo.java b/src/com/google/doclava/ParameterInfo.java
new file mode 100644
index 0000000..f4e39f0
--- /dev/null
+++ b/src/com/google/doclava/ParameterInfo.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.util.HashSet;
+
+public class ParameterInfo {
+  public ParameterInfo(String name, String typeName, TypeInfo type, boolean isVarArg,
+      SourcePositionInfo position) {
+    mName = name;
+    mTypeName = typeName;
+    mType = type;
+    mIsVarArg = isVarArg;
+    mPosition = position;
+  }
+
+  TypeInfo type() {
+    return mType;
+  }
+
+  String name() {
+    return mName;
+  }
+
+  String typeName() {
+    return mTypeName;
+  }
+
+  SourcePositionInfo position() {
+    return mPosition;
+  }
+  
+  boolean isVarArg() {
+    return mIsVarArg;
+  }
+
+  public void makeHDF(Data data, String base, boolean isLastVararg, HashSet<String> typeVariables) {
+    data.setValue(base + ".name", this.name());
+    type().makeHDF(data, base + ".type", isLastVararg, typeVariables);
+  }
+
+  public static void makeHDF(Data data, String base, ParameterInfo[] params, boolean isVararg,
+      HashSet<String> typeVariables) {
+    for (int i = 0; i < params.length; i++) {
+      params[i].makeHDF(data, base + "." + i, isVararg && (i == params.length - 1), typeVariables);
+    }
+  }
+  
+  /**
+   * Returns true if this parameter's dimension information agrees
+   * with the represented callee's dimension information.
+   */
+  public boolean matchesDimension(String dimension, boolean varargs) {
+    if (varargs) {
+      dimension += "[]";
+    }
+    return mType.dimension().equals(dimension);
+  }
+
+  String mName;
+  String mTypeName;
+  TypeInfo mType;
+  boolean mIsVarArg;
+  SourcePositionInfo mPosition;
+}
diff --git a/src/com/google/doclava/ParsedTagInfo.java b/src/com/google/doclava/ParsedTagInfo.java
new file mode 100755
index 0000000..bcb9230
--- /dev/null
+++ b/src/com/google/doclava/ParsedTagInfo.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import java.util.ArrayList;
+
+public class ParsedTagInfo extends TagInfo {
+  private ContainerInfo mContainer;
+  private String mCommentText;
+  private Comment mComment;
+
+  ParsedTagInfo(String name, String kind, String text, ContainerInfo base, SourcePositionInfo sp) {
+    super(name, kind, text, SourcePositionInfo.findBeginning(sp, text));
+    mContainer = base;
+    mCommentText = text;
+  }
+
+  public TagInfo[] commentTags() {
+    if (mComment == null) {
+      mComment = new Comment(mCommentText, mContainer, position());
+    }
+    return mComment.tags();
+  }
+
+  protected void setCommentText(String comment) {
+    mCommentText = comment;
+  }
+
+  public static <T extends ParsedTagInfo> TagInfo[] joinTags(T[] tags) {
+    ArrayList<TagInfo> list = new ArrayList<TagInfo>();
+    final int N = tags.length;
+    for (int i = 0; i < N; i++) {
+      TagInfo[] t = tags[i].commentTags();
+      final int M = t.length;
+      for (int j = 0; j < M; j++) {
+        list.add(t[j]);
+      }
+    }
+    return list.toArray(new TagInfo[list.size()]);
+  }
+}
diff --git a/src/com/google/doclava/Proofread.java b/src/com/google/doclava/Proofread.java
new file mode 100644
index 0000000..64a0a1e
--- /dev/null
+++ b/src/com/google/doclava/Proofread.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import java.io.IOException;
+import java.io.FileWriter;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+public class Proofread {
+  static FileWriter out = null;
+  static final Pattern WHITESPACE = Pattern.compile("\\r?\\n");
+  static final String INDENT = "        ";
+  static final String NEWLINE = "\n" + INDENT;
+
+  public static void initProofread(String filename) {
+    try {
+      out = new FileWriter(filename);
+      out.write("javadoc proofread file: " + filename + "\n");
+    } catch (IOException e) {
+      if (out != null) {
+        try {
+          out.close();
+        } catch (IOException ex) {}
+        out = null;
+      }
+      System.err.println("error opening file: " + filename);
+    }
+  }
+
+  public static void finishProofread(String filename) {
+    if (out == null) {
+      return;
+    }
+
+    try {
+      out.close();
+    } catch (IOException e) {}
+  }
+
+  public static void write(String s) {
+    if (out == null) {
+      return;
+    }
+    try {
+      out.write(s);
+    } catch (IOException e) {}
+  }
+
+  public static void writeIndented(String s) {
+    s = s.trim();
+    Matcher m = WHITESPACE.matcher(s);
+    s = m.replaceAll(NEWLINE);
+    write(INDENT);
+    write(s);
+    write("\n");
+  }
+
+  public static void writeFileHeader(String filename) {
+    write("\n\n=== ");
+    write(filename);
+    write(" ===\n");
+  }
+
+  public static void writeTagList(TagInfo[] tags) {
+    if (out == null) {
+      return;
+    }
+
+    for (TagInfo t : tags) {
+      String k = t.kind();
+      if ("Text".equals(t.name())) {
+        writeIndented(t.text());
+      } else if ("@more".equals(k)) {
+        writeIndented("");
+      } else if ("@see".equals(k)) {
+        SeeTagInfo see = (SeeTagInfo) t;
+        String label = see.label();
+        if (label == null) {
+          label = "";
+        }
+        writeIndented("{" + see.name() + " ... " + label + "}");
+      } else if ("@code".equals(k)) {
+        writeIndented(t.text());
+      } else if ("@samplecode".equals(k)) {
+        writeIndented(t.text());
+      } else {
+        writeIndented("{" + (t.name() != null ? t.name() : "") + "/" + t.text() + "}");
+      }
+    }
+  }
+
+  public static void writePackages(String filename, TagInfo[] tags) {
+    if (out == null) {
+      return;
+    }
+
+    writeFileHeader(filename);
+    writeTagList(tags);
+  }
+
+  public static void writePackage(String filename, TagInfo[] tags) {
+    if (out == null) {
+      return;
+    }
+
+    writeFileHeader(filename);
+    writeTagList(tags);
+  }
+
+  public static void writeClass(String filename, ClassInfo cl) {
+    if (out == null) {
+      return;
+    }
+
+    writeFileHeader(filename);
+    writeTagList(cl.inlineTags());
+
+    // enum constants
+    for (FieldInfo f : cl.enumConstants()) {
+      write("ENUM: " + f.name() + "\n");
+      writeTagList(f.inlineTags());
+    }
+
+    // fields
+    for (FieldInfo f : cl.selfFields()) {
+      write("FIELD: " + f.name() + "\n");
+      writeTagList(f.inlineTags());
+    }
+
+    // constructors
+    for (MethodInfo m : cl.constructors()) {
+      write("CONSTRUCTOR: " + m.name() + "\n");
+      writeTagList(m.inlineTags().tags());
+    }
+
+    // methods
+    for (MethodInfo m : cl.selfMethods()) {
+      write("METHOD: " + m.name() + "\n");
+      writeTagList(m.inlineTags().tags());
+    }
+  }
+}
diff --git a/src/com/google/doclava/SampleCode.java b/src/com/google/doclava/SampleCode.java
new file mode 100644
index 0000000..91b1746
--- /dev/null
+++ b/src/com/google/doclava/SampleCode.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.util.*;
+import java.io.*;
+
+
+public class SampleCode {
+  String mSource;
+  String mDest;
+  String mTitle;
+
+  public SampleCode(String source, String dest, String title) {
+    mSource = source;
+    mTitle = title;
+    int len = dest.length();
+    if (len > 1 && dest.charAt(len - 1) != '/') {
+      mDest = dest + '/';
+    } else {
+      mDest = dest;
+    }
+  }
+
+  public void write(boolean offlineMode) {
+    File f = new File(mSource);
+    if (!f.isDirectory()) {
+      System.out.println("-samplecode not a directory: " + mSource);
+      return;
+    }
+    if (offlineMode)
+      writeIndexOnly(f, mDest, offlineMode);
+    else
+      writeDirectory(f, mDest);
+  }
+
+  public static String convertExtension(String s, String ext) {
+    return s.substring(0, s.lastIndexOf('.')) + ext;
+  }
+
+  public static String[] IMAGES = {".png", ".jpg", ".gif"};
+  public static String[] TEMPLATED = {".java", ".xml"};
+
+  public static boolean inList(String s, String[] list) {
+    for (String t : list) {
+      if (s.endsWith(t)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public void writeDirectory(File dir, String relative) {
+    TreeSet<String> dirs = new TreeSet<String>();
+    TreeSet<String> files = new TreeSet<String>();
+
+    String subdir = relative; // .substring(mDest.length());
+
+    for (File f : dir.listFiles()) {
+      String name = f.getName();
+      if (name.startsWith(".") || name.startsWith("_")) {
+        continue;
+      }
+      if (f.isFile()) {
+        String out = relative + name;
+
+        if (inList(out, IMAGES)) {
+          // copied directly
+          ClearPage.copyFile(f, out);
+          writeImagePage(f, convertExtension(out, Doclava.htmlExtension), subdir);
+          files.add(name);
+        }
+        if (inList(out, TEMPLATED)) {
+          // copied and goes through the template
+          ClearPage.copyFile(f, out);
+          writePage(f, convertExtension(out, Doclava.htmlExtension), subdir);
+          files.add(name);
+        }
+        // else ignored
+      } else if (f.isDirectory()) {
+        writeDirectory(f, relative + name + "/");
+        dirs.add(name);
+      }
+    }
+
+    // write the index page
+    int i;
+
+    Data hdf = writeIndex(dir);
+    hdf.setValue("subdir", subdir);
+    i = 0;
+    for (String d : dirs) {
+      hdf.setValue("subdirs." + i + ".name", d);
+      i++;
+    }
+    i = 0;
+    for (String f : files) {
+      hdf.setValue("files." + i + ".name", f);
+      hdf.setValue("files." + i + ".href", convertExtension(f, ".html"));
+      i++;
+    }
+
+    ClearPage.write(hdf, "sampleindex.cs", relative + "/index" + Doclava.htmlExtension);
+  }
+
+  public void writeIndexOnly(File dir, String relative, Boolean offline) {
+    Data hdf = writeIndex(dir);
+    if (!offline) relative = "/" + relative;
+    ClearPage.write(hdf, "sampleindex.cs", relative + "index" + Doclava.htmlExtension);
+  }
+
+  public Data writeIndex(File dir) {
+    Data hdf = Doclava.makeHDF();
+
+    hdf.setValue("page.title", dir.getName() + " - " + mTitle);
+    hdf.setValue("projectTitle", mTitle);
+
+    String filename = dir.getPath() + "/_index.html";
+    String summary =
+        SampleTagInfo.readFile(new SourcePositionInfo(filename, -1, -1), filename, "sample code",
+            true, false, true);
+
+    if (summary == null) {
+      summary = "";
+    }
+    hdf.setValue("summary", summary);
+
+    return hdf;
+  }
+
+  public void writePage(File f, String out, String subdir) {
+    String name = f.getName();
+
+    String filename = f.getPath();
+    String data =
+        SampleTagInfo.readFile(new SourcePositionInfo(filename, -1, -1), filename, "sample code",
+            true, true, true);
+    data = Doclava.escape(data);
+
+    Data hdf = Doclava.makeHDF();
+
+    hdf.setValue("page.title", name);
+    hdf.setValue("subdir", subdir);
+    hdf.setValue("realFile", name);
+    hdf.setValue("fileContents", data);
+
+    ClearPage.write(hdf, "sample.cs", out);
+  }
+
+  public void writeImagePage(File f, String out, String subdir) {
+    String name = f.getName();
+
+    String data = "<img src=\"" + name + "\" title=\"" + name + "\" />";
+
+    Data hdf = Doclava.makeHDF();
+
+    hdf.setValue("page.title", name);
+    hdf.setValue("subdir", subdir);
+    hdf.setValue("realFile", name);
+    hdf.setValue("fileContents", data);
+
+    ClearPage.write(hdf, "sample.cs", out);
+  }
+}
diff --git a/src/com/google/doclava/SampleTagInfo.java b/src/com/google/doclava/SampleTagInfo.java
new file mode 100644
index 0000000..9b9e40a
--- /dev/null
+++ b/src/com/google/doclava/SampleTagInfo.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.io.Reader;
+import java.io.IOException;
+import java.io.FileReader;
+import java.io.LineNumberReader;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/*
+ * SampleTagInfo copies text from a given file into the javadoc comment.
+ * 
+ * The @include tag copies the text verbatim from the given file.
+ * 
+ * The @sample tag copies the text from the given file, stripping leading and trailing whitespace,
+ * and reducing the indent level of the text to the indent level of the first non-whitespace line.
+ * 
+ * Both tags accept either a filename and an id or just a filename. If no id is provided, the entire
+ * file is copied. If an id is provided, the lines in the given file between the first two lines
+ * containing BEGIN_INCLUDE(id) and END_INCLUDE(id), for the given id, are copied. The id may be
+ * only letters, numbers and underscore (_).
+ * 
+ * Four examples: {@include samples/ApiDemos/src/com/google/app/Notification1.java} {@sample
+ * samples/ApiDemos/src/com/google/app/Notification1.java} {@include
+ * samples/ApiDemos/src/com/google/app/Notification1.java Bleh} {@sample
+ * samples/ApiDemos/src/com/google/app/Notification1.java Bleh}
+ */
+public class SampleTagInfo extends TagInfo {
+  static final int STATE_BEGIN = 0;
+  static final int STATE_MATCHING = 1;
+
+  static final Pattern TEXT =
+      Pattern.compile("[\r\n \t]*([^\r\n \t]*)[\r\n \t]*([0-9A-Za-z_]*)[\r\n \t]*", Pattern.DOTALL);
+
+  private static final String BEGIN_INCLUDE = "BEGIN_INCLUDE";
+  private static final String END_INCLUDE = "END_INCLUDE";
+
+  private ContainerInfo mBase;
+  private String mIncluded;
+
+  public static String escapeHtml(String str) {
+    return str.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
+  }
+
+  private static boolean isIncludeLine(String str) {
+    return str.indexOf(BEGIN_INCLUDE) >= 0 || str.indexOf(END_INCLUDE) >= 0;
+  }
+
+  SampleTagInfo(String name, String kind, String text, ContainerInfo base,
+      SourcePositionInfo position) {
+    super(name, kind, text, position);
+    mBase = base;
+
+    Matcher m = TEXT.matcher(text);
+    if (!m.matches()) {
+      Errors.error(Errors.BAD_INCLUDE_TAG, position, "Bad @include tag: " + text);
+      return;
+    }
+    String filename = m.group(1);
+    String id = m.group(2);
+    boolean trim = "@sample".equals(name);
+
+    if (id == null || "".equals(id)) {
+      mIncluded = readFile(position, filename, id, trim, true, false);
+    } else {
+      mIncluded = loadInclude(position, filename, id, trim);
+    }
+
+    if (mIncluded == null) {
+      Errors.error(Errors.BAD_INCLUDE_TAG, position, "include tag '" + id + "' not found in file: "
+          + filename);
+    }
+  }
+
+  static String getTrimString(String line) {
+    int i = 0;
+    int len = line.length();
+    for (; i < len; i++) {
+      char c = line.charAt(i);
+      if (c != ' ' && c != '\t') {
+        break;
+      }
+    }
+    if (i == len) {
+      return null;
+    } else {
+      return line.substring(0, i);
+    }
+  }
+
+  static String loadInclude(SourcePositionInfo pos, String filename, String id, boolean trim) {
+    Reader input = null;
+    StringBuilder result = new StringBuilder();
+
+    String begin = BEGIN_INCLUDE + "(" + id + ")";
+    String end = END_INCLUDE + "(" + id + ")";
+
+    try {
+      input = new FileReader(filename);
+      LineNumberReader lines = new LineNumberReader(input);
+
+      int state = STATE_BEGIN;
+
+      int trimLength = -1;
+      String trimString = null;
+      int trailing = 0;
+
+      while (true) {
+        String line = lines.readLine();
+        if (line == null) {
+          return null;
+        }
+        switch (state) {
+          case STATE_BEGIN:
+            if (line.indexOf(begin) >= 0) {
+              state = STATE_MATCHING;
+            }
+            break;
+          case STATE_MATCHING:
+            if (line.indexOf(end) >= 0) {
+              return result.substring(0);
+            } else {
+              boolean empty = "".equals(line.trim());
+              if (trim) {
+                if (isIncludeLine(line)) {
+                  continue;
+                }
+                if (trimLength < 0 && !empty) {
+                  trimString = getTrimString(line);
+                  if (trimString != null) {
+                    trimLength = trimString.length();
+                  }
+                }
+                if (trimLength >= 0 && line.length() > trimLength) {
+                  boolean trimThisLine = true;
+                  for (int i = 0; i < trimLength; i++) {
+                    if (line.charAt(i) != trimString.charAt(i)) {
+                      trimThisLine = false;
+                      break;
+                    }
+                  }
+                  if (trimThisLine) {
+                    line = line.substring(trimLength);
+                  }
+                }
+                if (trimLength >= 0) {
+                  if (!empty) {
+                    for (int i = 0; i < trailing; i++) {
+                      result.append('\n');
+                    }
+                    line = escapeHtml(line);
+                    result.append(line);
+                    trailing = 1; // add \n next time, maybe
+                  } else {
+                    trailing++;
+                  }
+                }
+              } else {
+                result.append(line);
+                result.append('\n');
+              }
+            }
+            break;
+        }
+      }
+    } catch (IOException e) {
+      Errors.error(Errors.BAD_INCLUDE_TAG, pos, "Error reading file for" + " include \"" + id
+          + "\" " + filename);
+    } finally {
+      if (input != null) {
+        try {
+          input.close();
+        } catch (IOException ex) {}
+      }
+    }
+    Errors.error(Errors.BAD_INCLUDE_TAG, pos, "Did not find " + end + " in file " + filename);
+    return null;
+  }
+
+  static String readFile(SourcePositionInfo pos, String filename, String id, boolean trim,
+      boolean escape, boolean errorOk) {
+    Reader input = null;
+    StringBuilder result = new StringBuilder();
+    int trailing = 0;
+    boolean started = false;
+    try {
+      input = new FileReader(filename);
+      LineNumberReader lines = new LineNumberReader(input);
+
+      while (true) {
+        String line = lines.readLine();
+        if (line == null) {
+          break;
+        }
+        if (trim) {
+          if (isIncludeLine(line)) {
+            continue;
+          }
+          if (!"".equals(line.trim())) {
+            if (started) {
+              for (int i = 0; i < trailing; i++) {
+                result.append('\n');
+              }
+            }
+            if (escape) {
+              line = escapeHtml(line);
+            }
+            result.append(line);
+            trailing = 1; // add \n next time, maybe
+            started = true;
+          } else {
+            if (started) {
+              trailing++;
+            }
+          }
+        } else {
+          result.append(line);
+          result.append('\n');
+        }
+      }
+    } catch (IOException e) {
+      if (errorOk) {
+        return null;
+      } else {
+        Errors.error(Errors.BAD_INCLUDE_TAG, pos, "Error reading file for" + " include \"" + id
+            + "\" " + filename);
+      }
+    } finally {
+      if (input != null) {
+        try {
+          input.close();
+        } catch (IOException ex) {}
+      }
+    }
+    return result.substring(0);
+  }
+
+  @Override
+  public void makeHDF(Data data, String base) {
+    data.setValue(base + ".name", name());
+    data.setValue(base + ".kind", kind());
+    if (mIncluded != null) {
+      data.setValue(base + ".text", mIncluded);
+    } else {
+      data.setValue(base + ".text", "INCLUDE_ERROR");
+    }
+  }
+}
diff --git a/src/com/google/doclava/Scoped.java b/src/com/google/doclava/Scoped.java
new file mode 100644
index 0000000..03e42f9
--- /dev/null
+++ b/src/com/google/doclava/Scoped.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+public interface Scoped {
+  boolean isPublic();
+
+  boolean isProtected();
+
+  boolean isPackagePrivate();
+
+  boolean isPrivate();
+
+  boolean isHidden();
+}
diff --git a/src/com/google/doclava/SeeTagInfo.java b/src/com/google/doclava/SeeTagInfo.java
new file mode 100644
index 0000000..40581cd
--- /dev/null
+++ b/src/com/google/doclava/SeeTagInfo.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+public class SeeTagInfo extends TagInfo {
+  private ContainerInfo mBase;
+  LinkReference mLink;
+
+  SeeTagInfo(String name, String kind, String text, ContainerInfo base, SourcePositionInfo position) {
+    super(name, kind, text, position);
+    mBase = base;
+  }
+
+  protected LinkReference linkReference() {
+    if (mLink == null) {
+      mLink =
+          LinkReference.parse(text(), mBase, position(), (!"@see".equals(name()))
+              && (mBase != null ? mBase.checkLevel() : true));
+    }
+    return mLink;
+  }
+
+  public String label() {
+    return linkReference().label;
+  }
+
+  @Override
+  public void makeHDF(Data data, String base) {
+    LinkReference linkRef = linkReference();
+    if (linkRef.kind != null) {
+      // if they have a better suggestion about "kind" use that.
+      // do this before super.makeHDF() so it picks it up
+      setKind(linkRef.kind);
+    }
+
+    super.makeHDF(data, base);
+
+    data.setValue(base + ".label", linkRef.label);
+    if (linkRef.href != null) {
+      data.setValue(base + ".href", linkRef.href);
+    }
+  }
+
+  public boolean checkLevel() {
+    return linkReference().checkLevel();
+  }
+
+  public static void makeHDF(Data data, String base, SeeTagInfo[] tags) {
+    int j = 0;
+    for (SeeTagInfo tag : tags) {
+      if (tag.mBase.checkLevel() && tag.checkLevel()) {
+        tag.makeHDF(data, base + "." + j);
+        j++;
+      }
+    }
+  }
+}
diff --git a/src/com/google/doclava/SinceTagger.java b/src/com/google/doclava/SinceTagger.java
new file mode 100644
index 0000000..00e2029
--- /dev/null
+++ b/src/com/google/doclava/SinceTagger.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+import com.google.doclava.apicheck.ApiCheck;
+import com.google.doclava.apicheck.ApiInfo;
+import com.google.doclava.apicheck.ApiParseException;
+
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Collections;
+
+
+/**
+ * Applies version information to the DroidDoc class model from apicheck XML files. Sample usage:
+ * 
+ * <pre>
+ *   ClassInfo[] classInfos = ...
+ *
+ *   SinceTagger sinceTagger = new SinceTagger()
+ *   sinceTagger.addVersion("frameworks/base/api/1.xml", "Android 1.0")
+ *   sinceTagger.addVersion("frameworks/base/api/2.xml", "Android 1.5")
+ *   sinceTagger.tagAll(...);
+ * </pre>
+ */
+public class SinceTagger {
+
+  private final Map<String, String> xmlToName = new LinkedHashMap<String, String>();
+
+  /**
+   * Specifies the apicheck XML file and the API version it holds. Calls to this method should be
+   * called in order from oldest version to newest.
+   */
+  public void addVersion(String file, String name) {
+    xmlToName.put(file, name);
+  }
+
+  public void tagAll(ClassInfo[] classDocs) {
+    // read through the XML files in order, applying their since information
+    // to the Javadoc models
+    for (Map.Entry<String, String> versionSpec : xmlToName.entrySet()) {
+      String xmlFile = versionSpec.getKey();
+      String versionName = versionSpec.getValue();
+      
+      ApiInfo specApi;
+      try {
+        specApi = new ApiCheck().parseApi(xmlFile);
+      } catch (ApiParseException e) {
+        Errors.error(Errors.NO_SINCE_DATA, null, "Could not add since data for " + versionName);
+        continue;
+      }
+
+      applyVersionsFromSpec(versionName, specApi, classDocs);
+    }
+
+    if (!xmlToName.isEmpty()) {
+      warnForMissingVersions(classDocs);
+    }
+  }
+
+  public boolean hasVersions() {
+    return !xmlToName.isEmpty();
+  }
+
+  /**
+   * Writes an index of the version names to {@code data}.
+   */
+  public void writeVersionNames(Data data) {
+    int index = 1;
+    for (String version : xmlToName.values()) {
+      data.setValue("since." + index + ".name", version);
+      index++;
+    }
+  }
+
+  /**
+   * Applies the version information to {@code classDocs} where not already present.
+   * 
+   * @param versionName the version name
+   * @param specApi the spec for this version. If a symbol is in this spec, it was present in the
+   *        named version
+   * @param classDocs the doc model to update
+   */
+  private void applyVersionsFromSpec(String versionName, ApiInfo specApi, ClassInfo[] classDocs) {
+    for (ClassInfo classDoc : classDocs) {
+      PackageInfo packageSpec
+          = specApi.getPackages().get(classDoc.containingPackage().name());
+
+      if (packageSpec == null) {
+        continue;
+      }
+
+      ClassInfo classSpec = packageSpec.allClasses().get(classDoc.name());
+
+      if (classSpec == null) {
+        continue;
+      }
+
+      versionPackage(versionName, classDoc.containingPackage());
+      versionClass(versionName, classDoc);
+      versionConstructors(versionName, classSpec, classDoc);
+      versionFields(versionName, classSpec, classDoc);
+      versionMethods(versionName, classSpec, classDoc);
+    }
+  }
+
+  /**
+   * Applies version information to {@code doc} where not already present.
+   */
+  private void versionPackage(String versionName, PackageInfo doc) {
+    if (doc.getSince() == null) {
+      doc.setSince(versionName);
+    }
+  }
+
+  /**
+   * Applies version information to {@code doc} where not already present.
+   */
+  private void versionClass(String versionName, ClassInfo doc) {
+    if (doc.getSince() == null) {
+      doc.setSince(versionName);
+    }
+  }
+
+  /**
+   * Applies version information from {@code spec} to {@code doc} where not already present.
+   */
+  private void versionConstructors(String versionName, ClassInfo spec, ClassInfo doc) {
+    for (MethodInfo constructor : doc.constructors()) {
+      if (constructor.getSince() == null
+          && spec.hasConstructor(constructor)) {
+        constructor.setSince(versionName);
+      }
+    }
+  }
+
+  /**
+   * Applies version information from {@code spec} to {@code doc} where not already present.
+   */
+  private void versionFields(String versionName, ClassInfo spec, ClassInfo doc) {
+    for (FieldInfo field : doc.fields()) {
+      if (field.getSince() == null && spec.allFields().containsKey(field.name())) {
+        field.setSince(versionName);
+      }
+    }
+  }
+
+  /**
+   * Applies version information from {@code spec} to {@code doc} where not already present.
+   */
+  private void versionMethods(String versionName, ClassInfo spec, ClassInfo doc) {
+    for (MethodInfo method : doc.methods()) {
+      if (method.getSince() != null) {
+        continue;
+      }
+
+      for (ClassInfo superclass : spec.hierarchy()) {
+        if (superclass.allMethods().containsKey(method.getHashableName())) {
+          method.setSince(versionName);
+          break;
+        }
+      }
+    }
+  }
+
+  /**
+   * Warns if any symbols are missing version information. When configured properly, this will yield
+   * zero warnings because {@code apicheck} guarantees that all symbols are present in the most
+   * recent API.
+   */
+  private void warnForMissingVersions(ClassInfo[] classDocs) {
+    for (ClassInfo claz : classDocs) {
+      if (!checkLevelRecursive(claz)) {
+        continue;
+      }
+
+      if (claz.getSince() == null) {
+        Errors.error(Errors.NO_SINCE_DATA, claz.position(), "XML missing class "
+            + claz.qualifiedName());
+      }
+
+      for (FieldInfo field : missingVersions(claz.fields())) {
+        Errors.error(Errors.NO_SINCE_DATA, field.position(), "XML missing field "
+            + claz.qualifiedName() + "#" + field.name());
+      }
+
+      for (MethodInfo constructor : missingVersions(claz.constructors())) {
+        Errors.error(Errors.NO_SINCE_DATA, constructor.position(), "XML missing constructor "
+            + claz.qualifiedName() + "#" + constructor.getHashableName());
+      }
+
+      for (MethodInfo method : missingVersions(claz.methods())) {
+        Errors.error(Errors.NO_SINCE_DATA, method.position(), "XML missing method "
+            + claz.qualifiedName() + "#" + method.getHashableName());
+      }
+    }
+  }
+
+  /**
+   * Returns the DocInfos in {@code all} that are documented but do not have since tags.
+   */
+  private <T extends MemberInfo> Iterable<T> missingVersions(T[] all) {
+    List<T> result = Collections.emptyList();
+    for (T t : all) {
+      // if this member has version info or isn't documented, skip it
+      if (t.getSince() != null || t.isHidden() || !checkLevelRecursive(t.realContainingClass())) {
+        continue;
+      }
+
+      if (result.isEmpty()) {
+        result = new ArrayList<T>(); // lazily construct a mutable list
+      }
+      result.add(t);
+    }
+    return result;
+  }
+
+  /**
+   * Returns true if {@code claz} and all containing classes are documented. The result may be used
+   * to filter out members that exist in the API data structure but aren't a part of the API.
+   */
+  private boolean checkLevelRecursive(ClassInfo claz) {
+    for (ClassInfo c = claz; c != null; c = c.containingClass()) {
+      if (!c.checkLevel()) {
+        return false;
+      }
+    }
+    return true;
+  }
+}
diff --git a/src/com/google/doclava/Sorter.java b/src/com/google/doclava/Sorter.java
new file mode 100644
index 0000000..2ee8f67
--- /dev/null
+++ b/src/com/google/doclava/Sorter.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+public class Sorter implements Comparable {
+  public String label;
+  public Object data;
+
+  public Sorter(String l, Object d) {
+    label = l;
+    data = d;
+  }
+
+  public int compareTo(Object other) {
+    return label.compareToIgnoreCase(((Sorter) other).label);
+  }
+}
diff --git a/src/com/google/doclava/SourcePositionInfo.java b/src/com/google/doclava/SourcePositionInfo.java
new file mode 100644
index 0000000..cf516c8
--- /dev/null
+++ b/src/com/google/doclava/SourcePositionInfo.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+public class SourcePositionInfo implements Comparable {
+  public static final SourcePositionInfo UNKNOWN = new SourcePositionInfo("(unknown)", 0, 0);
+
+  public SourcePositionInfo(String file, int line, int column) {
+    this.file = file;
+    this.line = line;
+    this.column = column;
+  }
+
+  public SourcePositionInfo(SourcePositionInfo that) {
+    this.file = that.file;
+    this.line = that.line;
+    this.column = that.column;
+  }
+
+  /**
+   * Given this position and str which occurs at that position, as well as str an index into str,
+   * find the SourcePositionInfo.
+   * 
+   * @throw StringIndexOutOfBoundsException if index &gt; str.length()
+   */
+  public static SourcePositionInfo add(SourcePositionInfo that, String str, int index) {
+    if (that == null) {
+      return null;
+    }
+    int line = that.line;
+    char prev = 0;
+    for (int i = 0; i < index; i++) {
+      char c = str.charAt(i);
+      if (c == '\r' || (c == '\n' && prev != '\r')) {
+        line++;
+      }
+      prev = c;
+    }
+    return new SourcePositionInfo(that.file, line, 0);
+  }
+
+  public static SourcePositionInfo findBeginning(SourcePositionInfo that, String str) {
+    if (that == null) {
+      return null;
+    }
+    int line = that.line - 1; // -1 because, well, it seems to work
+    int prev = 0;
+    for (int i = str.length() - 1; i >= 0; i--) {
+      char c = str.charAt(i);
+      if ((c == '\r' && prev != '\n') || (c == '\n')) {
+        line--;
+      }
+      prev = c;
+    }
+    return new SourcePositionInfo(that.file, line, 0);
+  }
+
+  @Override
+  public String toString() {
+    return file + ':' + line;
+  }
+
+  public int compareTo(Object o) {
+    SourcePositionInfo that = (SourcePositionInfo) o;
+    int r = this.file.compareTo(that.file);
+    if (r != 0) return r;
+    return this.line - that.line;
+  }
+  
+  /**
+   * Build a SourcePositionInfo from the XML source= notation
+   */
+  public static SourcePositionInfo fromXml(String source) {
+    if (source != null) {
+      for (int i = 0; i < source.length(); i++) {
+        if (source.charAt(i) == ':') {
+          return new SourcePositionInfo(source.substring(0, i), Integer.parseInt(source
+              .substring(i + 1)), 0);
+        }
+      }
+    }
+
+    return UNKNOWN;
+  }
+
+  public String file;
+  public int line;
+  public int column;
+}
diff --git a/src/com/google/doclava/Stubs.java b/src/com/google/doclava/Stubs.java
new file mode 100644
index 0000000..1fb67e8
--- /dev/null
+++ b/src/com/google/doclava/Stubs.java
@@ -0,0 +1,948 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Set;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+
+public class Stubs {
+  private static HashSet<ClassInfo> notStrippable;
+
+  public static void writeStubsAndXml(String stubsDir, String xmlFile,
+      HashSet<String> stubPackages) {
+    // figure out which classes we need
+    notStrippable = new HashSet<ClassInfo>();
+    ClassInfo[] all = Converter.allClasses();
+    PrintStream xmlWriter = null;
+    if (xmlFile != null) {
+      try {
+        File xml = new File(xmlFile);
+        xml.getParentFile().mkdirs();
+        xmlWriter = new PrintStream(xml);
+      } catch (FileNotFoundException e) {
+        Errors.error(Errors.IO_ERROR, new SourcePositionInfo(xmlFile, 0, 0),
+            "Cannot open file for write.");
+      }
+    }
+    // If a class is public or protected, not hidden, and marked as included,
+    // then we can't strip it
+    for (ClassInfo cl : all) {
+      if (cl.checkLevel() && cl.isIncluded()) {
+        cantStripThis(cl, notStrippable, "0:0");
+      }
+    }
+
+    // complain about anything that looks includeable but is not supposed to
+    // be written, e.g. hidden things
+    for (ClassInfo cl : notStrippable) {
+      if (!cl.isHidden()) {
+        MethodInfo[] methods = cl.selfMethods();
+        for (MethodInfo m : methods) {
+          if (m.isHidden()) {
+            Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Reference to hidden method "
+                + m.name());
+          } else if (m.isDeprecated()) {
+            // don't bother reporting deprecated methods
+            // unless they are public
+            Errors.error(Errors.DEPRECATED, m.position(), "Method " + cl.qualifiedName() + "."
+                + m.name() + " is deprecated");
+          }
+
+          ClassInfo returnClass = m.returnType().asClassInfo();
+          if (returnClass != null && returnClass.isHidden()) {
+            Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Method " + cl.qualifiedName()
+                + "." + m.name() + " returns unavailable type " + returnClass.name());
+          }
+
+          ParameterInfo[] params = m.parameters();
+          for (ParameterInfo p : params) {
+            TypeInfo t = p.type();
+            if (!t.isPrimitive()) {
+              if (t.asClassInfo().isHidden()) {
+                Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Parameter of hidden type "
+                    + t.fullName() + " in " + cl.qualifiedName() + "." + m.name() + "()");
+              }
+            }
+          }
+        }
+
+        // annotations are handled like methods
+        methods = cl.annotationElements();
+        for (MethodInfo m : methods) {
+          if (m.isHidden()) {
+            Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Reference to hidden annotation "
+                + m.name());
+          }
+
+          ClassInfo returnClass = m.returnType().asClassInfo();
+          if (returnClass != null && returnClass.isHidden()) {
+            Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Annotation '" + m.name()
+                + "' returns unavailable type " + returnClass.name());
+          }
+
+          ParameterInfo[] params = m.parameters();
+          for (ParameterInfo p : params) {
+            TypeInfo t = p.type();
+            if (!t.isPrimitive()) {
+              if (t.asClassInfo().isHidden()) {
+                Errors.error(Errors.UNAVAILABLE_SYMBOL, p.position(),
+                    "Reference to unavailable annotation class " + t.fullName());
+              }
+            }
+          }
+        }
+      } else if (cl.isDeprecated()) {
+        // not hidden, but deprecated
+        Errors.error(Errors.DEPRECATED, cl.position(), "Class " + cl.qualifiedName()
+            + " is deprecated");
+      }
+    }
+
+    HashMap<PackageInfo, List<ClassInfo>> packages = new HashMap<PackageInfo, List<ClassInfo>>();
+    for (ClassInfo cl : notStrippable) {
+      if (!cl.isDocOnly()) {
+        if (stubPackages == null || stubPackages.contains(cl.containingPackage().name())) {
+          // write out the stubs
+          if (stubsDir != null) {
+            writeClassFile(stubsDir, cl);
+          }
+          // build class list for xml file
+          if (xmlWriter != null) {
+            if (packages.containsKey(cl.containingPackage())) {
+              packages.get(cl.containingPackage()).add(cl);
+            } else {
+              ArrayList<ClassInfo> classes = new ArrayList<ClassInfo>();
+              classes.add(cl);
+              packages.put(cl.containingPackage(), classes);
+            }
+          }
+        }
+      }
+    }
+
+    // write out the XML
+    if (xmlWriter != null) {
+      writeXML(xmlWriter, packages, notStrippable);
+      xmlWriter.close();
+    }
+  }
+
+  public static void cantStripThis(ClassInfo cl, HashSet<ClassInfo> notStrippable, String why) {
+
+    if (!notStrippable.add(cl)) {
+      // slight optimization: if it already contains cl, it already contains
+      // all of cl's parents
+      return;
+    }
+    cl.setReasonIncluded(why);
+
+    // cant strip annotations
+    /*
+     * if (cl.annotations() != null){ for (AnnotationInstanceInfo ai : cl.annotations()){ if
+     * (ai.type() != null){ cantStripThis(ai.type(), notStrippable, "1:" + cl.qualifiedName()); } }
+     * }
+     */
+    // cant strip any public fields or their generics
+    if (cl.allSelfFields() != null) {
+      for (FieldInfo fInfo : cl.allSelfFields()) {
+        if (fInfo.type() != null) {
+          if (fInfo.type().asClassInfo() != null) {
+            cantStripThis(fInfo.type().asClassInfo(), notStrippable, "2:" + cl.qualifiedName());
+          }
+          if (fInfo.type().typeArguments() != null) {
+            for (TypeInfo tTypeInfo : fInfo.type().typeArguments()) {
+              if (tTypeInfo.asClassInfo() != null) {
+                cantStripThis(tTypeInfo.asClassInfo(), notStrippable, "3:" + cl.qualifiedName());
+              }
+            }
+          }
+        }
+      }
+    }
+    // cant strip any of the type's generics
+    if (cl.asTypeInfo() != null) {
+      if (cl.asTypeInfo().typeArguments() != null) {
+        for (TypeInfo tInfo : cl.asTypeInfo().typeArguments()) {
+          if (tInfo.asClassInfo() != null) {
+            cantStripThis(tInfo.asClassInfo(), notStrippable, "4:" + cl.qualifiedName());
+          }
+        }
+      }
+    }
+    // cant strip any of the annotation elements
+    // cantStripThis(cl.annotationElements(), notStrippable);
+    // take care of methods
+    cantStripThis(cl.allSelfMethods(), notStrippable);
+    cantStripThis(cl.allConstructors(), notStrippable);
+    // blow the outer class open if this is an inner class
+    if (cl.containingClass() != null) {
+      cantStripThis(cl.containingClass(), notStrippable, "5:" + cl.qualifiedName());
+    }
+    // blow open super class and interfaces
+    ClassInfo supr = cl.realSuperclass();
+    if (supr != null) {
+      if (supr.isHidden()) {
+        // cl is a public class declared as extending a hidden superclass.
+        // this is not a desired practice but it's happened, so we deal
+        // with it by stripping off the superclass relation for purposes of
+        // generating the doc & stub information, and proceeding normally.
+        cl.init(cl.asTypeInfo(), cl.realInterfaces(), cl.realInterfaceTypes(), cl.innerClasses(),
+            cl.allConstructors(), cl.allSelfMethods(), cl.annotationElements(), cl.allSelfFields(),
+            cl.enumConstants(), cl.containingPackage(), cl.containingClass(), null, null, cl
+                .annotations());
+        Errors.error(Errors.HIDDEN_SUPERCLASS, cl.position(), "Public class " + cl.qualifiedName()
+            + " stripped of unavailable superclass " + supr.qualifiedName());
+      } else {
+        cantStripThis(supr, notStrippable, "6:" + cl.realSuperclass().name() + cl.qualifiedName());
+      }
+    }
+  }
+
+  private static void cantStripThis(MethodInfo[] mInfos, HashSet<ClassInfo> notStrippable) {
+    // for each method, blow open the parameters, throws and return types. also blow open their
+    // generics
+    if (mInfos != null) {
+      for (MethodInfo mInfo : mInfos) {
+        if (mInfo.getTypeParameters() != null) {
+          for (TypeInfo tInfo : mInfo.getTypeParameters()) {
+            if (tInfo.asClassInfo() != null) {
+              cantStripThis(tInfo.asClassInfo(), notStrippable, "8:"
+                  + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name());
+            }
+          }
+        }
+        if (mInfo.parameters() != null) {
+          for (ParameterInfo pInfo : mInfo.parameters()) {
+            if (pInfo.type() != null && pInfo.type().asClassInfo() != null) {
+              cantStripThis(pInfo.type().asClassInfo(), notStrippable, "9:"
+                  + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name());
+              if (pInfo.type().typeArguments() != null) {
+                for (TypeInfo tInfoType : pInfo.type().typeArguments()) {
+                  if (tInfoType.asClassInfo() != null) {
+                    ClassInfo tcl = tInfoType.asClassInfo();
+                    if (tcl.isHidden()) {
+                      Errors
+                          .error(Errors.UNAVAILABLE_SYMBOL, mInfo.position(),
+                              "Parameter of hidden type " + tInfoType.fullName() + " in "
+                                  + mInfo.containingClass().qualifiedName() + '.' + mInfo.name()
+                                  + "()");
+                    } else {
+                      cantStripThis(tcl, notStrippable, "10:"
+                          + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name());
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+        for (ClassInfo thrown : mInfo.thrownExceptions()) {
+          cantStripThis(thrown, notStrippable, "11:" + mInfo.realContainingClass().qualifiedName()
+              + ":" + mInfo.name());
+        }
+        if (mInfo.returnType() != null && mInfo.returnType().asClassInfo() != null) {
+          cantStripThis(mInfo.returnType().asClassInfo(), notStrippable, "12:"
+              + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name());
+          if (mInfo.returnType().typeArguments() != null) {
+            for (TypeInfo tyInfo : mInfo.returnType().typeArguments()) {
+              if (tyInfo.asClassInfo() != null) {
+                cantStripThis(tyInfo.asClassInfo(), notStrippable, "13:"
+                    + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name());
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  static String javaFileName(ClassInfo cl) {
+    String dir = "";
+    PackageInfo pkg = cl.containingPackage();
+    if (pkg != null) {
+      dir = pkg.name();
+      dir = dir.replace('.', '/') + '/';
+    }
+    return dir + cl.name() + ".java";
+  }
+
+  static void writeClassFile(String stubsDir, ClassInfo cl) {
+    // inner classes are written by their containing class
+    if (cl.containingClass() != null) {
+      return;
+    }
+
+    // Work around the bogus "Array" class we invent for
+    // Arrays.copyOf's Class<? extends T[]> newType parameter. (http://b/2715505)
+    if (cl.containingPackage() != null
+        && cl.containingPackage().name().equals(PackageInfo.DEFAULT_PACKAGE)) {
+      return;
+    }
+
+    String filename = stubsDir + '/' + javaFileName(cl);
+    File file = new File(filename);
+    ClearPage.ensureDirectory(file);
+
+    PrintStream stream = null;
+    try {
+      stream = new PrintStream(file);
+      writeClassFile(stream, cl);
+    } catch (FileNotFoundException e) {
+      System.err.println("error writing file: " + filename);
+    } finally {
+      if (stream != null) {
+        stream.close();
+      }
+    }
+  }
+
+  static void writeClassFile(PrintStream stream, ClassInfo cl) {
+    PackageInfo pkg = cl.containingPackage();
+    if (pkg != null) {
+      stream.println("package " + pkg.name() + ";");
+    }
+    writeClass(stream, cl);
+  }
+
+  static void writeClass(PrintStream stream, ClassInfo cl) {
+    writeAnnotations(stream, cl.annotations());
+
+    stream.print(cl.scope() + " ");
+    if (cl.isAbstract() && !cl.isAnnotation() && !cl.isInterface()) {
+      stream.print("abstract ");
+    }
+    if (cl.isStatic()) {
+      stream.print("static ");
+    }
+    if (cl.isFinal() && !cl.isEnum()) {
+      stream.print("final ");
+    }
+    if (false) {
+      stream.print("strictfp ");
+    }
+
+    HashSet<String> classDeclTypeVars = new HashSet();
+    String leafName = cl.asTypeInfo().fullName(classDeclTypeVars);
+    int bracket = leafName.indexOf('<');
+    if (bracket < 0) bracket = leafName.length() - 1;
+    int period = leafName.lastIndexOf('.', bracket);
+    if (period < 0) period = -1;
+    leafName = leafName.substring(period + 1);
+
+    String kind = cl.kind();
+    stream.println(kind + " " + leafName);
+
+    TypeInfo base = cl.superclassType();
+
+    if (!"enum".equals(kind)) {
+      if (base != null && !"java.lang.Object".equals(base.qualifiedTypeName())) {
+        stream.println("  extends " + base.fullName(classDeclTypeVars));
+      }
+    }
+
+    TypeInfo[] interfaces = cl.realInterfaceTypes();
+    List<TypeInfo> usedInterfaces = new ArrayList<TypeInfo>();
+    for (TypeInfo iface : interfaces) {
+      if (notStrippable.contains(iface.asClassInfo()) && !iface.asClassInfo().isDocOnly()) {
+        usedInterfaces.add(iface);
+      }
+    }
+    if (usedInterfaces.size() > 0 && !cl.isAnnotation()) {
+      // can java annotations extend other ones?
+      if (cl.isInterface() || cl.isAnnotation()) {
+        stream.print("  extends ");
+      } else {
+        stream.print("  implements ");
+      }
+      String comma = "";
+      for (TypeInfo iface : usedInterfaces) {
+        stream.print(comma + iface.fullName(classDeclTypeVars));
+        comma = ", ";
+      }
+      stream.println();
+    }
+
+    stream.println("{");
+
+    FieldInfo[] enumConstants = cl.enumConstants();
+    int N = enumConstants.length;
+    for (int i = 0; i < N; i++) {
+      FieldInfo field = enumConstants[i];
+      if (!field.constantLiteralValue().equals("null")) {
+        stream.println(field.name() + "(" + field.constantLiteralValue()
+            + (i == N - 1 ? ");" : "),"));
+      } else {
+        stream.println(field.name() + "(" + (i == N - 1 ? ");" : "),"));
+      }
+    }
+
+    for (ClassInfo inner : cl.getRealInnerClasses()) {
+      if (notStrippable.contains(inner) && !inner.isDocOnly()) {
+        writeClass(stream, inner);
+      }
+    }
+
+
+    for (MethodInfo method : cl.constructors()) {
+      if (!method.isDocOnly()) {
+        writeMethod(stream, method, true);
+      }
+    }
+
+    boolean fieldNeedsInitialization = false;
+    boolean staticFieldNeedsInitialization = false;
+    for (FieldInfo field : cl.allSelfFields()) {
+      if (!field.isDocOnly()) {
+        if (!field.isStatic() && field.isFinal() && !fieldIsInitialized(field)) {
+          fieldNeedsInitialization = true;
+        }
+        if (field.isStatic() && field.isFinal() && !fieldIsInitialized(field)) {
+          staticFieldNeedsInitialization = true;
+        }
+      }
+    }
+
+    // The compiler includes a default public constructor that calls the super classes
+    // default constructor in the case where there are no written constructors.
+    // So, if we hide all the constructors, java may put in a constructor
+    // that calls a nonexistent super class constructor. So, if there are no constructors,
+    // and the super class doesn't have a default constructor, write in a private constructor
+    // that works. TODO -- we generate this as protected, but we really should generate
+    // it as private unless it also exists in the real code.
+    if ((cl.constructors().length == 0 && (cl.getNonWrittenConstructors().length != 0 || fieldNeedsInitialization))
+        && !cl.isAnnotation() && !cl.isInterface() && !cl.isEnum()) {
+      // Errors.error(Errors.HIDDEN_CONSTRUCTOR,
+      // cl.position(), "No constructors " +
+      // "found and superclass has no parameterless constructor.  A constructor " +
+      // "that calls an appropriate superclass constructor " +
+      // "was automatically written to stubs.\n");
+      stream.println(cl.leafName() + "() { " + superCtorCall(cl, null) + "throw new"
+          + " RuntimeException(\"Stub!\"); }");
+    }
+
+    for (MethodInfo method : cl.allSelfMethods()) {
+      if (cl.isEnum()) {
+        if (("values".equals(method.name()) && "()".equals(method.signature()))
+            || ("valueOf".equals(method.name()) && "(java.lang.String)".equals(method.signature()))) {
+          // skip these two methods on enums, because they're synthetic,
+          // although for some reason javadoc doesn't mark them as synthetic,
+          // maybe because they still want them documented
+          continue;
+        }
+      }
+      if (!method.isDocOnly()) {
+        writeMethod(stream, method, false);
+      }
+    }
+    // Write all methods that are hidden, but override abstract methods or interface methods.
+    // These can't be hidden.
+    for (MethodInfo method : cl.getHiddenMethods()) {
+      MethodInfo overriddenMethod =
+          method.findRealOverriddenMethod(method.name(), method.signature(), notStrippable);
+      ClassInfo classContainingMethod =
+          method.findRealOverriddenClass(method.name(), method.signature());
+      if (overriddenMethod != null && !overriddenMethod.isHidden() && !overriddenMethod.isDocOnly()
+          && (overriddenMethod.isAbstract() || overriddenMethod.containingClass().isInterface())) {
+        method.setReason("1:" + classContainingMethod.qualifiedName());
+        cl.addMethod(method);
+        writeMethod(stream, method, false);
+      }
+    }
+
+    for (MethodInfo element : cl.annotationElements()) {
+      if (!element.isDocOnly()) {
+        writeAnnotationElement(stream, element);
+      }
+    }
+
+    for (FieldInfo field : cl.allSelfFields()) {
+      if (!field.isDocOnly()) {
+        writeField(stream, field);
+      }
+    }
+
+    if (staticFieldNeedsInitialization) {
+      stream.print("static { ");
+      for (FieldInfo field : cl.allSelfFields()) {
+        if (!field.isDocOnly() && field.isStatic() && field.isFinal() && !fieldIsInitialized(field)
+            && field.constantValue() == null) {
+          stream.print(field.name() + " = " + field.type().defaultValue() + "; ");
+        }
+      }
+      stream.println("}");
+    }
+
+    stream.println("}");
+  }
+
+
+  static void writeMethod(PrintStream stream, MethodInfo method, boolean isConstructor) {
+    String comma;
+
+    stream.print(method.scope() + " ");
+    if (method.isStatic()) {
+      stream.print("static ");
+    }
+    if (method.isFinal()) {
+      stream.print("final ");
+    }
+    if (method.isAbstract()) {
+      stream.print("abstract ");
+    }
+    if (method.isSynchronized()) {
+      stream.print("synchronized ");
+    }
+    if (method.isNative()) {
+      stream.print("native ");
+    }
+    if (false /* method.isStictFP() */) {
+      stream.print("strictfp ");
+    }
+
+    stream.print(method.typeArgumentsName(new HashSet()) + " ");
+
+    if (!isConstructor) {
+      stream.print(method.returnType().fullName(method.typeVariables()) + " ");
+    }
+    String n = method.name();
+    int pos = n.lastIndexOf('.');
+    if (pos >= 0) {
+      n = n.substring(pos + 1);
+    }
+    stream.print(n + "(");
+    comma = "";
+    int count = 1;
+    int size = method.parameters().length;
+    for (ParameterInfo param : method.parameters()) {
+      stream.print(comma + fullParameterTypeName(method, param.type(), count == size) + " "
+          + param.name());
+      comma = ", ";
+      count++;
+    }
+    stream.print(")");
+
+    comma = "";
+    if (method.thrownExceptions().length > 0) {
+      stream.print(" throws ");
+      for (ClassInfo thrown : method.thrownExceptions()) {
+        stream.print(comma + thrown.qualifiedName());
+        comma = ", ";
+      }
+    }
+    if (method.isAbstract() || method.isNative() || method.containingClass().isInterface()) {
+      stream.println(";");
+    } else {
+      stream.print(" { ");
+      if (isConstructor) {
+        stream.print(superCtorCall(method.containingClass(), method.thrownExceptions()));
+      }
+      stream.println("throw new RuntimeException(\"Stub!\"); }");
+    }
+  }
+
+  static void writeField(PrintStream stream, FieldInfo field) {
+    stream.print(field.scope() + " ");
+    if (field.isStatic()) {
+      stream.print("static ");
+    }
+    if (field.isFinal()) {
+      stream.print("final ");
+    }
+    if (field.isTransient()) {
+      stream.print("transient ");
+    }
+    if (field.isVolatile()) {
+      stream.print("volatile ");
+    }
+
+    stream.print(field.type().fullName());
+    stream.print(" ");
+    stream.print(field.name());
+
+    if (fieldIsInitialized(field)) {
+      stream.print(" = " + field.constantLiteralValue());
+    }
+
+    stream.println(";");
+  }
+
+  static boolean fieldIsInitialized(FieldInfo field) {
+    return (field.isFinal() && field.constantValue() != null)
+        || !field.type().dimension().equals("") || field.containingClass().isInterface();
+  }
+
+  // Returns 'true' if the method is an @Override of a visible parent
+  // method implementation, and thus does not affect the API.
+  static boolean methodIsOverride(MethodInfo mi) {
+    // Abstract/static/final methods are always listed in the API description
+    if (mi.isAbstract() || mi.isStatic() || mi.isFinal()) {
+      return false;
+    }
+
+    // Find any relevant ancestor declaration and inspect it
+    MethodInfo om = mi.findSuperclassImplementation(notStrippable);
+    if (om != null) {
+      // Visibility mismatch is an API change, so check for it
+      if (mi.mIsPrivate == om.mIsPrivate && mi.mIsPublic == om.mIsPublic
+          && mi.mIsProtected == om.mIsProtected) {
+        // Look only for overrides of an ancestor class implementation,
+        // not of e.g. an abstract or interface method declaration
+        if (!om.isAbstract()) {
+          // If the parent is hidden, we can't rely on it to provide
+          // the API
+          if (!om.isHidden()) {
+            // If the only "override" turns out to be in our own class
+            // (which sometimes happens in concrete subclasses of
+            // abstract base classes), it's not really an override
+            if (!mi.mContainingClass.equals(om.mContainingClass)) {
+              return true;
+            }
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+  static boolean canCallMethod(ClassInfo from, MethodInfo m) {
+    if (m.isPublic() || m.isProtected()) {
+      return true;
+    }
+    if (m.isPackagePrivate()) {
+      String fromPkg = from.containingPackage().name();
+      String pkg = m.containingClass().containingPackage().name();
+      if (fromPkg.equals(pkg)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // call a constructor, any constructor on this class's superclass.
+  static String superCtorCall(ClassInfo cl, ClassInfo[] thrownExceptions) {
+    ClassInfo base = cl.realSuperclass();
+    if (base == null) {
+      return "";
+    }
+    HashSet<String> exceptionNames = new HashSet<String>();
+    if (thrownExceptions != null) {
+      for (ClassInfo thrown : thrownExceptions) {
+        exceptionNames.add(thrown.name());
+      }
+    }
+    MethodInfo[] ctors = base.constructors();
+    MethodInfo ctor = null;
+    // bad exception indicates that the exceptions thrown by the super constructor
+    // are incompatible with the constructor we're using for the sub class.
+    Boolean badException = false;
+    for (MethodInfo m : ctors) {
+      if (canCallMethod(cl, m)) {
+        if (m.thrownExceptions() != null) {
+          for (ClassInfo thrown : m.thrownExceptions()) {
+            if (!exceptionNames.contains(thrown.name())) {
+              badException = true;
+            }
+          }
+        }
+        if (badException) {
+          badException = false;
+          continue;
+        }
+        // if it has no args, we're done
+        if (m.parameters().length == 0) {
+          return "";
+        }
+        ctor = m;
+      }
+    }
+    if (ctor != null) {
+      String result = "";
+      result += "super(";
+      ParameterInfo[] params = ctor.parameters();
+      int N = params.length;
+      for (int i = 0; i < N; i++) {
+        TypeInfo t = params[i].type();
+        if (t.isPrimitive() && t.dimension().equals("")) {
+          String n = t.simpleTypeName();
+          if (("byte".equals(n) || "short".equals(n) || "int".equals(n) || "long".equals(n)
+              || "float".equals(n) || "double".equals(n))
+              && t.dimension().equals("")) {
+            result += "0";
+          } else if ("char".equals(n)) {
+            result += "'\\0'";
+          } else if ("boolean".equals(n)) {
+            result += "false";
+          } else {
+            result += "<<unknown-" + n + ">>";
+          }
+        } else {
+          // put null in each super class method. Cast null to the correct type
+          // to avoid collisions with other constructors. If the type is generic
+          // don't cast it
+          result +=
+              (!t.isTypeVariable() ? "(" + t.qualifiedTypeName() + t.dimension() + ")" : "")
+                  + "null";
+        }
+        if (i != N - 1) {
+          result += ",";
+        }
+      }
+      result += "); ";
+      return result;
+    } else {
+      return "";
+    }
+  }
+
+  static void writeAnnotations(PrintStream stream, AnnotationInstanceInfo[] annotations) {
+    for (AnnotationInstanceInfo ann : annotations) {
+      if (!ann.type().isHidden()) {
+        stream.println(ann.toString());
+      }
+    }
+  }
+
+  static void writeAnnotationElement(PrintStream stream, MethodInfo ann) {
+    stream.print(ann.returnType().fullName());
+    stream.print(" ");
+    stream.print(ann.name());
+    stream.print("()");
+    AnnotationValueInfo def = ann.defaultAnnotationElementValue();
+    if (def != null) {
+      stream.print(" default ");
+      stream.print(def.valueString());
+    }
+    stream.println(";");
+  }
+
+  static void writeXML(PrintStream xmlWriter, HashMap<PackageInfo, List<ClassInfo>> allClasses,
+      HashSet notStrippable) {
+    // extract the set of packages, sort them by name, and write them out in that order
+    Set<PackageInfo> allClassKeys = allClasses.keySet();
+    PackageInfo[] allPackages = allClassKeys.toArray(new PackageInfo[allClassKeys.size()]);
+    Arrays.sort(allPackages, PackageInfo.comparator);
+
+    xmlWriter.println("<api>");
+    for (PackageInfo pack : allPackages) {
+      writePackageXML(xmlWriter, pack, allClasses.get(pack), notStrippable);
+    }
+    xmlWriter.println("</api>");
+  }
+
+  static void writePackageXML(PrintStream xmlWriter, PackageInfo pack, List<ClassInfo> classList,
+      HashSet notStrippable) {
+    ClassInfo[] classes = classList.toArray(new ClassInfo[classList.size()]);
+    Arrays.sort(classes, ClassInfo.comparator);
+    // Work around the bogus "Array" class we invent for
+    // Arrays.copyOf's Class<? extends T[]> newType parameter. (http://b/2715505)
+    if (pack.name().equals(PackageInfo.DEFAULT_PACKAGE)) {
+      return;
+    }
+    xmlWriter.println("<package name=\"" + pack.name() + "\"\n"
+    // + " source=\"" + pack.position() + "\"\n"
+        + ">");
+    for (ClassInfo cl : classes) {
+      writeClassXML(xmlWriter, cl, notStrippable);
+    }
+    xmlWriter.println("</package>");
+
+
+  }
+
+  static void writeClassXML(PrintStream xmlWriter, ClassInfo cl, HashSet notStrippable) {
+    String scope = cl.scope();
+    String deprecatedString = "";
+    String declString = (cl.isInterface()) ? "interface" : "class";
+    if (cl.isDeprecated()) {
+      deprecatedString = "deprecated";
+    } else {
+      deprecatedString = "not deprecated";
+    }
+    xmlWriter.println("<" + declString + " name=\"" + cl.name() + "\"");
+    if (!cl.isInterface() && !cl.qualifiedName().equals("java.lang.Object")) {
+      xmlWriter.println(" extends=\""
+          + ((cl.realSuperclass() == null) ? "java.lang.Object" : cl.realSuperclass()
+              .qualifiedName()) + "\"");
+    }
+    xmlWriter.println(" abstract=\"" + cl.isAbstract() + "\"\n" + " static=\"" + cl.isStatic()
+        + "\"\n" + " final=\"" + cl.isFinal() + "\"\n" + " deprecated=\"" + deprecatedString
+        + "\"\n" + " visibility=\"" + scope + "\"\n"
+        // + " source=\"" + cl.position() + "\"\n"
+        + ">");
+
+    ClassInfo[] interfaces = cl.realInterfaces();
+    Arrays.sort(interfaces, ClassInfo.comparator);
+    for (ClassInfo iface : interfaces) {
+      if (notStrippable.contains(iface)) {
+        xmlWriter.println("<implements name=\"" + iface.qualifiedName() + "\">");
+        xmlWriter.println("</implements>");
+      }
+    }
+
+    MethodInfo[] constructors = cl.constructors();
+    Arrays.sort(constructors, MethodInfo.comparator);
+    for (MethodInfo mi : constructors) {
+      writeConstructorXML(xmlWriter, mi);
+    }
+
+    MethodInfo[] methods = cl.allSelfMethods();
+    Arrays.sort(methods, MethodInfo.comparator);
+    for (MethodInfo mi : methods) {
+      if (!methodIsOverride(mi)) {
+        writeMethodXML(xmlWriter, mi);
+      }
+    }
+
+    FieldInfo[] fields = cl.allSelfFields();
+    Arrays.sort(fields, FieldInfo.comparator);
+    for (FieldInfo fi : fields) {
+      writeFieldXML(xmlWriter, fi);
+    }
+    xmlWriter.println("</" + declString + ">");
+
+  }
+
+  static void writeMethodXML(PrintStream xmlWriter, MethodInfo mi) {
+    String scope = mi.scope();
+
+    String deprecatedString = "";
+    if (mi.isDeprecated()) {
+      deprecatedString = "deprecated";
+    } else {
+      deprecatedString = "not deprecated";
+    }
+    xmlWriter.println("<method name=\""
+        + mi.name()
+        + "\"\n"
+        + ((mi.returnType() != null) ? " return=\""
+            + makeXMLcompliant(fullParameterTypeName(mi, mi.returnType(), false)) + "\"\n" : "")
+        + " abstract=\"" + mi.isAbstract() + "\"\n" + " native=\"" + mi.isNative() + "\"\n"
+        + " synchronized=\"" + mi.isSynchronized() + "\"\n" + " static=\"" + mi.isStatic() + "\"\n"
+        + " final=\"" + mi.isFinal() + "\"\n" + " deprecated=\"" + deprecatedString + "\"\n"
+        + " visibility=\"" + scope + "\"\n"
+        // + " source=\"" + mi.position() + "\"\n"
+        + ">");
+
+    // write parameters in declaration order
+    int numParameters = mi.parameters().length;
+    int count = 0;
+    for (ParameterInfo pi : mi.parameters()) {
+      count++;
+      writeParameterXML(xmlWriter, mi, pi, count == numParameters);
+    }
+
+    // but write exceptions in canonicalized order
+    ClassInfo[] exceptions = mi.thrownExceptions();
+    Arrays.sort(exceptions, ClassInfo.comparator);
+    for (ClassInfo pi : exceptions) {
+      xmlWriter.println("<exception name=\"" + pi.name() + "\" type=\"" + pi.qualifiedName()
+          + "\">");
+      xmlWriter.println("</exception>");
+    }
+    xmlWriter.println("</method>");
+  }
+
+  static void writeConstructorXML(PrintStream xmlWriter, MethodInfo mi) {
+    String scope = mi.scope();
+    String deprecatedString = "";
+    if (mi.isDeprecated()) {
+      deprecatedString = "deprecated";
+    } else {
+      deprecatedString = "not deprecated";
+    }
+    xmlWriter.println("<constructor name=\"" + mi.name() + "\"\n" + " type=\""
+        + mi.containingClass().qualifiedName() + "\"\n" + " static=\"" + mi.isStatic() + "\"\n"
+        + " final=\"" + mi.isFinal() + "\"\n" + " deprecated=\"" + deprecatedString + "\"\n"
+        + " visibility=\"" + scope + "\"\n"
+        // + " source=\"" + mi.position() + "\"\n"
+        + ">");
+
+    int numParameters = mi.parameters().length;
+    int count = 0;
+    for (ParameterInfo pi : mi.parameters()) {
+      count++;
+      writeParameterXML(xmlWriter, mi, pi, count == numParameters);
+    }
+
+    ClassInfo[] exceptions = mi.thrownExceptions();
+    Arrays.sort(exceptions, ClassInfo.comparator);
+    for (ClassInfo pi : exceptions) {
+      xmlWriter.println("<exception name=\"" + pi.name() + "\" type=\"" + pi.qualifiedName()
+          + "\">");
+      xmlWriter.println("</exception>");
+    }
+    xmlWriter.println("</constructor>");
+  }
+
+  static void writeParameterXML(PrintStream xmlWriter, MethodInfo method, ParameterInfo pi,
+      boolean isLast) {
+    xmlWriter.println("<parameter name=\"" + pi.name() + "\" type=\""
+        + makeXMLcompliant(fullParameterTypeName(method, pi.type(), isLast)) + "\">");
+    xmlWriter.println("</parameter>");
+  }
+
+  static void writeFieldXML(PrintStream xmlWriter, FieldInfo fi) {
+    String scope = fi.scope();
+    String deprecatedString = "";
+    if (fi.isDeprecated()) {
+      deprecatedString = "deprecated";
+    } else {
+      deprecatedString = "not deprecated";
+    }
+    // need to make sure value is valid XML
+    String value = makeXMLcompliant(fi.constantLiteralValue());
+
+    String fullTypeName = makeXMLcompliant(fi.type().qualifiedTypeName()) + fi.type().dimension();
+
+    xmlWriter.println("<field name=\"" + fi.name() + "\"\n" + " type=\"" + fullTypeName + "\"\n"
+        + " transient=\"" + fi.isTransient() + "\"\n" + " volatile=\"" + fi.isVolatile() + "\"\n"
+        + (fieldIsInitialized(fi) ? " value=\"" + value + "\"\n" : "") + " static=\""
+        + fi.isStatic() + "\"\n" + " final=\"" + fi.isFinal() + "\"\n" + " deprecated=\""
+        + deprecatedString + "\"\n" + " visibility=\"" + scope + "\"\n"
+        // + " source=\"" + fi.position() + "\"\n"
+        + ">");
+    xmlWriter.println("</field>");
+  }
+
+  static String makeXMLcompliant(String s) {
+    String returnString = "";
+    returnString = s.replaceAll("&", "&amp;");
+    returnString = returnString.replaceAll("<", "&lt;");
+    returnString = returnString.replaceAll(">", "&gt;");
+    returnString = returnString.replaceAll("\"", "&quot;");
+    returnString = returnString.replaceAll("'", "&pos;");
+    return returnString;
+  }
+
+  static String fullParameterTypeName(MethodInfo method, TypeInfo type, boolean isLast) {
+    String fullTypeName = type.fullName(method.typeVariables());
+    if (isLast && method.isVarArgs()) {
+      // TODO: note that this does not attempt to handle hypothetical
+      // vararg methods whose last parameter is a list of arrays, e.g.
+      // "Object[]...".
+      fullTypeName = type.fullNameNoDimension(method.typeVariables()) + "...";
+    }
+    return fullTypeName;
+  }
+}
diff --git a/src/com/google/doclava/TagInfo.java b/src/com/google/doclava/TagInfo.java
new file mode 100644
index 0000000..09d4e35
--- /dev/null
+++ b/src/com/google/doclava/TagInfo.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+public class TagInfo {
+  private String mName;
+  private String mText;
+  private String mKind;
+  private SourcePositionInfo mPosition;
+
+  TagInfo(String n, String k, String t, SourcePositionInfo sp) {
+    mName = n;
+    mText = t;
+    mKind = k;
+    mPosition = sp;
+  }
+
+  String name() {
+    return mName;
+  }
+
+  String text() {
+    return mText;
+  }
+
+  String kind() {
+    return mKind;
+  }
+
+  SourcePositionInfo position() {
+    return mPosition;
+  }
+
+  void setKind(String kind) {
+    mKind = kind;
+  }
+
+  public void makeHDF(Data data, String base) {
+    data.setValue(base + ".name", name());
+    data.setValue(base + ".text", text());
+    data.setValue(base + ".kind", kind());
+  }
+
+  public static void makeHDF(Data data, String base, TagInfo[] tags) {
+    makeHDF(data, base, tags, null, 0, 0);
+  }
+
+  public static void makeHDF(Data data, String base, InheritedTags tags) {
+    makeHDF(data, base, tags.tags(), tags.inherited(), 0, 0);
+  }
+
+  private static int makeHDF(Data data, String base, TagInfo[] tags, InheritedTags inherited,
+      int j, int depth) {
+    int i;
+    int len = tags.length;
+    if (len == 0 && inherited != null) {
+      j = makeHDF(data, base, inherited.tags(), inherited.inherited(), j, depth + 1);
+    } else {
+      for (i = 0; i < len; i++, j++) {
+        TagInfo t = tags[i];
+        if (inherited != null && t.name().equals("@inheritDoc")) {
+          j = makeHDF(data, base, inherited.tags(), inherited.inherited(), j, depth + 1);
+        } else {
+          if (t.name().equals("@inheritDoc")) {
+            Errors.error(Errors.BAD_INHERITDOC, t.mPosition,
+                "@inheritDoc on class/method that is not inherited");
+          }
+          t.makeHDF(data, base + "." + j);
+        }
+      }
+    }
+    return j;
+  }
+}
diff --git a/src/com/google/doclava/TextTagInfo.java b/src/com/google/doclava/TextTagInfo.java
new file mode 100644
index 0000000..35a486b
--- /dev/null
+++ b/src/com/google/doclava/TextTagInfo.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+public class TextTagInfo extends TagInfo {
+  TextTagInfo(String n, String k, String t, SourcePositionInfo p) {
+    super(n, k, Doclava.escape(t), p);
+  }
+}
diff --git a/src/com/google/doclava/ThrowsTagInfo.java b/src/com/google/doclava/ThrowsTagInfo.java
new file mode 100644
index 0000000..5f49485
--- /dev/null
+++ b/src/com/google/doclava/ThrowsTagInfo.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+public class ThrowsTagInfo extends ParsedTagInfo {
+  static final Pattern PATTERN = Pattern.compile("(\\S+)\\s+(.*)", Pattern.DOTALL);
+  private ClassInfo mException;
+
+  public ThrowsTagInfo(String name, String kind, String text, ContainerInfo base,
+      SourcePositionInfo sp) {
+    super(name, kind, text, base, sp);
+
+    Matcher m = PATTERN.matcher(text);
+    if (m.matches()) {
+      setCommentText(m.group(2));
+      String className = m.group(1);
+      if (base instanceof ClassInfo) {
+        mException = ((ClassInfo) base).findClass(className);
+      }
+      if (mException == null) {
+        mException = Converter.obtainClass(className);
+      }
+    }
+  }
+
+  public ThrowsTagInfo(String name, String kind, String text, ClassInfo exception,
+      String exceptionComment, ContainerInfo base, SourcePositionInfo sp) {
+    super(name, kind, text, base, sp);
+    mException = exception;
+    setCommentText(exceptionComment);
+  }
+
+  public ClassInfo exception() {
+    return mException;
+  }
+
+  public TypeInfo exceptionType() {
+    if (mException != null) {
+      return mException.asTypeInfo();
+    } else {
+      return null;
+    }
+  }
+
+  public static void makeHDF(Data data, String base, ThrowsTagInfo[] tags) {
+    for (int i = 0; i < tags.length; i++) {
+      TagInfo.makeHDF(data, base + '.' + i + ".comment", tags[i].commentTags());
+      if (tags[i].exceptionType() != null) {
+        tags[i].exceptionType().makeHDF(data, base + "." + i + ".type");
+      }
+    }
+  }
+
+
+}
diff --git a/src/com/google/doclava/TodoFile.java b/src/com/google/doclava/TodoFile.java
new file mode 100644
index 0000000..5cf4f1e
--- /dev/null
+++ b/src/com/google/doclava/TodoFile.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.util.*;
+
+public class TodoFile {
+
+  public static final String MISSING = "No description text";
+
+  public static boolean areTagsUseful(InheritedTags tags) {
+    while (tags != null) {
+      if (areTagsUseful(tags.tags())) {
+        return true;
+      }
+      tags = tags.inherited();
+    }
+    return false;
+  }
+
+  public static boolean areTagsUseful(TagInfo[] tags) {
+    for (TagInfo t : tags) {
+      if ("Text".equals(t.name()) && t.text().trim().length() != 0) {
+        return true;
+      }
+      if ("@inheritDoc".equals(t.name())) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public static void setHDF(Data data, String base, SourcePositionInfo pos, String name,
+      String descr) {
+    data.setValue(base + ".pos", pos.toString());
+    data.setValue(base + ".name", name);
+    data.setValue(base + ".descr", descr);
+  }
+
+  static class PackageStats {
+    String name;
+    public int total;
+    public int errors;
+  }
+
+  public static String percent(int a, int b) {
+    return "" + Math.round((((b - a) / (float) b)) * 100) + "%";
+  }
+
+  public static void writeTodoFile(String filename) {
+    Data data = Doclava.makeHDF();
+    Doclava.setPageTitle(data, "Missing Documentation");
+    TreeMap<String, PackageStats> packageStats = new TreeMap<String, PackageStats>();
+
+    ClassInfo[] classes = Converter.rootClasses();
+    Arrays.sort(classes);
+
+    int classIndex = 0;
+
+    for (ClassInfo cl : classes) {
+      if (cl.isHidden()) {
+        continue;
+      }
+
+      String classBase = "classes." + classIndex;
+
+      String base = classBase + ".errors.";
+      int errors = 0;
+      int total = 1;
+
+      if (!areTagsUseful(cl.inlineTags())) {
+        setHDF(data, base + errors, cl.position(), "&lt;class comment&gt;", MISSING);
+        errors++;
+      }
+
+
+      for (MethodInfo m : cl.constructors()) {
+        boolean good = true;
+        total++;
+        if (m.checkLevel()) {
+          if (!areTagsUseful(m.inlineTags())) {
+            setHDF(data, base + errors, m.position(), m.prettySignature(), MISSING);
+            good = false;
+          }
+        }
+        if (!good) {
+          errors++;
+        }
+      }
+
+      for (MethodInfo m : cl.selfMethods()) {
+        boolean good = true;
+        total++;
+        if (m.checkLevel()) {
+          if (!areTagsUseful(m.inlineTags())) {
+            setHDF(data, base + errors, m.position(), m.name() + m.prettySignature(), MISSING);
+            good = false;
+          }
+        }
+        if (!good) {
+          errors++;
+        }
+      }
+
+
+      for (FieldInfo f : cl.enumConstants()) {
+        boolean good = true;
+        total++;
+        if (f.checkLevel()) {
+          if (!areTagsUseful(f.inlineTags())) {
+            setHDF(data, base + errors, f.position(), f.name(), MISSING);
+            good = false;
+          }
+        }
+        if (!good) {
+          errors++;
+        }
+      }
+
+      for (FieldInfo f : cl.selfFields()) {
+        boolean good = true;
+        total++;
+        if (f.checkLevel()) {
+          if (!areTagsUseful(f.inlineTags())) {
+            setHDF(data, base + errors, f.position(), f.name(), MISSING);
+            good = false;
+          }
+        }
+        if (!good) {
+          errors++;
+        }
+      }
+
+      if (errors > 0) {
+        data.setValue(classBase + ".qualified", cl.qualifiedName());
+        data.setValue(classBase + ".errorCount", "" + errors);
+        data.setValue(classBase + ".totalCount", "" + total);
+        data.setValue(classBase + ".percentGood", percent(errors, total));
+      }
+
+      PackageInfo pkg = cl.containingPackage();
+      String pkgName = pkg != null ? pkg.name() : "";
+      PackageStats ps = packageStats.get(pkgName);
+      if (ps == null) {
+        ps = new PackageStats();
+        ps.name = pkgName;
+        packageStats.put(pkgName, ps);
+      }
+      ps.total += total;
+      ps.errors += errors;
+
+      classIndex++;
+    }
+
+    int allTotal = 0;
+    int allErrors = 0;
+
+    int i = 0;
+    for (PackageStats ps : packageStats.values()) {
+      data.setValue("packages." + i + ".name", "" + ps.name);
+      data.setValue("packages." + i + ".errorCount", "" + ps.errors);
+      data.setValue("packages." + i + ".totalCount", "" + ps.total);
+      data.setValue("packages." + i + ".percentGood", percent(ps.errors, ps.total));
+
+      allTotal += ps.total;
+      allErrors += ps.errors;
+
+      i++;
+    }
+
+    data.setValue("all.errorCount", "" + allErrors);
+    data.setValue("all.totalCount", "" + allTotal);
+    data.setValue("all.percentGood", percent(allErrors, allTotal));
+
+    ClearPage.write(data, "todo.cs", filename, true);
+  }
+}
diff --git a/src/com/google/doclava/TypeInfo.java b/src/com/google/doclava/TypeInfo.java
new file mode 100644
index 0000000..8572f59
--- /dev/null
+++ b/src/com/google/doclava/TypeInfo.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import java.util.*;
+
+public class TypeInfo {
+  public static final Set<String> PRIMITIVE_TYPES = Collections.unmodifiableSet(
+      new HashSet<String>(Arrays.asList("boolean", "byte", "char", "double", "float", "int",
+      "long", "short", "void")));
+  
+  public TypeInfo(boolean isPrimitive, String dimension, String simpleTypeName,
+      String qualifiedTypeName, ClassInfo cl) {
+    mIsPrimitive = isPrimitive;
+    mDimension = dimension;
+    mSimpleTypeName = simpleTypeName;
+    mQualifiedTypeName = qualifiedTypeName;
+    mClass = cl;
+  }
+
+  public TypeInfo(String typeString) {
+    // VarArgs
+    if (typeString.endsWith("...")) {
+      typeString = typeString.substring(0, typeString.length() - 3);
+    }
+    
+    // Generic parameters
+    int paramStartPos = typeString.indexOf('<');
+    if (paramStartPos > -1) {
+      ArrayList<TypeInfo> generics = new ArrayList<TypeInfo>();
+      int paramEndPos = typeString.lastIndexOf('>');
+      
+      int entryStartPos = paramStartPos + 1;
+      int bracketNesting = 0;
+      for (int i = entryStartPos; i < paramEndPos; i++) {
+        char c = typeString.charAt(i);
+        if (c == ',' && bracketNesting == 0) {
+          String entry = typeString.substring(entryStartPos, i).trim();
+          TypeInfo info = new TypeInfo(entry);
+          generics.add(info);
+          entryStartPos = i + 1;
+        } else if (c == '<') {
+          bracketNesting++;
+        } else if (c == '>') {
+          bracketNesting--;
+        }
+      }
+     
+      TypeInfo info = new TypeInfo(typeString.substring(entryStartPos, paramEndPos).trim());
+      generics.add(info);
+      
+      mTypeArguments = new TypeInfo[generics.size()];
+      generics.toArray(mTypeArguments);
+      
+      if (paramEndPos < typeString.length() - 1) {
+        typeString = typeString.substring(0,paramStartPos) + typeString.substring(paramEndPos + 1);
+      } else {
+        typeString = typeString.substring(0,paramStartPos);
+      }
+    }
+    
+    // Dimensions
+    int pos = typeString.indexOf('['); 
+    if (pos > -1) {
+      mDimension = typeString.substring(pos);
+      typeString = typeString.substring(0, pos);
+    } else {
+      mDimension = "";
+    }
+   
+    if (PRIMITIVE_TYPES.contains(typeString)) {
+      mIsPrimitive = true;
+      mSimpleTypeName = typeString;
+      mQualifiedTypeName = typeString;
+    } else {
+      mQualifiedTypeName = typeString;
+      pos = typeString.lastIndexOf('.');
+      if (pos > -1) {
+        mSimpleTypeName = typeString.substring(pos + 1);
+      } else {
+        mSimpleTypeName = typeString;
+      }
+    }
+  }
+
+  public ClassInfo asClassInfo() {
+    return mClass;
+  }
+
+  public boolean isPrimitive() {
+    return mIsPrimitive;
+  }
+
+  public String dimension() {
+    return mDimension;
+  }
+
+  public String simpleTypeName() {
+    return mSimpleTypeName;
+  }
+
+  public String qualifiedTypeName() {
+    return mQualifiedTypeName;
+  }
+
+  public String fullName() {
+    if (mFullName != null) {
+      return mFullName;
+    } else {
+      return fullName(new HashSet<String>());
+    }
+  }
+
+  public static String typeArgumentsName(TypeInfo[] args, HashSet<String> typeVars) {
+    String result = "<";
+    for (int i = 0; i < args.length; i++) {
+      result += args[i].fullName(typeVars);
+      if (i != args.length - 1) {
+        result += ", ";
+      }
+    }
+    result += ">";
+    return result;
+  }
+
+  public String fullName(HashSet<String> typeVars) {
+    mFullName = fullNameNoDimension(typeVars) + mDimension;
+    return mFullName;
+  }
+
+  public String fullNameNoDimension(HashSet<String> typeVars) {
+    String fullName = null;
+    if (mIsTypeVariable) {
+      if (typeVars.contains(mQualifiedTypeName)) {
+        // don't recurse forever with the parameters. This handles
+        // Enum<K extends Enum<K>>
+        return mQualifiedTypeName;
+      }
+      typeVars.add(mQualifiedTypeName);
+    }
+    /*
+     * if (fullName != null) { return fullName; }
+     */
+    fullName = mQualifiedTypeName;
+    if (mTypeArguments != null && mTypeArguments.length > 0) {
+      fullName += typeArgumentsName(mTypeArguments, typeVars);
+    } else if (mSuperBounds != null && mSuperBounds.length > 0) {
+      fullName += " super " + mSuperBounds[0].fullName(typeVars);
+      for (int i = 1; i < mSuperBounds.length; i++) {
+        fullName += " & " + mSuperBounds[i].fullName(typeVars);
+      }
+    } else if (mExtendsBounds != null && mExtendsBounds.length > 0) {
+      fullName += " extends " + mExtendsBounds[0].fullName(typeVars);
+      for (int i = 1; i < mExtendsBounds.length; i++) {
+        fullName += " & " + mExtendsBounds[i].fullName(typeVars);
+      }
+    }
+    return fullName;
+  }
+
+  public TypeInfo[] typeArguments() {
+    return mTypeArguments;
+  }
+
+  public void makeHDF(Data data, String base) {
+    makeHDFRecursive(data, base, false, false, new HashSet<String>());
+  }
+
+  public void makeQualifiedHDF(Data data, String base) {
+    makeHDFRecursive(data, base, true, false, new HashSet<String>());
+  }
+
+  public void makeHDF(Data data, String base, boolean isLastVararg, HashSet<String> typeVariables) {
+    makeHDFRecursive(data, base, false, isLastVararg, typeVariables);
+  }
+
+  public void makeQualifiedHDF(Data data, String base, HashSet<String> typeVariables) {
+    makeHDFRecursive(data, base, true, false, typeVariables);
+  }
+
+  private void makeHDFRecursive(Data data, String base, boolean qualified, boolean isLastVararg,
+      HashSet<String> typeVars) {
+    String label = qualified ? qualifiedTypeName() : simpleTypeName();
+    label += (isLastVararg) ? "..." : dimension();
+    data.setValue(base + ".label", label);
+    if (mIsTypeVariable || mIsWildcard) {
+      // could link to an @param tag on the class to describe this
+      // but for now, just don't make it a link
+    } else if (!isPrimitive() && mClass != null) {
+      if (mClass.isIncluded()) {
+        data.setValue(base + ".link", mClass.htmlPage());
+        data.setValue(base + ".since", mClass.getSince());
+      } else {
+        Doclava.federationTagger.tagAll(new ClassInfo[] {mClass});
+        if (!mClass.getFederatedReferences().isEmpty()) {
+          FederatedSite site = mClass.getFederatedReferences().iterator().next();
+          data.setValue(base + ".link", site.linkFor(mClass.htmlPage()));
+          data.setValue(base + ".federated", site.name());
+        }
+      }
+    }
+
+    if (mIsTypeVariable) {
+      if (typeVars.contains(qualifiedTypeName())) {
+        // don't recurse forever with the parameters. This handles
+        // Enum<K extends Enum<K>>
+        return;
+      }
+      typeVars.add(qualifiedTypeName());
+    }
+    if (mTypeArguments != null) {
+      TypeInfo.makeHDF(data, base + ".typeArguments", mTypeArguments, qualified, typeVars);
+    }
+    if (mSuperBounds != null) {
+      TypeInfo.makeHDF(data, base + ".superBounds", mSuperBounds, qualified, typeVars);
+    }
+    if (mExtendsBounds != null) {
+      TypeInfo.makeHDF(data, base + ".extendsBounds", mExtendsBounds, qualified, typeVars);
+    }
+  }
+
+  public static void makeHDF(Data data, String base, TypeInfo[] types, boolean qualified,
+      HashSet<String> typeVariables) {
+    final int N = types.length;
+    for (int i = 0; i < N; i++) {
+      types[i].makeHDFRecursive(data, base + "." + i, qualified, false, typeVariables);
+    }
+  }
+
+  public static void makeHDF(Data data, String base, TypeInfo[] types, boolean qualified) {
+    makeHDF(data, base, types, qualified, new HashSet<String>());
+  }
+
+  void setTypeArguments(TypeInfo[] args) {
+    mTypeArguments = args;
+  }
+
+  void setBounds(TypeInfo[] superBounds, TypeInfo[] extendsBounds) {
+    mSuperBounds = superBounds;
+    mExtendsBounds = extendsBounds;
+  }
+
+  void setIsTypeVariable(boolean b) {
+    mIsTypeVariable = b;
+  }
+
+  void setIsWildcard(boolean b) {
+    mIsWildcard = b;
+  }
+
+  static HashSet<String> typeVariables(TypeInfo[] params) {
+    return typeVariables(params, new HashSet());
+  }
+
+  static HashSet<String> typeVariables(TypeInfo[] params, HashSet<String> result) {
+    for (TypeInfo t : params) {
+      if (t.mIsTypeVariable) {
+        result.add(t.mQualifiedTypeName);
+      }
+    }
+    return result;
+  }
+
+
+  public boolean isTypeVariable() {
+    return mIsTypeVariable;
+  }
+
+  public String defaultValue() {
+    if (mIsPrimitive) {
+      if ("boolean".equals(mSimpleTypeName)) {
+        return "false";
+      } else {
+        return "0";
+      }
+    } else {
+      return "null";
+    }
+  }
+
+  @Override
+  public String toString() {
+    String returnString = "";
+    returnString +=
+        "Primitive?: " + mIsPrimitive + " TypeVariable?: " + mIsTypeVariable + " Wildcard?: "
+            + mIsWildcard + " Dimension: " + mDimension + " QualifedTypeName: "
+            + mQualifiedTypeName;
+
+    if (mTypeArguments != null) {
+      returnString += "\nTypeArguments: ";
+      for (TypeInfo tA : mTypeArguments) {
+        returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
+      }
+    }
+    if (mSuperBounds != null) {
+      returnString += "\nSuperBounds: ";
+      for (TypeInfo tA : mSuperBounds) {
+        returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
+      }
+    }
+    if (mExtendsBounds != null) {
+      returnString += "\nExtendsBounds: ";
+      for (TypeInfo tA : mExtendsBounds) {
+        returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
+      }
+    }
+    return returnString;
+  }
+
+  private boolean mIsPrimitive;
+  private boolean mIsTypeVariable;
+  private boolean mIsWildcard;
+  private String mDimension;
+  private String mSimpleTypeName;
+  private String mQualifiedTypeName;
+  private ClassInfo mClass;
+  private TypeInfo[] mTypeArguments;
+  private TypeInfo[] mSuperBounds;
+  private TypeInfo[] mExtendsBounds;
+  private String mFullName;
+}
diff --git a/src/com/google/doclava/apicheck/AbstractMethodInfo.java b/src/com/google/doclava/apicheck/AbstractMethodInfo.java
new file mode 100644
index 0000000..306dba8
--- /dev/null
+++ b/src/com/google/doclava/apicheck/AbstractMethodInfo.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava.apicheck;
+
+public interface AbstractMethodInfo {
+
+  public void addException(String exec);
+
+  public void addParameter(com.google.doclava.ParameterInfo p);
+
+  public void setDeprecated(boolean deprecated);
+  
+  public void setVarargs(boolean varargs);
+  public boolean isVarArgs();
+}
diff --git a/src/com/google/doclava/apicheck/ApiCheck.java b/src/com/google/doclava/apicheck/ApiCheck.java
new file mode 100644
index 0000000..0ec19c1
--- /dev/null
+++ b/src/com/google/doclava/apicheck/ApiCheck.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava.apicheck;
+
+import com.google.doclava.AnnotationInstanceInfo;
+import com.google.doclava.ClassInfo;
+import com.google.doclava.ConstructorInfo;
+import com.google.doclava.Converter;
+import com.google.doclava.Errors;
+import com.google.doclava.MethodInfo;
+import com.google.doclava.PackageInfo;
+import com.google.doclava.ParameterInfo;
+import com.google.doclava.SourcePositionInfo;
+import com.google.doclava.TypeInfo;
+
+import com.google.doclava.FieldInfo;
+import com.google.doclava.Errors.ErrorMessage;
+
+import com.sun.javadoc.ClassDoc;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.Stack;
+
+public class ApiCheck {
+  // parse out and consume the -whatever command line flags
+  private static ArrayList<String[]> parseFlags(ArrayList<String> allArgs) {
+    ArrayList<String[]> ret = new ArrayList<String[]>();
+
+    int i;
+    for (i = 0; i < allArgs.size(); i++) {
+      // flags with one value attached
+      String flag = allArgs.get(i);
+      if (flag.equals("-error") || flag.equals("-warning") || flag.equals("-hide")) {
+        String[] arg = new String[2];
+        arg[0] = flag;
+        arg[1] = allArgs.get(++i);
+        ret.add(arg);
+      } else {
+        // we've consumed all of the -whatever args, so we're done
+        break;
+      }
+    }
+
+    // i now points to the first non-flag arg; strip what came before
+    for (; i > 0; i--) {
+      allArgs.remove(0);
+    }
+    return ret;
+  }
+
+  public static void main(String[] originalArgs) {
+    ApiCheck acheck = new ApiCheck();
+    Report report = acheck.checkApi(originalArgs);
+   
+    Errors.printErrors(report.errors());
+    System.exit(report.code);
+  }
+  
+  /**
+   * Compares two api xml files for consistency.
+   */
+  public Report checkApi(String[] originalArgs) {
+    // translate to an ArrayList<String> for munging
+    ArrayList<String> args = new ArrayList<String>(originalArgs.length);
+    for (String a : originalArgs) {
+      args.add(a);
+    }
+
+    ArrayList<String[]> flags = ApiCheck.parseFlags(args);
+    for (String[] a : flags) {
+      if (a[0].equals("-error") || a[0].equals("-warning") || a[0].equals("-hide")) {
+        try {
+          int level = -1;
+          if (a[0].equals("-error")) {
+            level = Errors.ERROR;
+          } else if (a[0].equals("-warning")) {
+            level = Errors.WARNING;
+          } else if (a[0].equals("-hide")) {
+            level = Errors.HIDDEN;
+          }
+          Errors.setErrorLevel(Integer.parseInt(a[1]), level);
+        } catch (NumberFormatException e) {
+          System.err.println("Bad argument: " + a[0] + " " + a[1]);
+          return new Report(2, Errors.getErrors());
+        }
+      }
+    }
+
+    ApiInfo oldApi;
+    ApiInfo newApi;
+    
+    try {
+      oldApi = parseApi(args.get(0));
+      newApi = parseApi(args.get(1));
+    } catch (ApiParseException e) {
+      e.printStackTrace();
+      System.err.println("Error parsing API");
+      return new Report(1, Errors.getErrors());
+    }
+
+    // only run the consistency check if we haven't had XML parse errors
+    if (!Errors.hadError) {
+      oldApi.isConsistent(newApi);
+    }
+
+    return new Report(Errors.hadError ? 1 : 0, Errors.getErrors());
+  }
+
+  public ApiInfo parseApi(String xmlFile) throws ApiParseException {
+    FileInputStream fileStream = null;
+    try {
+      fileStream = new FileInputStream(xmlFile);
+      return parseApi(fileStream);
+    } catch (IOException e) {
+      throw new ApiParseException("Could not open file for parsing: " + xmlFile, e);
+    } finally {
+      if (fileStream != null) {
+        try {
+          fileStream.close();
+        } catch (IOException ignored) {}
+      }
+    }
+  }
+  
+  public ApiInfo parseApi(URL xmlURL) throws ApiParseException {
+    InputStream xmlStream = null;
+    try {
+      xmlStream = xmlURL.openStream();
+      return parseApi(xmlStream);
+    } catch (IOException e) {
+      throw new ApiParseException("Could not open stream for parsing: " + xmlURL,e);
+    } finally {
+      if (xmlStream != null) {
+        try {
+          xmlStream.close();
+        } catch (IOException ignored) {}
+      }
+    }
+  }
+  
+  public ApiInfo parseApi(InputStream xmlStream) throws ApiParseException {
+    try {
+      XMLReader xmlreader = XMLReaderFactory.createXMLReader();
+      MakeHandler handler = new MakeHandler();
+      xmlreader.setContentHandler(handler);
+      xmlreader.setErrorHandler(handler);
+      xmlreader.parse(new InputSource(xmlStream));
+      ApiInfo apiInfo = handler.getApi();
+      apiInfo.resolveSuperclasses();
+      apiInfo.resolveInterfaces();
+      return apiInfo;
+    } catch (Exception e) {
+      throw new ApiParseException("Error parsing API", e);
+    }
+  }
+  
+  private class MakeHandler extends DefaultHandler {
+
+    private ApiInfo mApi;
+    private PackageInfo mCurrentPackage;
+    private ClassInfo mCurrentClass;
+    private AbstractMethodInfo mCurrentMethod;
+    private Stack<ClassInfo> mClassScope = new Stack<ClassInfo>();
+    
+
+    public MakeHandler() {
+      super();
+      mApi = new ApiInfo();
+    }
+
+    @Override
+    public void startElement(String uri, String localName, String qName, Attributes attributes) {
+      if (qName.equals("package")) {
+        mCurrentPackage =
+            new PackageInfo(attributes.getValue("name"), SourcePositionInfo.fromXml(attributes
+                .getValue("source")));
+      } else if (qName.equals("class") || qName.equals("interface")) {
+        // push the old outer scope for later recovery, then set
+        // up the new current class object
+        mClassScope.push(mCurrentClass);
+        
+        ClassDoc classDoc = null;
+        String rawCommentText = "";
+        SourcePositionInfo position = SourcePositionInfo.fromXml(attributes.getValue("source"));
+        String visibility = attributes.getValue("visibility");
+        boolean isPublic = "public".equals(visibility);
+        boolean isProtected = "protected".equals(visibility);
+        boolean isPrivate = "private".equals(visibility); 
+        boolean isPackagePrivate = !isPublic && !isPrivate && !isProtected;
+        boolean isStatic = Boolean.valueOf(attributes.getValue("static"));
+        boolean isInterface = qName.equals("interface");
+        boolean isAbstract = Boolean.valueOf(attributes.getValue("abstract"));
+        boolean isOrdinaryClass = qName.equals("class");
+        boolean isException = false; // TODO: check hierarchy for java.lang.Exception
+        boolean isError = false; // TODO: not sure.
+        boolean isEnum = false; // TODO: not sure.
+        boolean isAnnotation = false; // TODO: not sure.
+        boolean isFinal = Boolean.valueOf(attributes.getValue("final"));
+        boolean isIncluded = false;
+        String name = attributes.getValue("name");
+        String qualifiedName = qualifiedName(mCurrentPackage.name(), name, mCurrentClass);
+        String qualifiedTypeName = null; // TODO: not sure
+        boolean isPrimitive = false;
+        
+        mCurrentClass =
+            new ClassInfo(classDoc, rawCommentText, position, isPublic, isProtected, 
+            isPackagePrivate, isPrivate, isStatic, isInterface, isAbstract, isOrdinaryClass, 
+            isException, isError, isEnum, isAnnotation, isFinal, isIncluded, name, qualifiedName,
+            qualifiedTypeName, isPrimitive);
+        
+        mCurrentClass.setContainingPackage(mCurrentPackage);
+        String superclass = attributes.getValue("extends");
+        if (superclass == null && !isInterface && !"java.lang.Object".equals(qualifiedName)) {
+          throw new AssertionError("no superclass known for class " + name);
+        }
+        
+        // Resolve superclass after .xml completely parsed.
+        mApi.mapClassToSuper(mCurrentClass, superclass);
+        
+        TypeInfo typeInfo = Converter.obtainTypeFromString(qualifiedName) ;
+        mCurrentClass.setTypeInfo(typeInfo);
+        mCurrentClass.setAnnotations(new AnnotationInstanceInfo[] {});
+      } else if (qName.equals("method")) {
+        String rawCommentText = "";
+        TypeInfo[] typeParameters = new TypeInfo[0];
+        String name = attributes.getValue("name");
+        String signature = null; // TODO
+        ClassInfo containingClass = mCurrentClass;
+        ClassInfo realContainingClass = mCurrentClass;
+        String visibility = attributes.getValue("visibility");
+        boolean isPublic = "public".equals(visibility);
+        boolean isProtected = "protected".equals(visibility);
+        boolean isPrivate = "private".equals(visibility); 
+        boolean isPackagePrivate = !isPublic && !isPrivate && !isProtected;
+        boolean isFinal = Boolean.valueOf(attributes.getValue("final"));
+        boolean isStatic = Boolean.valueOf(attributes.getValue("static"));
+        boolean isSynthetic = false; // TODO
+        boolean isAbstract = Boolean.valueOf(attributes.getValue("abstract"));
+        boolean isSynchronized = Boolean.valueOf(attributes.getValue("synchronized"));
+        boolean isNative = Boolean.valueOf(attributes.getValue("native"));
+        boolean isAnnotationElement = false; // TODO
+        String kind = qName;
+        String flatSignature = null; // TODO
+        MethodInfo overriddenMethod = null; // TODO
+        TypeInfo returnType = Converter.obtainTypeFromString(attributes.getValue("return"));
+        ParameterInfo[] parameters = new ParameterInfo[0];
+        ClassInfo[] thrownExceptions = new ClassInfo[0];
+        SourcePositionInfo position = SourcePositionInfo.fromXml(attributes.getValue("source"));
+        AnnotationInstanceInfo[] annotations = new AnnotationInstanceInfo[] {}; // TODO
+        
+        mCurrentMethod = 
+            new MethodInfo(rawCommentText, typeParameters, name, signature, containingClass,
+            realContainingClass, isPublic, isProtected, isPackagePrivate, isPrivate, isFinal,
+            isStatic, isSynthetic, isAbstract, isSynchronized, isNative, isAnnotationElement, kind,
+            flatSignature, overriddenMethod, returnType, parameters, thrownExceptions, position,
+            annotations);
+        
+        mCurrentMethod.setDeprecated("deprecated".equals(attributes.getValue("deprecated")));
+      } else if (qName.equals("constructor")) {
+        mCurrentMethod =
+            new ConstructorInfo(attributes.getValue("name"), attributes.getValue("type"), Boolean
+                .valueOf(attributes.getValue("static")), Boolean.valueOf(attributes
+                .getValue("final")), attributes.getValue("deprecated"), attributes
+                .getValue("visibility"), SourcePositionInfo.fromXml(attributes.getValue("source")),
+                mCurrentClass);
+      } else if (qName.equals("field")) {
+        String visibility = attributes.getValue("visibility");
+        boolean isPublic = visibility.equals("public");
+        boolean isProtected = visibility.equals("protected");
+        boolean isPrivate = visibility.equals("private");
+        boolean isPackagePrivate = visibility.equals("");
+        String typeName = attributes.getValue("type");
+        TypeInfo type = Converter.obtainTypeFromString(typeName);
+        
+        FieldInfo fInfo =
+            new FieldInfo(attributes.getValue("name"), mCurrentClass, mCurrentClass, isPublic,
+            isProtected, isPackagePrivate, isPrivate, Boolean.valueOf(attributes.getValue("final")),
+            Boolean.valueOf(attributes.getValue("static")), Boolean.valueOf(attributes.
+            getValue("transient")), Boolean.valueOf(attributes.getValue("volatile")), false,
+            type, "", attributes.getValue("value"), SourcePositionInfo
+            .fromXml(attributes.getValue("source")), new AnnotationInstanceInfo[] {});
+        
+        fInfo.setDeprecated("deprecated".equals(attributes.getValue("deprecated")));
+        mCurrentClass.addField(fInfo);
+      } else if (qName.equals("parameter")) {
+        String name = attributes.getValue("name");
+        String typeName = attributes.getValue("type");
+        TypeInfo type = Converter.obtainTypeFromString(typeName);
+        boolean isVarArg = typeName.endsWith("...");
+        SourcePositionInfo position = null;
+        
+        mCurrentMethod.addParameter(new ParameterInfo(name, typeName, type, isVarArg, position));
+        mCurrentMethod.setVarargs(isVarArg);
+      } else if (qName.equals("exception")) {
+        mCurrentMethod.addException(attributes.getValue("type"));
+      } else if (qName.equals("implements")) {
+        // Resolve interfaces after .xml completely parsed.
+        mApi.mapClassToInterface(mCurrentClass, attributes.getValue("name"));
+      }
+    }
+
+    @Override
+    public void endElement(String uri, String localName, String qName) {
+      if (qName.equals("method")) {
+        mCurrentClass.addMethod((MethodInfo) mCurrentMethod);
+      } else if (qName.equals("constructor")) {
+        mCurrentClass.addConstructor((ConstructorInfo) mCurrentMethod);
+      } else if (qName.equals("class") || qName.equals("interface")) {
+        mCurrentPackage.addClass(mCurrentClass);
+        mCurrentClass = mClassScope.pop();
+      } else if (qName.equals("package")) {
+        mApi.addPackage(mCurrentPackage);
+      }
+    }
+
+    public ApiInfo getApi() {
+      return mApi;
+    }
+    
+    private String qualifiedName(String pkg, String className, ClassInfo parent) {
+      String parentQName = (parent != null) ? (parent.qualifiedName() + ".") : "";
+        return pkg + "." + parentQName + className;
+    }
+  }
+  
+  public class Report {
+    private int code;
+    private Set<ErrorMessage> errors;
+    
+    private Report(int code, Set<ErrorMessage> errors) {
+      this.code = code;
+      this.errors = errors;
+    }
+    
+    public int code() {
+      return code;
+    }
+    
+    public Set<ErrorMessage> errors() {
+      return errors;
+    }
+  }
+}
diff --git a/src/com/google/doclava/apicheck/ApiInfo.java b/src/com/google/doclava/apicheck/ApiInfo.java
new file mode 100644
index 0000000..758942a
--- /dev/null
+++ b/src/com/google/doclava/apicheck/ApiInfo.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava.apicheck;
+
+import com.google.doclava.ClassInfo;
+import com.google.doclava.Errors;
+import com.google.doclava.PackageInfo;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ApiInfo {
+
+  private HashMap<String, PackageInfo> mPackages
+      = new HashMap<String, PackageInfo>();
+  private HashMap<String, ClassInfo> mAllClasses
+      = new HashMap<String, ClassInfo>();
+  private Map<ClassInfo,String> mClassToSuper
+      = new HashMap<ClassInfo, String>();
+  private Map<ClassInfo, ArrayList<String>> mClassToInterface
+      = new HashMap<ClassInfo, ArrayList<String>>();
+
+
+  public ClassInfo findClass(String name) {
+    return mAllClasses.get(name);
+  }
+
+  protected void resolveInterfaces() {
+    for (ClassInfo cl : mAllClasses.values()) {
+      ArrayList<String> ifaces = mClassToInterface.get(cl);
+      if (ifaces == null) {
+        continue;
+      }
+      for (String iface : ifaces) {
+        cl.addInterface(mAllClasses.get(iface));
+      }
+    }
+  }
+
+  /**
+   * Checks to see if this api is consistent with a newer version.
+   */
+  public boolean isConsistent(ApiInfo otherApi) {
+    boolean consistent = true;
+    for (PackageInfo pInfo : mPackages.values()) {
+      if (otherApi.getPackages().containsKey(pInfo.name())) {
+        if (!pInfo.isConsistent(otherApi.getPackages().get(pInfo.name()))) {
+          consistent = false;
+        }
+      } else {
+        Errors.error(Errors.REMOVED_PACKAGE, pInfo.position(), "Removed package " + pInfo.name());
+        consistent = false;
+      }
+    }
+    for (PackageInfo pInfo : otherApi.mPackages.values()) {
+      if (!mPackages.containsKey(pInfo.name())) {
+        Errors.error(Errors.ADDED_PACKAGE, pInfo.position(), "Added package " + pInfo.name());
+        consistent = false;
+      }
+    }
+    return consistent;
+  }
+
+  public HashMap<String, PackageInfo> getPackages() {
+    return mPackages;
+  }
+  
+  protected void mapClassToSuper(ClassInfo classInfo, String superclass) {
+    mClassToSuper.put(classInfo, superclass);
+  }
+  
+  protected void mapClassToInterface(ClassInfo classInfo, String iface) {
+    if (!mClassToInterface.containsKey(classInfo)) {
+      mClassToInterface.put(classInfo, new ArrayList<String>());
+    }
+    mClassToInterface.get(classInfo).add(iface);
+  }
+
+  protected void addPackage(PackageInfo pInfo) {
+    // track the set of organized packages in the API
+    mPackages.put(pInfo.name(), pInfo);
+
+    // accumulate a direct map of all the classes in the API
+    for (ClassInfo cl : pInfo.allClasses().values()) {
+      mAllClasses.put(cl.qualifiedName(), cl);
+    }
+  }
+
+  protected void resolveSuperclasses() {
+    for (ClassInfo cl : mAllClasses.values()) {
+      // java.lang.Object has no superclass
+      if (!cl.qualifiedName().equals("java.lang.Object")) {
+        String scName = mClassToSuper.get(cl);
+        if (scName == null) {
+          scName = "java.lang.Object";
+        }
+        ClassInfo superclass = mAllClasses.get(scName);
+        if (superclass == null) {
+          // Superclass not provided by this codebase. Inject a stub.
+          superclass = new ClassInfo(scName);
+        }
+        cl.setSuperClass(superclass);
+      }
+    }
+  }
+}
diff --git a/src/com/google/doclava/apicheck/ApiParseException.java b/src/com/google/doclava/apicheck/ApiParseException.java
new file mode 100644
index 0000000..cd8ad7f
--- /dev/null
+++ b/src/com/google/doclava/apicheck/ApiParseException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package com.google.doclava.apicheck;
+
+public final class ApiParseException extends Exception {
+  public ApiParseException(String message, Exception cause) {
+    super(message, cause);
+  }
+  
+  public ApiParseException() {
+    
+  }
+  
+  ApiParseException(String message) {
+    super(message);
+  }
+}
diff --git a/test/api/add-class.xml b/test/api/add-class.xml
new file mode 100644
index 0000000..4795229
--- /dev/null
+++ b/test/api/add-class.xml
@@ -0,0 +1,132 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Funk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Funk"
+ type="doclava.sample.Funk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+</class>
+</package>
+</api>
diff --git a/test/api/added-exception.xml b/test/api/added-exception.xml
new file mode 100644
index 0000000..306206c
--- /dev/null
+++ b/test/api/added-exception.xml
@@ -0,0 +1,295 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="thrower"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="MalformedURLException" type="java.net.MalformedURLException">
+</exception>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/added-field.xml b/test/api/added-field.xml
new file mode 100644
index 0000000..63a516a
--- /dev/null
+++ b/test/api/added-field.xml
@@ -0,0 +1,289 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+<field name="FOUR_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="4.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/added-interface.xml b/test/api/added-interface.xml
new file mode 100644
index 0000000..7902b18
--- /dev/null
+++ b/test/api/added-interface.xml
@@ -0,0 +1,115 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/added-package.xml b/test/api/added-package.xml
new file mode 100644
index 0000000..cdc869a
--- /dev/null
+++ b/test/api/added-package.xml
@@ -0,0 +1,490 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+<package name="doclava.sample.added"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/api.xml b/test/api/api.xml
new file mode 100644
index 0000000..9399797
--- /dev/null
+++ b/test/api/api.xml
@@ -0,0 +1,304 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="depra"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+</method>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="thrower"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="MalformedURLException" type="java.net.MalformedURLException">
+</exception>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-abstract.xml b/test/api/changed-abstract.xml
new file mode 100644
index 0000000..f6ced64
--- /dev/null
+++ b/test/api/changed-abstract.xml
@@ -0,0 +1,246 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-abstract2.xml b/test/api/changed-abstract2.xml
new file mode 100644
index 0000000..936f901
--- /dev/null
+++ b/test/api/changed-abstract2.xml
@@ -0,0 +1,246 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-class-info.xml b/test/api/changed-class-info.xml
new file mode 100644
index 0000000..742137e
--- /dev/null
+++ b/test/api/changed-class-info.xml
@@ -0,0 +1,269 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<interface name="Small"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</interface>
+</package>
+</api>
diff --git a/test/api/changed-class-info2.xml b/test/api/changed-class-info2.xml
new file mode 100644
index 0000000..63a1d17
--- /dev/null
+++ b/test/api/changed-class-info2.xml
@@ -0,0 +1,270 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-deprecated.xml b/test/api/changed-deprecated.xml
new file mode 100644
index 0000000..59e3dc1
--- /dev/null
+++ b/test/api/changed-deprecated.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-deprecated2.xml b/test/api/changed-deprecated2.xml
new file mode 100644
index 0000000..7befbf7
--- /dev/null
+++ b/test/api/changed-deprecated2.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-deprecated3.xml b/test/api/changed-deprecated3.xml
new file mode 100644
index 0000000..96a2e91
--- /dev/null
+++ b/test/api/changed-deprecated3.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-final.xml b/test/api/changed-final.xml
new file mode 100644
index 0000000..5976ba5
--- /dev/null
+++ b/test/api/changed-final.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-final2.xml b/test/api/changed-final2.xml
new file mode 100644
index 0000000..1ac7603
--- /dev/null
+++ b/test/api/changed-final2.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-final3.xml b/test/api/changed-final3.xml
new file mode 100644
index 0000000..b6fc9aa
--- /dev/null
+++ b/test/api/changed-final3.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-native.xml b/test/api/changed-native.xml
new file mode 100644
index 0000000..8b03a96
--- /dev/null
+++ b/test/api/changed-native.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-scope.xml b/test/api/changed-scope.xml
new file mode 100644
index 0000000..e3fafae
--- /dev/null
+++ b/test/api/changed-scope.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-scope2.xml b/test/api/changed-scope2.xml
new file mode 100644
index 0000000..e91a126
--- /dev/null
+++ b/test/api/changed-scope2.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="private"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-scope3.xml b/test/api/changed-scope3.xml
new file mode 100644
index 0000000..daa8632
--- /dev/null
+++ b/test/api/changed-scope3.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-scope4.xml b/test/api/changed-scope4.xml
new file mode 100644
index 0000000..ca0b6dc
--- /dev/null
+++ b/test/api/changed-scope4.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-static.xml b/test/api/changed-static.xml
new file mode 100644
index 0000000..5381417
--- /dev/null
+++ b/test/api/changed-static.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-static2.xml b/test/api/changed-static2.xml
new file mode 100644
index 0000000..b2a4837
--- /dev/null
+++ b/test/api/changed-static2.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-static3.xml b/test/api/changed-static3.xml
new file mode 100644
index 0000000..dd43ec3
--- /dev/null
+++ b/test/api/changed-static3.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-super.xml b/test/api/changed-super.xml
new file mode 100644
index 0000000..eb98cb4
--- /dev/null
+++ b/test/api/changed-super.xml
@@ -0,0 +1,115 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-synchronized.xml b/test/api/changed-synchronized.xml
new file mode 100644
index 0000000..111a047
--- /dev/null
+++ b/test/api/changed-synchronized.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-transient.xml b/test/api/changed-transient.xml
new file mode 100644
index 0000000..0527dd3
--- /dev/null
+++ b/test/api/changed-transient.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="true"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-type.xml b/test/api/changed-type.xml
new file mode 100644
index 0000000..cc3e217
--- /dev/null
+++ b/test/api/changed-type.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="float"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-value.xml b/test/api/changed-value.xml
new file mode 100644
index 0000000..78a1121
--- /dev/null
+++ b/test/api/changed-value.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50005"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-value2.xml b/test/api/changed-value2.xml
new file mode 100644
index 0000000..74de2bf
--- /dev/null
+++ b/test/api/changed-value2.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="18"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/changed-volatile.xml b/test/api/changed-volatile.xml
new file mode 100644
index 0000000..f061460
--- /dev/null
+++ b/test/api/changed-volatile.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="true"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/constants.xml b/test/api/constants.xml
new file mode 100644
index 0000000..688f935
--- /dev/null
+++ b/test/api/constants.xml
@@ -0,0 +1,278 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/medium.xml b/test/api/medium.xml
new file mode 100644
index 0000000..2cf8e3a
--- /dev/null
+++ b/test/api/medium.xml
@@ -0,0 +1,246 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/parameter-changed-1.xml b/test/api/parameter-changed-1.xml
new file mode 100644
index 0000000..691ddd2
--- /dev/null
+++ b/test/api/parameter-changed-1.xml
@@ -0,0 +1,33 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/parameter-changed-2.xml b/test/api/parameter-changed-2.xml
new file mode 100644
index 0000000..f480934
--- /dev/null
+++ b/test/api/parameter-changed-2.xml
@@ -0,0 +1,35 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="java.lang.Integer">
+</parameter>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/parameter-changed-3.xml b/test/api/parameter-changed-3.xml
new file mode 100644
index 0000000..d91572b
--- /dev/null
+++ b/test/api/parameter-changed-3.xml
@@ -0,0 +1,35 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/removed-exception.xml b/test/api/removed-exception.xml
new file mode 100644
index 0000000..46f625b
--- /dev/null
+++ b/test/api/removed-exception.xml
@@ -0,0 +1,291 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="thrower"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/api/removed-interface.xml b/test/api/removed-interface.xml
new file mode 100644
index 0000000..7951c72
--- /dev/null
+++ b/test/api/removed-interface.xml
@@ -0,0 +1,244 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/return-type-changed-1.xml b/test/api/return-type-changed-1.xml
new file mode 100644
index 0000000..7902b18
--- /dev/null
+++ b/test/api/return-type-changed-1.xml
@@ -0,0 +1,115 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/return-type-changed-2.xml b/test/api/return-type-changed-2.xml
new file mode 100644
index 0000000..e12e880
--- /dev/null
+++ b/test/api/return-type-changed-2.xml
@@ -0,0 +1,115 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/simple.xml b/test/api/simple.xml
new file mode 100644
index 0000000..7902b18
--- /dev/null
+++ b/test/api/simple.xml
@@ -0,0 +1,115 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+</class>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/api/throws.xml b/test/api/throws.xml
new file mode 100644
index 0000000..068bf54
--- /dev/null
+++ b/test/api/throws.xml
@@ -0,0 +1,293 @@
+<api>
+<package name="doclava.sample"
+>
+<class name="Abstract"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Abstract"
+ type="doclava.sample.Abstract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="me"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Bunk"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Bunk"
+ type="doclava.sample.Bunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="sunk"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="DeBunk"
+ extends="doclava.sample.Bunk"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeBunk"
+ type="doclava.sample.DeBunk"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="gunk"
+ return="java.lang.Integer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="args" type="int...">
+</parameter>
+</method>
+<method name="thrower"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="MalformedURLException" type="java.net.MalformedURLException">
+</exception>
+</method>
+</class>
+<class name="Extender"
+ extends="doclava.sample.Abstract"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="doclava.sample.Face">
+</implements>
+<constructor name="Extender"
+ type="doclava.sample.Extender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="RAW_DEAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TREE_FITTY"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="3.50001"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<interface name="Face"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="returnObject"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
+<class name="Foo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Foo"
+ type="doclava.sample.Foo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get1"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="nothing"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="Small"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Small"
+ type="doclava.sample.Small"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="doclava.sample.Small"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SEVENTEEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/doclava/ApiCheckTest.java b/test/doclava/ApiCheckTest.java
new file mode 100644
index 0000000..af4918d
--- /dev/null
+++ b/test/doclava/ApiCheckTest.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.
+ */
+
+package doclava;
+
+import com.google.doclava.Errors;
+import com.google.doclava.Errors.Error;
+import com.google.doclava.Errors.ErrorMessage;
+import com.google.doclava.apicheck.ApiCheck;
+import com.google.doclava.apicheck.ApiCheck.Report;
+
+import junit.framework.TestCase;
+
+import java.util.Iterator;
+
+public class ApiCheckTest extends TestCase {
+  /**
+   * Clear all errors and make sure all future errors will be recorded.
+   */
+  public void setUp() {
+    Errors.clearErrors();
+    for (Errors.Error error : Errors.ERRORS) {
+      Errors.setErrorLevel(error.code, Errors.ERROR);
+    }
+  }
+  
+  public void testEquivalentApi() {
+    String[] args = { "test/api/medium.xml", "test/api/medium.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(report.errors().size(), 0);
+  }
+  
+  public void testMethodReturnTypeChanged() {
+    String[] args = { "test/api/return-type-changed-1.xml", "test/api/return-type-changed-2.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_TYPE, report.errors().iterator().next().error());
+  }
+  
+  public void testMethodParameterChanged() {
+    String[] args = { "test/api/parameter-changed-1.xml", "test/api/parameter-changed-2.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(2, report.errors().size());
+    
+    Iterator<ErrorMessage> errors = report.errors().iterator();
+    ErrorMessage m1 = errors.next();
+    ErrorMessage m2 = errors.next();
+    assertNotSame(m1.error(), m2.error());
+    assertTrue(m1.error().equals(Errors.ADDED_METHOD) || m1.error().equals(Errors.REMOVED_METHOD));
+    assertTrue(m2.error().equals(Errors.ADDED_METHOD) || m2.error().equals(Errors.REMOVED_METHOD));
+  }
+  
+  public void testConstructorParameterChanged() {
+    String[] args = { "test/api/parameter-changed-1.xml", "test/api/parameter-changed-3.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(2, report.errors().size());
+    Iterator<ErrorMessage> errors = report.errors().iterator();
+    ErrorMessage m1 = errors.next();
+    ErrorMessage m2 = errors.next();
+    assertNotSame(m1.error(), m2.error());
+    assertTrue(m1.error().equals(Errors.ADDED_METHOD) || m1.error().equals(Errors.REMOVED_METHOD));
+    assertTrue(m2.error().equals(Errors.ADDED_METHOD) || m2.error().equals(Errors.REMOVED_METHOD));
+  }
+  
+  public void testAddedClass() {
+    String[] args = { "test/api/simple.xml", "test/api/add-class.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.ADDED_CLASS, report.errors().iterator().next().error());
+  }
+  
+  public void testRemovedClass() {
+    String[] args = { "test/api/add-class.xml", "test/api/simple.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.REMOVED_CLASS, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedSuper() {
+    String[] args = { "test/api/simple.xml", "test/api/changed-super.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_SUPERCLASS, report.errors().iterator().next().error());
+  }
+  
+  public void testAddedInterface() {
+    String[] args = { "test/api/removed-interface.xml", "test/api/medium.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.ADDED_INTERFACE, report.errors().iterator().next().error());
+  }
+  
+  public void testRemovedInterface() {
+    String[] args = { "test/api/medium.xml", "test/api/removed-interface.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.REMOVED_INTERFACE, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedAbstractClass() {
+    String[] args = { "test/api/medium.xml", "test/api/changed-abstract.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_ABSTRACT, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedAbstractClass2() {
+    String[] args = { "test/api/changed-abstract.xml", "test/api/medium.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_ABSTRACT, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedAbstractMethod() {
+    String[] args = { "test/api/medium.xml", "test/api/changed-abstract2.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_ABSTRACT, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedAbstractMethod2() {
+    String[] args = { "test/api/changed-abstract2.xml", "test/api/medium.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_ABSTRACT, report.errors().iterator().next().error());
+  }
+  
+  public void testAddedPackage() {
+    String[] args = { "test/api/medium.xml", "test/api/added-package.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.ADDED_PACKAGE, report.errors().iterator().next().error());
+  }
+  
+  public void testRemovedPackage() {
+    String[] args = { "test/api/added-package.xml", "test/api/medium.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.REMOVED_PACKAGE, report.errors().iterator().next().error());
+  }
+    
+  public void testChangedValue() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-value.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_VALUE, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedValue2() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-value2.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_VALUE, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedType() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-type.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_TYPE, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedFinalField() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-final.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_FINAL, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedFinalMethod() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-final2.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_FINAL, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedFinalClass() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-final3.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_FINAL, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedFinalClass2() {
+    String[] args = { "test/api/changed-final3.xml", "test/api/constants.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_FINAL, report.errors().iterator().next().error());
+  }
+  
+  public void testAddedField() {
+    String[] args = { "test/api/constants.xml", "test/api/added-field.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.ADDED_FIELD, report.errors().iterator().next().error());
+  }
+  
+  public void testRemovedField() {
+    String[] args = { "test/api/added-field.xml", "test/api/constants.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.REMOVED_FIELD, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedStaticMethod() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-static.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_STATIC, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedStaticClass() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-static2.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_STATIC, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedStaticField() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-static3.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_STATIC, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedTransient() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-transient.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_TRANSIENT, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedSynchronized() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-synchronized.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_SYNCHRONIZED, report.errors().iterator().next().error());
+  }
+
+  public void testChangedVolatile() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-volatile.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_VOLATILE, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedNative() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-native.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_NATIVE, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedScopeMethod() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-scope.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_SCOPE, report.errors().iterator().next().error());
+  }
+
+  public void testChangedScopeClass() {
+    String[] args = { "test/api/changed-scope.xml", "test/api/constants.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_SCOPE, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedScopeClass2() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-scope2.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_SCOPE, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedScopeField() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-scope3.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_SCOPE, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedConstructorScope() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-scope4.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_SCOPE, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedMethodThrows() {
+    String[] args = { "test/api/throws.xml", "test/api/removed-exception.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_THROWS, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedMethodThrows2() {
+    String[] args = { "test/api/removed-exception.xml", "test/api/throws.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_THROWS, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedConstructorThrows() {
+    String[] args = { "test/api/throws.xml", "test/api/added-exception.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_THROWS, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedConstructorThrows2() {
+    String[] args = { "test/api/added-exception.xml", "test/api/throws.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_THROWS, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedMethodDeprecated() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-deprecated.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_DEPRECATED, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedConstructorDeprecated() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-deprecated2.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_DEPRECATED, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedFieldDeprecated() {
+    String[] args = { "test/api/constants.xml", "test/api/changed-deprecated3.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_DEPRECATED, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedClassToInterface() {
+    String[] args = { "test/api/changed-class-info2.xml", "test/api/changed-class-info.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_CLASS, report.errors().iterator().next().error());
+  }
+  
+  public void testChangedInterfaceToClass() {
+    String[] args = { "test/api/changed-class-info.xml", "test/api/changed-class-info2.xml" };
+    ApiCheck apiCheck = new ApiCheck();
+    Report report = apiCheck.checkApi(args);
+    assertEquals(1, report.errors().size());
+    assertEquals(Errors.CHANGED_CLASS, report.errors().iterator().next().error());
+  }
+}
\ No newline at end of file