Update Caliper to r71.
diff --git a/build.xml b/build.xml
index a1584b0..2d52200 100644
--- a/build.xml
+++ b/build.xml
@@ -1,104 +1,103 @@
 <?xml version="1.0"?>
 
-<project name="caliper" default="compile">
-
-    <property environment="env"/>
-
+<project name="caliper" default="install">
     <!-- can be overridden at the command line with -Dversion=
          or in IDEA, in the ant properties dialog -->
-    <property name="version" value="snapshot"/>
+    <property name="version" value="0.0"/> <!-- subversion revision? -->
 
-    <path id="compile.classpath">
-        <pathelement location="lib/google-collect-1.0-rc4.jar"/>
+    <property name="frameworkclasses" value="build/classes/framework"/>
+    <property name="otherclasses" value="build/classes/other"/>
+    <property name="installroot" value="build/caliper-${version}"/>
+    <property name="javadocroot" value="${installroot}/docs/api"/>
+    <property name="collections" value="lib/google-collect-1.0-rc4.jar"/>
+
+    <path id="dependencies">
+        <pathelement location="${collections}"/>
     </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">
-            <classpath refid="compile.classpath"/>
-        </javac>
-        <copy toDir="build/classes">
-            <fileset dir="src" excludes="**/*.java"/>
-        </copy>
-    </target>
+    <path id="testdependencies">
+        <path refid="dependencies"/>
+        <pathelement location="${frameworkclasses}"/>
+        <pathelement location="lib/junit.jar"/>
+    </path>
 
-    <target name="test.compile"
-            depends="compile"
-            description="Compile test source.">
-        <mkdir dir="build/test"/>
-        <javac srcdir="test"
+    <target name="compile"
+            description="Compile all Java source code">
+        <mkdir dir="${frameworkclasses}"/>
+        <javac srcdir="src"
+               includes="com/**"
+               destdir="${frameworkclasses}"
                debug="on"
-               destdir="build/test"
+               source="1.5"
+               target="1.5"
+               classpathref="dependencies">
+            <compilerarg value="-Xlint"/>
+            <!--compilerarg value="-Werror"/-->
+        </javac>
+
+        <mkdir dir="${otherclasses}"/>
+        <javac srcdir="src"
+               excludes="com/**"
+               debug="on"
+               destdir="${otherclasses}"
                source="1.5"
                target="1.5">
+            <compilerarg value="-Xlint"/>
+            <!--compilerarg value="-Werror"/-->
             <classpath>
-                <pathelement location="build/classes"/>
-                <pathelement location="lib/google-collect-1.0-rc4.jar"/>
-                <pathelement location="lib/junit.jar"/>
+                <path refid="testdependencies"/>
             </classpath>
         </javac>
-        <copy toDir="build/test">
-            <fileset dir="test" excludes="**/*.java"/>
-        </copy>
     </target>
 
     <target name="test"
-            depends="test.compile"
-            description="Execute JUnit tests.">
-        <java fork="true"
-              classname="junit.textui.TestRunner"
-              failonerror="true"
-              taskname="junit">
+            depends="compile"
+            description="Run unit tests">
+        <junit fork="true"
+               haltonfailure="true">
             <classpath>
-                <pathelement location="build/test"/>
-                <pathelement location="build/classes"/>
-                <pathelement location="lib/junit.jar"/>
-                <pathelement location="lib/google-collect-1.0-rc4.jar"/>
+                <pathelement location="${otherclasses}"/>
+                <path refid="testdependencies"/>
             </classpath>
-            <arg value="com.google.caliper.AllTests" />
-        </java>
+            <batchtest>
+              <fileset dir="src">
+                <include name="test/*Test.java"/>
+              </fileset>
+            </batchtest>
+
+        </junit>
     </target>
 
-    <target name="clean"
-            description="Remove generated files.">
-        <delete dir="build"/>
-    </target>
+    <target name="buildjar"
+            depends="compile"
+            description="Build JAR archive of caliper framework">
+        <mkdir dir="${installroot}/lib"/>
 
-    <target name="jar" depends="compile" description="Build jars.">
-        <mkdir dir="build/dist"/>
-        <mkdir dir="build/dist/caliper-${version}"/>
-        <jar jarfile="build/dist/caliper-${version}/caliper-${version}.jar">
-            <fileset dir="build/classes"/>
-        </jar>
-    </target>
+        <taskdef name="jarjar"
+                 classname="com.tonicsystems.jarjar.JarJarTask"
+                 classpath="lib/jarjar-1.0rc8.jar"/>
 
-    <target name="jarsrc" description="Build jar of source.">
-        <jar jarfile="build/dist/caliper-${version}/src-${version}.zip">
-            <fileset dir="src"/>
-        </jar>
-    </target>
+        <jarjar jarfile="${installroot}/lib/caliper-${version}.jar">
+            <fileset dir="${frameworkclasses}"/>
+            <zipfileset src="${collections}"/>
+            <rule pattern="com.google.common.**" result="com.google.caliper.internal.guava.@1"/>
+            <keep pattern="com.google.caliper.**"/>
 
-    <target name="dist" depends="jar, jarsrc, javadoc"
-            description="Build entire distribution.">
-        <copy toDir="build/dist/caliper-${version}" file="COPYING"/>
-        <copy toDir="build/dist/caliper-${version}">
-            <fileset dir="build" includes="javadoc/**/*"/>
-        </copy>
-
-        <zip destfile="build/caliper-${version}.zip"
-             basedir="build/dist"/>
+            <!-- include some files for GWT's benefit -->
+            <zipfileset dir="src">
+                <include name="com/google/caliper/Run.java"/>
+                <include name="com/google/caliper/Scenario.java"/>
+                <include name="CaliperCore.gwt.xml" />
+            </zipfileset>
+        </jarjar>
     </target>
 
     <target name="javadoc"
-            description="Generate Javadocs.">
-        <delete dir="build/javadoc"/>
-        <mkdir dir="build/javadoc"/>
+            description="Generate API documentation to ${javadocroot}">
+        <delete dir="${javadocroot}"/> <!-- TODO: figure out how to make this more incremental -->
+        <mkdir dir="${javadocroot}"/>
         <javadoc packagenames="com.google.caliper"
-                 destdir="build/javadoc"
+                 destdir="${javadocroot}"
                  use="true"
                  author="true"
                  protected="true"
@@ -106,9 +105,44 @@
             <sourcepath>
                 <pathelement location="src"/>
             </sourcepath>
-            <classpath refid="compile.classpath"/>
+            <classpath refid="dependencies"/>
             <link href="http://google-collections.googlecode.com/svn/trunk/javadoc/"/>
             <link href="http://java.sun.com/javase/6/docs/api"/>
         </javadoc>
     </target>
+
+    <target name="install" depends="buildjar, javadoc"
+            description="Create a complete installation tree in ./build/caliper-*">
+        <mkdir dir="${installroot}"/>
+        <zip zipfile="${installroot}/src-${version}.zip">
+            <fileset dir="src"/>
+        </zip>
+
+        <copy toDir="${installroot}" file="COPYING"/>
+        <copy toDir="${installroot}" file="src/scripts/caliper">
+            <filterset>
+                <filter token="VERSION" value="${version}"/>
+            </filterset>
+        </copy>
+        <chmod perm="ugo=rx" file="${installroot}/caliper"/>
+    </target>
+
+    <target name="dist"
+            depends="install"
+            description="Create a zipped distribution for upload to Google Code">
+        <zip destfile="build/caliper-${version}.zip">
+            <zipfileset dir="build/caliper-${version}"
+                        excludes="caliper"
+                        prefix="caliper-${version}"/>
+            <zipfileset file="build/caliper-${version}/caliper" 
+                        prefix="caliper-${version}"
+                        filemode="555"/>
+        </zip>
+    </target>
+
+    <target name="clean"
+            description="Remove all generated files.">
+        <delete dir="build"/>
+    </target>
+
 </project>
diff --git a/caliper.iml b/caliper.iml
new file mode 100644
index 0000000..70039aa
--- /dev/null
+++ b/caliper.iml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/ideabuild/framework" />
+    <output-test url="file://$MODULE_DIR$/ideabuild/other" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/com" isTestSource="false" packagePrefix="com" />
+      <sourceFolder url="file://$MODULE_DIR$/src/examples" isTestSource="true" packagePrefix="examples" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test" isTestSource="true" packagePrefix="test" />
+      <sourceFolder url="file://$MODULE_DIR$/src/tutorial" isTestSource="true" packagePrefix="tutorial" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/google-collect-1.0-rc4.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" scope="TEST">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/junit.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+  </component>
+</module>
+
diff --git a/caliper.ipr b/caliper.ipr
index f4e0208..80e7392 100644
--- a/caliper.ipr
+++ b/caliper.ipr
@@ -1,15 +1,79 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project relativePaths="false" version="4">
+<project version="4">
   <component name="AntConfiguration">
     <defaultAnt bundledAnt="true" />
-  </component>
-  <component name="BuildJarProjectSettings">
-    <option name="BUILD_JARS_ON_MAKE" value="false" />
+    <buildFile url="file://$PROJECT_DIR$/build.xml">
+      <additionalClassPath />
+      <antReference projectDefault="true" />
+      <customJdkName value="" />
+      <maximumHeapSize value="128" />
+      <maximumStackSize value="2" />
+      <properties />
+    </buildFile>
   </component>
   <component name="CodeStyleSettingsManager">
     <option name="PER_PROJECT_SETTINGS">
       <value>
-        <ADDITIONAL_INDENT_OPTIONS fileType="java">
+        <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
+        <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+        <option name="ALIGN_MULTILINE_FOR" value="false" />
+        <option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
+        <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
+        <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
+        <option name="BLANK_LINES_BEFORE_PACKAGE" value="1" />
+        <option name="BLANK_LINES_AROUND_CLASS" value="0" />
+        <option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
+        <option name="USE_FQ_CLASS_NAMES_IN_JAVADOC" value="false" />
+        <option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
+        <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
+        <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
+        <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
+          <value />
+        </option>
+        <option name="IMPORT_LAYOUT_TABLE">
+          <value>
+            <package name="" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="" withSubpackages="true" static="true" />
+          </value>
+        </option>
+        <option name="RIGHT_MARGIN" value="100" />
+        <option name="CALL_PARAMETERS_WRAP" value="1" />
+        <option name="METHOD_PARAMETERS_WRAP" value="1" />
+        <option name="EXTENDS_LIST_WRAP" value="1" />
+        <option name="THROWS_LIST_WRAP" value="1" />
+        <option name="EXTENDS_KEYWORD_WRAP" value="1" />
+        <option name="THROWS_KEYWORD_WRAP" value="1" />
+        <option name="METHOD_CALL_CHAIN_WRAP" value="1" />
+        <option name="BINARY_OPERATION_WRAP" value="1" />
+        <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
+        <option name="TERNARY_OPERATION_WRAP" value="1" />
+        <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
+        <option name="KEEP_SIMPLE_BLOCKS_IN_ONE_LINE" value="true" />
+        <option name="FOR_STATEMENT_WRAP" value="1" />
+        <option name="ARRAY_INITIALIZER_WRAP" value="1" />
+        <option name="ASSIGNMENT_WRAP" value="1" />
+        <option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
+        <option name="LABELED_STATEMENT_WRAP" value="1" />
+        <option name="WRAP_COMMENTS" value="true" />
+        <option name="ASSERT_STATEMENT_WRAP" value="1" />
+        <option name="IF_BRACE_FORCE" value="3" />
+        <option name="DOWHILE_BRACE_FORCE" value="3" />
+        <option name="WHILE_BRACE_FORCE" value="3" />
+        <option name="FOR_BRACE_FORCE" value="3" />
+        <option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
+        <option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
+        <option name="JD_P_AT_EMPTY_LINES" value="false" />
+        <option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
+        <option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
+        <option name="JD_KEEP_EMPTY_RETURN" value="false" />
+        <option name="METHOD_ANNOTATION_WRAP" value="5" />
+        <option name="CLASS_ANNOTATION_WRAP" value="5" />
+        <option name="FIELD_ANNOTATION_WRAP" value="5" />
+        <option name="PARAMETER_ANNOTATION_WRAP" value="1" />
+        <option name="VARIABLE_ANNOTATION_WRAP" value="1" />
+        <option name="ENUM_CONSTANTS_WRAP" value="2" />
+        <ADDITIONAL_INDENT_OPTIONS fileType="">
           <option name="INDENT_SIZE" value="4" />
           <option name="CONTINUATION_INDENT_SIZE" value="8" />
           <option name="TAB_SIZE" value="4" />
@@ -18,8 +82,8 @@
           <option name="LABEL_INDENT_SIZE" value="0" />
           <option name="LABEL_INDENT_ABSOLUTE" value="false" />
         </ADDITIONAL_INDENT_OPTIONS>
-        <ADDITIONAL_INDENT_OPTIONS fileType="jsp">
-          <option name="INDENT_SIZE" value="4" />
+        <ADDITIONAL_INDENT_OPTIONS fileType="groovy">
+          <option name="INDENT_SIZE" value="2" />
           <option name="CONTINUATION_INDENT_SIZE" value="8" />
           <option name="TAB_SIZE" value="4" />
           <option name="USE_TAB_CHARACTER" value="false" />
@@ -27,6 +91,15 @@
           <option name="LABEL_INDENT_SIZE" value="0" />
           <option name="LABEL_INDENT_ABSOLUTE" value="false" />
         </ADDITIONAL_INDENT_OPTIONS>
+        <ADDITIONAL_INDENT_OPTIONS fileType="java">
+          <option name="INDENT_SIZE" value="2" />
+          <option name="CONTINUATION_INDENT_SIZE" value="4" />
+          <option name="TAB_SIZE" value="2" />
+          <option name="USE_TAB_CHARACTER" value="false" />
+          <option name="SMART_TABS" value="false" />
+          <option name="LABEL_INDENT_SIZE" value="0" />
+          <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+        </ADDITIONAL_INDENT_OPTIONS>
         <ADDITIONAL_INDENT_OPTIONS fileType="xml">
           <option name="INDENT_SIZE" value="4" />
           <option name="CONTINUATION_INDENT_SIZE" value="8" />
@@ -38,90 +111,590 @@
         </ADDITIONAL_INDENT_OPTIONS>
       </value>
     </option>
-    <option name="USE_PER_PROJECT_SETTINGS" value="false" />
+    <option name="USE_PER_PROJECT_SETTINGS" value="true" />
   </component>
   <component name="CompilerConfiguration">
     <option name="DEFAULT_COMPILER" value="Javac" />
-    <option name="DEPLOY_AFTER_MAKE" value="0" />
     <resourceExtensions>
       <entry name=".+\.(properties|xml|html|dtd|tld)" />
       <entry name=".+\.(gif|png|jpeg|jpg)" />
     </resourceExtensions>
-    <wildcardResourcePatterns>
-      <entry name="?*.properties" />
-      <entry name="?*.xml" />
-      <entry name="?*.gif" />
-      <entry name="?*.png" />
-      <entry name="?*.jpeg" />
-      <entry name="?*.jpg" />
-      <entry name="?*.html" />
-      <entry name="?*.dtd" />
-      <entry name="?*.tld" />
-      <entry name="?*.ftl" />
-    </wildcardResourcePatterns>
+    <wildcardResourcePatterns />
+    <annotationProcessing enabled="false" useClasspath="true" />
   </component>
-  <component name="CopyrightManager" default="">
+  <component name="CopyrightManager" default="Apache 2.0/Google">
+    <copyright>
+      <option name="notice" value="Copyright (C) &amp;#36;today.year Google Inc.&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10;http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
+      <option name="keyword" value="Copyright" />
+      <option name="allowReplaceKeyword" value="Copyright" />
+      <option name="myName" value="Apache 2.0/Google" />
+      <option name="myLocal" value="true" />
+    </copyright>
     <module2copyright />
   </component>
   <component name="DependencyValidationManager">
     <option name="SKIP_IMPORT_STATEMENTS" value="false" />
   </component>
-  <component name="EclipseCompilerSettings">
-    <option name="DEBUGGING_INFO" value="true" />
-    <option name="GENERATE_NO_WARNINGS" value="true" />
-    <option name="DEPRECATION" value="false" />
-    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
-    <option name="MAXIMUM_HEAP_SIZE" value="128" />
+  <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" defaultCharsetForPropertiesFiles="UTF-8">
+    <file url="file://$PROJECT_DIR$" charset="UTF-8" />
+    <file url="PROJECT" charset="UTF-8" />
   </component>
-  <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
+  <component name="EntryPointsManager">
+    <entry_points version="2.0" />
+  </component>
   <component name="InspectionProjectProfileManager">
-    <option name="PROJECT_PROFILE" value="Project Default" />
-    <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
-    <scopes />
     <profiles>
       <profile version="1.0" is_locked="false">
         <option name="myName" value="Project Default" />
         <option name="myLocal" value="false" />
-        <inspection_tool class="CloneDeclaresCloneNotSupported" level="WARNING" enabled="false" />
-        <inspection_tool class="JavaDoc" level="WARNING" enabled="false">
+        <inspection_tool class="AbstractMethodCallInConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="AbstractMethodOverridesAbstractMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="AccessToNonThreadSafeStaticFieldFromInstance" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="nonThreadSafeTypes" value="java.text.DateFormat,java.util.Calendar" />
+        </inspection_tool>
+        <inspection_tool class="AccessToStaticFieldLockedOnInstance" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="AmbiguousMethodCall" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="AnonymousClassVariableHidesContainingMethodVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ArchaicSystemPropertyAccess" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ArithmeticOnVolatileField" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="AssertEqualsMayBeAssertSame" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="AssertStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="AssignmentToCatchBlockParameter" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="AssignmentToCollectionFieldFromParameter" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignorePrivateMethods" value="true" />
+        </inspection_tool>
+        <inspection_tool class="AssignmentToDateFieldFromParameter" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignorePrivateMethods" value="true" />
+        </inspection_tool>
+        <inspection_tool class="AssignmentToForLoopParameter" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_checkForeachParameters" value="false" />
+        </inspection_tool>
+        <inspection_tool class="AssignmentToMethodParameter" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreTransformationOfOriginalParameter" value="false" />
+        </inspection_tool>
+        <inspection_tool class="AssignmentToStaticFieldFromInstanceMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="AssignmentUsedAsCondition" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="AwaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="AwaitWithoutCorrespondingSignal" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="BadOddness" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="BeforeClassOrAfterClassIsPublicStaticVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="BeforeOrAfterIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="BigDecimalEquals" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="BooleanMethodIsAlwaysInverted" enabled="false" level="WARNING" enabled_by_default="false" />
+        <inspection_tool class="BusyWait" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="CStyleArrayDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="CachedNumberConstructorCall" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="CallToNativeMethodWhileLocked" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="CallToStringConcatCanBeReplacedByOperator" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="CastConflictsWithInstanceof" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="CastThatLosesPrecision" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreIntegerCharCasts" value="false" />
+        </inspection_tool>
+        <inspection_tool class="CastToIncompatibleInterface" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ChainedEquality" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="CheckEmptyScriptTag" enabled="false" level="WARNING" enabled_by_default="false" />
+        <inspection_tool class="CheckValidXmlInScriptTagBody" enabled="false" level="ERROR" enabled_by_default="false" />
+        <inspection_tool class="ClassEscapesItsScope" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ClassInTopLevelPackage" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ClassInitializer" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ClassNameDiffersFromFileName" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ClassNewInstance" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ClassWithMultipleLoggers" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="loggerClassName" value="java.util.logging.Logger" />
+        </inspection_tool>
+        <inspection_tool class="CloneCallsSuperClone" enabled="false" level="WARNING" enabled_by_default="false" />
+        <inspection_tool class="CloneDeclaresCloneNotSupported" enabled="false" level="WARNING" enabled_by_default="false" />
+        <inspection_tool class="CollectionAddedToSelf" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="CollectionsFieldAccessReplaceableByMethodCall" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ComparableImplementedButEqualsNotOverridden" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ComparatorNotSerializable" enabled="true" level="INFO" enabled_by_default="true" />
+        <inspection_tool class="CompareToUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ComparisonOfShortAndChar" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ComparisonToNaN" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ConditionSignal" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ConditionalExpressionWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ConfusingElse" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ConfusingFloatingPointLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ConfusingOctalEscape" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ConstantAssertCondition" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ConstantJUnitAssertArgument" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ConstantMathCall" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ConstantOnLHSOfComparison" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ConstantStringIntern" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ConstantValueVariableUse" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ControlFlowStatementWithoutBraces" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="CovariantEquals" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="DefaultNotLastCaseInSwitch" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="DivideByZero" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="DoubleCheckedLocking" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreOnVolatileVariables" value="false" />
+        </inspection_tool>
+        <inspection_tool class="DoubleNegation" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="DuplicateBooleanBranch" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="DuplicateCondition" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreMethodCalls" value="false" />
+        </inspection_tool>
+        <inspection_tool class="DynamicRegexReplaceableByCompiledPattern" enabled="true" level="INFO" enabled_by_default="true" />
+        <inspection_tool class="EmptyInitializer" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="EmptySynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="EnumerationCanBeIteration" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="EqualsAndHashcode" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="EqualsHashCodeCalledOnUrl" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="EqualsUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ExceptionFromCatchWhichDoesntWrap" enabled="false" level="WARNING" enabled_by_default="false">
+          <option name="ignoreGetMessage" value="true" />
+        </inspection_tool>
+        <inspection_tool class="ExtendsThread" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ExtendsUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ExternalizableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="FallthruInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="FieldAccessedSynchronizedAndUnsynchronized" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="countGettersAndSetters" value="false" />
+        </inspection_tool>
+        <inspection_tool class="FieldHidesSuperclassField" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignoreInvisibleFields" value="true" />
+        </inspection_tool>
+        <inspection_tool class="FieldMayBeFinal" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="FinalMethodInFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="FinalStaticMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+        <inspection_tool class="Finalize" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="FinalizeNotProtected" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="FloatingPointEquality" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ForLoopReplaceableByWhile" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignoreLoopsWithoutConditions" value="false" />
+        </inspection_tool>
+        <inspection_tool class="ForLoopThatDoesntUseLoopVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="HardcodedLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="HashCodeUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="HtmlExtraClosingTag" enabled="false" level="ERROR" enabled_by_default="false" />
+        <inspection_tool class="HtmlUnknownAttribute" enabled="false" level="WARNING" enabled_by_default="false">
+          <option name="myValues">
+            <value>
+              <list size="0" />
+            </value>
+          </option>
+          <option name="myCustomValuesEnabled" value="true" />
+        </inspection_tool>
+        <inspection_tool class="HtmlUnknownTag" enabled="false" level="WARNING" enabled_by_default="false">
+          <option name="myValues">
+            <value>
+              <list size="4">
+                <item index="0" class="java.lang.String" itemvalue="nobr" />
+                <item index="1" class="java.lang.String" itemvalue="noembed" />
+                <item index="2" class="java.lang.String" itemvalue="comment" />
+                <item index="3" class="java.lang.String" itemvalue="noscript" />
+              </list>
+            </value>
+          </option>
+          <option name="myCustomValuesEnabled" value="true" />
+        </inspection_tool>
+        <inspection_tool class="IOResource" enabled="true" level="INFO" enabled_by_default="true" />
+        <inspection_tool class="IfMayBeConditional" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="IfStatementWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ImplicitNumericConversion" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreWideningConversions" value="true" />
+          <option name="ignoreCharConversions" value="false" />
+          <option name="ignoreConstantConversions" value="false" />
+        </inspection_tool>
+        <inspection_tool class="InconsistentLanguageLevel" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="IndexOfReplaceableByContains" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="InnerClassVariableHidesOuterClassVariable" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignoreInvisibleFields" value="true" />
+        </inspection_tool>
+        <inspection_tool class="InstanceVariableUninitializedUse" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignorePrimitives" value="false" />
+        </inspection_tool>
+        <inspection_tool class="InstanceofCatchParameter" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="InstanceofIncompatibleInterface" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="InstanceofThis" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="InstantiationOfUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="IntLiteralMayBeLongLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="IntegerDivisionInFloatingPointContext" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="IntegerMultiplicationImplicitCastToLong" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="IteratorHasNextCallsIteratorNext" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="IteratorNextDoesNotThrowNoSuchElementException" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="JUnit4AnnotatedMethodInJUnit3TestCase" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="JUnitAbstractTestClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_regex" value="[A-Z][A-Za-z\d]*TestCase" />
+          <option name="m_minLength" value="12" />
+          <option name="m_maxLength" value="64" />
+        </inspection_tool>
+        <inspection_tool class="JUnitTestClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_regex" value="[A-Z][A-Za-z\d]*Test" />
+          <option name="m_minLength" value="8" />
+          <option name="m_maxLength" value="64" />
+        </inspection_tool>
+        <inspection_tool class="JavaDoc" enabled="false" level="WARNING" enabled_by_default="false">
           <option name="TOP_LEVEL_CLASS_OPTIONS">
             <value>
-              <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+              <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="public" />
               <option name="REQUIRED_TAGS" value="" />
             </value>
           </option>
           <option name="INNER_CLASS_OPTIONS">
             <value>
-              <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+              <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="protected" />
               <option name="REQUIRED_TAGS" value="" />
             </value>
           </option>
           <option name="METHOD_OPTIONS">
             <value>
-              <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
-              <option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
+              <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="protected" />
+              <option name="REQUIRED_TAGS" value="@throws or @exception" />
             </value>
           </option>
           <option name="FIELD_OPTIONS">
             <value>
-              <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+              <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="protected" />
               <option name="REQUIRED_TAGS" value="" />
             </value>
           </option>
-          <option name="IGNORE_DEPRECATED" value="false" />
-          <option name="IGNORE_JAVADOC_PERIOD" value="true" />
+          <option name="IGNORE_DEPRECATED" value="true" />
+          <option name="IGNORE_JAVADOC_PERIOD" value="false" />
+          <option name="IGNORE_DUPLICATED_THROWS" value="false" />
           <option name="myAdditionalJavadocTags" value="" />
         </inspection_tool>
+        <inspection_tool class="JavaLangImport" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="LengthOneStringInIndexOf" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ListIndexOfReplaceableByContains" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="LocalVariableHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignoreInvisibleFields" value="true" />
+          <option name="m_ignoreStaticMethods" value="true" />
+        </inspection_tool>
+        <inspection_tool class="LoggerInitializedWithForeignClass" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="loggerClassName" value="org.apache.log4j.Logger" />
+          <option name="loggerFactoryMethodName" value="getLogger" />
+        </inspection_tool>
+        <inspection_tool class="LoggingConditionDisagreesWithLogStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="LongLiteralsEndingWithLowercaseL" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="LoopConditionNotUpdatedInsideLoop" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreIterators" value="false" />
+        </inspection_tool>
+        <inspection_tool class="LoopWithImplicitTerminationCondition" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MapReplaceableByEnumMap" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MavenModelInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+        <inspection_tool class="MethodMayBeSynchronized" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MethodNameSameAsClassName" enabled="false" level="WARNING" enabled_by_default="false" />
+        <inspection_tool class="MethodOverloadsParentMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MethodOverridesPackageLocalMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MethodOverridesPrivateMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MethodOverridesStaticMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MethodReturnAlwaysConstant" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MismatchedArrayReadWrite" enabled="false" level="WARNING" enabled_by_default="false" />
+        <inspection_tool class="MisorderedAssertEqualsParameters" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MissingDeprecatedAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MissingOverrideAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_requireAnnotationsFirst" value="true" />
+        </inspection_tool>
+        <inspection_tool class="MisspelledCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MisspelledEquals" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MisspelledHashcode" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MisspelledSetUp" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MisspelledTearDown" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MisspelledToString" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MultipleDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MultipleExceptionsDeclaredOnTestMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MultipleTopLevelClassesInFile" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="MultipleTypedDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NakedNotify" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NativeMethods" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NegatedConditional" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignoreNegatedNullComparison" value="true" />
+        </inspection_tool>
+        <inspection_tool class="NestedConditionalExpression" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NestedSynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NonFinalFieldOfException" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NonFinalStaticVariableUsedInClassInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NonProtectedConstructorInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignoreNonPublicClasses" value="false" />
+        </inspection_tool>
+        <inspection_tool class="NonSerializableFieldInSerializableClass" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="superClassString" value="java.awt.Component" />
+        </inspection_tool>
+        <inspection_tool class="NonSerializableObjectBoundToHttpSession" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NonSerializableObjectPassedToObjectStream" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NonSerializableWithSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NonSerializableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NonShortCircuitBoolean" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NonStaticFinalLogger" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="loggerClassName" value="java.util.logging.Logger" />
+        </inspection_tool>
+        <inspection_tool class="NonSynchronizedMethodOverridesSynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NonThreadSafeLazyInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NotifyCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NotifyNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NotifyWithoutCorrespondingWait" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="NullableProblems" enabled="false" level="WARNING" enabled_by_default="false">
+          <option name="REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL" value="true" />
+          <option name="REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL" value="true" />
+          <option name="REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE" value="true" />
+          <option name="REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL" value="true" />
+          <option name="REPORT_NOT_ANNOTATED_GETTER" value="true" />
+          <option name="REPORT_NOT_ANNOTATED_SETTER_PARAMETER" value="true" />
+          <option name="REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS" value="true" />
+        </inspection_tool>
+        <inspection_tool class="ObjectEquality" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignoreEnums" value="true" />
+          <option name="m_ignoreClassObjects" value="true" />
+          <option name="m_ignorePrivateConstructors" value="false" />
+        </inspection_tool>
+        <inspection_tool class="ObjectNotify" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ObjectToString" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ObsoleteCollection" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreLibraryArguments" value="false" />
+        </inspection_tool>
+        <inspection_tool class="OctalAndDecimalIntegersMixed" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="OnDemandImport" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="OverlyComplexArithmeticExpression" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_limit" value="6" />
+        </inspection_tool>
+        <inspection_tool class="OverlyStrongTypeCast" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreInMatchingInstanceof" value="false" />
+        </inspection_tool>
+        <inspection_tool class="OverridableMethodCallDuringObjectConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="OverriddenMethodCallDuringObjectConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ParameterHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignoreInvisibleFields" value="true" />
+          <option name="m_ignoreStaticMethodParametersHidingInstanceFields" value="true" />
+          <option name="m_ignoreForConstructors" value="true" />
+          <option name="m_ignoreForPropertySetters" value="true" />
+          <option name="m_ignoreForAbstractMethods" value="false" />
+        </inspection_tool>
+        <inspection_tool class="ParameterizedParametersStaticCollection" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="PatternNotApplicable" enabled="false" level="ERROR" enabled_by_default="false" />
+        <inspection_tool class="PatternOverriddenByNonAnnotatedMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+        <inspection_tool class="PatternValidation" enabled="false" level="WARNING" enabled_by_default="false">
+          <option name="CHECK_NON_CONSTANT_VALUES" value="true" />
+        </inspection_tool>
+        <inspection_tool class="PointlessIndexOfComparison" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ProtectedMemberInFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="PublicConstructorInNonPublicClass" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="PublicField" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreEnums" value="false" />
+        </inspection_tool>
+        <inspection_tool class="PublicFieldAccessedInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="PublicStaticArrayField" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="RawUseOfParameterizedType" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreObjectConstruction" value="true" />
+          <option name="ignoreTypeCasts" value="false" />
+        </inspection_tool>
+        <inspection_tool class="ReadObjectAndWriteObjectPrivate" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ReadObjectInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ReadResolveAndWriteReplaceProtected" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="RedundantFieldInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="RedundantImplements" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreSerializable" value="false" />
+          <option name="ignoreCloneable" value="false" />
+        </inspection_tool>
+        <inspection_tool class="RedundantImport" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="RedundantMethodOverride" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="RedundantStringFormatCall" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="RedundantSuppression" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="RedundantThrowsDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ReplaceAllDot" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ReplaceAssignmentWithOperatorAssignment" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreLazyOperators" value="true" />
+          <option name="ignoreObscureOperators" value="false" />
+        </inspection_tool>
+        <inspection_tool class="RequiredAttributes" enabled="false" level="WARNING" enabled_by_default="false">
+          <option name="myAdditionalRequiredHtmlAttributes" value="" />
+        </inspection_tool>
+        <inspection_tool class="ResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ReturnOfDateField" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ReuseOfLocalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="RuntimeExec" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SafeLock" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SamePackageImport" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SerialPersistentFieldsWithWrongSignature" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SerialVersionUIDNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SerializableHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="superClassString" value="java.awt.Component" />
+        </inspection_tool>
+        <inspection_tool class="SerializableInnerClassHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="superClassString" value="java.awt.Component" />
+        </inspection_tool>
+        <inspection_tool class="SerializableInnerClassWithNonSerializableOuterClass" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="superClassString" value="java.awt.Component" />
+        </inspection_tool>
+        <inspection_tool class="SerializableWithUnconstructableAncestor" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SetReplaceableByEnumSet" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SetupCallsSuperSetup" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SetupIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SignalWithoutCorrespondingAwait" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SimplifiableIfStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+        <inspection_tool class="SimplifiableJUnitAssertion" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="Since15" enabled="true" level="ERROR" enabled_by_default="true">
+          <option name="FORBID_15_API" value="false" />
+          <option name="FORBID_16_API" value="true" />
+        </inspection_tool>
+        <inspection_tool class="SizeReplaceableByIsEmpty" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreNegations" value="false" />
+        </inspection_tool>
+        <inspection_tool class="SleepWhileHoldingLock" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SocketResource" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
+          <option name="processCode" value="true" />
+          <option name="processLiterals" value="true" />
+          <option name="processComments" value="true" />
+        </inspection_tool>
+        <inspection_tool class="StaticCallOnSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="StaticFieldReferenceOnSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="StaticInheritance" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="StaticNonFinalField" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="StaticSuite" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="StaticVariableInitialization" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignorePrimitives" value="false" />
+        </inspection_tool>
+        <inspection_tool class="StaticVariableUninitializedUse" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignorePrimitives" value="false" />
+        </inspection_tool>
+        <inspection_tool class="StringBufferReplaceableByStringBuilder" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="StringEqualsEmptyString" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SubtractionInCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SuspiciousIndentAfterControlStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SwitchStatementWithConfusingDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SynchronizeOnLock" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SynchronizeOnThis" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_includeNativeMethods" value="true" />
+        </inspection_tool>
+        <inspection_tool class="SynchronizedOnLiteralObject" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="SystemRunFinalizersOnExit" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TailRecursion" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TeardownCallsSuperTeardown" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TeardownIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TestCaseInProductCode" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TestCaseWithConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TestCaseWithNoTestMethods" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreSupers" value="false" />
+        </inspection_tool>
+        <inspection_tool class="TestMethodInProductCode" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TestMethodIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TestMethodWithoutAssertion" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TestOnlyProblems" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TextLabelInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ThisEscapedInConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ThreadDumpStack" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ThreadLocalNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ThreadPriority" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ThreadRun" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ThreadStartInConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ThreadStopSuspendResume" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ThreadWithDefaultRunMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ThreadYield" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="ThrowCaughtLocally" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreRethrownExceptions" value="false" />
+        </inspection_tool>
+        <inspection_tool class="ThrowablePrintStackTrace" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TooBroadScope" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_allowConstructorAsInitializer" value="false" />
+          <option name="m_onlyLookAtBlocks" value="false" />
+        </inspection_tool>
+        <inspection_tool class="TransientFieldInNonSerializableClass" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TransientFieldNotInitialized" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TypeParameterExtendsFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="TypeParameterHidesVisibleType" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UNUSED_SYMBOL" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="LOCAL_VARIABLE" value="true" />
+          <option name="FIELD" value="true" />
+          <option name="METHOD" value="true" />
+          <option name="CLASS" value="true" />
+          <option name="PARAMETER" value="true" />
+          <option name="REPORT_PARAMETER_FOR_PUBLIC_METHODS" value="true" />
+          <option name="INJECTION_ANNOS">
+            <value>
+              <list size="1">
+                <item index="0" class="java.lang.String" itemvalue="com.google.caliper.Param" />
+              </list>
+            </value>
+          </option>
+        </inspection_tool>
+        <inspection_tool class="UnaryPlus" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnconditionalWait" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnconstructableTestCase" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessarilyQualifiedStaticUsage" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignoreStaticFieldAccesses" value="false" />
+          <option name="m_ignoreStaticMethodCalls" value="false" />
+          <option name="m_ignoreStaticAccessFromStaticContext" value="false" />
+        </inspection_tool>
+        <inspection_tool class="UnnecessaryAnnotationParentheses" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessaryBlockStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessaryCallToStringValueOf" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessaryConstantArrayCreationExpression" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessaryConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessaryEnumModifier" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessaryFinalOnLocalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessaryFinalOnParameter" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="onlyWarnOnAbstractMethods" value="false" />
+        </inspection_tool>
+        <inspection_tool class="UnnecessaryFullyQualifiedName" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignoreJavadoc" value="false" />
+        </inspection_tool>
+        <inspection_tool class="UnnecessaryInheritDoc" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessaryInterfaceModifier" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessaryJavaDocLink" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessaryParentheses" enabled="true" level="INFO" enabled_by_default="true">
+          <option name="ignoreClarifyingParentheses" value="true" />
+          <option name="ignoreParenthesesOnConditionals" value="true" />
+        </inspection_tool>
+        <inspection_tool class="UnnecessaryQualifierForThis" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessarySuperConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessarySuperQualifier" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnnecessaryUnaryMinus" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnpredictableBigDecimalConstructorCall" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreReferences" value="true" />
+          <option name="ignoreComplexLiterals" value="false" />
+        </inspection_tool>
+        <inspection_tool class="UnusedCatchParameter" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="m_ignoreCatchBlocksWithComments" value="true" />
+          <option name="m_ignoreTestCases" value="true" />
+        </inspection_tool>
+        <inspection_tool class="UnusedDeclaration" enabled="false" level="WARNING" enabled_by_default="false">
+          <option name="ADD_MAINS_TO_ENTRIES" value="true" />
+          <option name="ADD_APPLET_TO_ENTRIES" value="true" />
+          <option name="ADD_SERVLET_TO_ENTRIES" value="true" />
+          <option name="ADD_NONJAVA_TO_ENTRIES" value="true" />
+          <option name="ADDITIONAL_ANNOTATIONS">
+            <value>
+              <list size="1">
+                <item index="0" class="java.lang.String" itemvalue="javax.ws.rs.*" />
+              </list>
+            </value>
+          </option>
+          <option name="ADD_JUNIT_TO_ENTRIES" value="true" />
+        </inspection_tool>
+        <inspection_tool class="UnusedImport" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UnusedLibrary" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UseOfAnotherObjectsPrivateField" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UseOfPropertiesAsHashtable" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UseOfSunClasses" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UtilityClassWithPublicConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="UtilityClassWithoutPrivateConstructor" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreClassesWithOnlyMain" value="false" />
+        </inspection_tool>
+        <inspection_tool class="VariableNotUsedInsideIf" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="VolatileArrayField" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="VolatileLongOrDoubleField" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="WaitCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="WaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="WaitNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="WaitOrAwaitWithoutTimeout" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="WaitWhileHoldingTwoLocks" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="WaitWithoutCorrespondingNotify" enabled="true" level="WARNING" enabled_by_default="true" />
+        <inspection_tool class="WeakerAccess" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="true" />
+          <option name="SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES" value="false" />
+          <option name="SUGGEST_PRIVATE_FOR_INNERS" value="false" />
+        </inspection_tool>
+        <inspection_tool class="WhileLoopSpinsOnField" enabled="true" level="WARNING" enabled_by_default="true">
+          <option name="ignoreNonEmtpyLoops" value="false" />
+        </inspection_tool>
       </profile>
     </profiles>
-    <list size="0" />
-  </component>
-  <component name="JavacSettings">
-    <option name="DEBUGGING_INFO" value="true" />
-    <option name="GENERATE_NO_WARNINGS" value="false" />
-    <option name="DEPRECATION" value="true" />
-    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
-    <option name="MAXIMUM_HEAP_SIZE" value="128" />
+    <option name="PROJECT_PROFILE" value="Project Default" />
+    <option name="USE_PROJECT_PROFILE" value="true" />
+    <version value="1.0" />
   </component>
   <component name="JavadocGenerationManager">
     <option name="OUTPUT_DIRECTORY" />
@@ -140,14 +713,6 @@
     <option name="LOCALE" />
     <option name="OPEN_IN_BROWSER" value="true" />
   </component>
-  <component name="JikesSettings">
-    <option name="JIKES_PATH" value="" />
-    <option name="DEBUGGING_INFO" value="true" />
-    <option name="DEPRECATION" value="true" />
-    <option name="GENERATE_NO_WARNINGS" value="false" />
-    <option name="IS_EMACS_ERRORS_MODE" value="true" />
-    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
-  </component>
   <component name="Palette2">
     <group name="Swing">
       <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
@@ -272,31 +837,17 @@
   <component name="ProjectDetails">
     <option name="projectName" value="caliper" />
   </component>
-  <component name="ProjectFileVersion" converted="true" />
-  <component name="ProjectKey">
-    <option name="state" value="https://caliper.googlecode.com/svn/trunk/caliper.ipr" />
+  <component name="ProjectDictionaryState">
+    <dictionary name="kevinb" />
   </component>
   <component name="ProjectModuleManager">
     <modules>
-      <module fileurl="file://$PROJECT_DIR$/core.iml" filepath="$PROJECT_DIR$/core.iml" />
+      <module fileurl="file://$PROJECT_DIR$/caliper.iml" filepath="$PROJECT_DIR$/caliper.iml" />
+      <module fileurl="file://$PROJECT_DIR$/ideaplugin/ideaplugin.iml" filepath="$PROJECT_DIR$/ideaplugin/ideaplugin.iml" />
     </modules>
   </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="1.5" project-jdk-type="JavaSDK">
-    <output url="file://$PROJECT_DIR$/out" />
-  </component>
-  <component name="ResourceManagerContainer">
-    <option name="myResourceBundles">
-      <value>
-        <list size="0" />
-      </value>
-    </option>
-  </component>
-  <component name="RmicSettings">
-    <option name="IS_EANABLED" value="false" />
-    <option name="DEBUGGING_INFO" value="true" />
-    <option name="GENERATE_NO_WARNINGS" value="false" />
-    <option name="GENERATE_IIOP_STUBS" value="false" />
-    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/ideabuild" />
   </component>
   <component name="SvnBranchConfigurationManager">
     <option name="myConfigurationMap">
@@ -304,9 +855,35 @@
         <entry key="$PROJECT_DIR$">
           <value>
             <SvnBranchConfiguration>
+              <option name="branchMap">
+                <map>
+                  <entry key="https://caliper.googlecode.com/svn/branches">
+                    <value>
+                      <list />
+                    </value>
+                  </entry>
+                  <entry key="https://caliper.googlecode.com/svn/cloud">
+                    <value>
+                      <list />
+                    </value>
+                  </entry>
+                  <entry key="https://caliper.googlecode.com/svn/static">
+                    <value>
+                      <list />
+                    </value>
+                  </entry>
+                  <entry key="https://caliper.googlecode.com/svn/tags">
+                    <value>
+                      <list />
+                    </value>
+                  </entry>
+                </map>
+              </option>
               <option name="branchUrls">
                 <list>
                   <option value="https://caliper.googlecode.com/svn/branches" />
+                  <option value="https://caliper.googlecode.com/svn/cloud" />
+                  <option value="https://caliper.googlecode.com/svn/static" />
                   <option value="https://caliper.googlecode.com/svn/tags" />
                 </list>
               </option>
@@ -316,27 +893,10 @@
         </entry>
       </map>
     </option>
-    <option name="myVersion" value="124" />
     <option name="mySupportsUserInfoFilter" value="true" />
   </component>
   <component name="VcsDirectoryMappings">
     <mapping directory="" vcs="svn" />
   </component>
-  <component name="libraryTable">
-    <library name="Google Collections">
-      <CLASSES>
-        <root url="jar://$PROJECT_DIR$/lib/google-collect-1.0-rc4.jar!/" />
-      </CLASSES>
-      <JAVADOC />
-      <SOURCES />
-    </library>
-    <library name="JUnit">
-      <CLASSES>
-        <root url="jar://$PROJECT_DIR$/lib/junit.jar!/" />
-      </CLASSES>
-      <JAVADOC />
-      <SOURCES />
-    </library>
-  </component>
 </project>
 
diff --git a/core.iml b/core.iml
deleted file mode 100644
index 09f6e96..0000000
--- a/core.iml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module relativePaths="false" type="JAVA_MODULE" version="4">
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <exclude-output />
-    <content url="file://$MODULE_DIR$">
-      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="library" name="Google Collections" level="project" />
-    <orderEntry type="library" name="JUnit" level="project" />
-  </component>
-</module>
-
diff --git a/lib/jarjar-1.0rc8.jar b/lib/jarjar-1.0rc8.jar
new file mode 100644
index 0000000..89390bf
--- /dev/null
+++ b/lib/jarjar-1.0rc8.jar
Binary files differ
diff --git a/src/CaliperCore.gwt.xml b/src/CaliperCore.gwt.xml
new file mode 100644
index 0000000..161ac57
--- /dev/null
+++ b/src/CaliperCore.gwt.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module>
+  <inherits name='com.google.gwt.user.User'/>
+  <source path="com/google/caliper">
+    <include name="**/Run.java"/>
+    <include name="**/Scenario.java"/>
+  </source>
+</module>
\ No newline at end of file
diff --git a/src/com/google/caliper/Arguments.java b/src/com/google/caliper/Arguments.java
new file mode 100644
index 0000000..e5ff0f7
--- /dev/null
+++ b/src/com/google/caliper/Arguments.java
@@ -0,0 +1,156 @@
+/*
+ * 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.caliper;
+
+import com.google.caliper.UserException.DisplayUsageException;
+import com.google.caliper.UserException.MalformedParameterException;
+import com.google.caliper.UserException.MultipleBenchmarkClassesException;
+import com.google.caliper.UserException.NoBenchmarkClassException;
+import com.google.caliper.UserException.UnrecognizedOptionException;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Parse command line arguments for the runner and in-process runner.
+ */
+public final class Arguments {
+  private String suiteClassName;
+
+  /** JVMs to run in the benchmark */
+  private final Set<String> userVms = new LinkedHashSet<String>();
+
+  /**
+   * Parameter values specified by the user on the command line. Parameters with
+   * no value in this multimap will get their values from the benchmark suite.
+   */
+  private final Multimap<String, String> userParameters = LinkedHashMultimap.create();
+
+  private long warmupMillis = 5000;
+  private long runMillis = 5000;
+
+  /** The URL to post benchmark results to. */
+  private String postHost = "http://microbenchmarks.appspot.com/run/";
+
+  public String getSuiteClassName() {
+    return suiteClassName;
+  }
+
+  public Set<String> getUserVms() {
+    return userVms;
+  }
+
+  public Multimap<String, String> getUserParameters() {
+    return userParameters;
+  }
+
+  public long getWarmupMillis() {
+    return warmupMillis;
+  }
+
+  public long getRunMillis() {
+    return runMillis;
+  }
+
+  public String getPostHost() {
+    return postHost;
+  }
+
+  public static Arguments parse(String[] argsArray) {
+    Arguments result = new Arguments();
+
+    Iterator<String> args = Iterators.forArray(argsArray);
+    while (args.hasNext()) {
+      String arg = args.next();
+
+      if ("--help".equals(arg)) {
+        throw new DisplayUsageException();
+      }
+
+      if ("--postHost".equals(arg)) {
+          result.postHost = args.next();
+
+      } else if (arg.startsWith("-D")) {
+        int equalsSign = arg.indexOf('=');
+        if (equalsSign == -1) {
+          throw new MalformedParameterException(arg);
+        }
+        String name = arg.substring(2, equalsSign);
+        String value = arg.substring(equalsSign + 1);
+        result.userParameters.put(name, value);
+
+      } else if ("--warmupMillis".equals(arg)) {
+        result.warmupMillis = Long.parseLong(args.next());
+
+      } else if ("--runMillis".equals(arg)) {
+        result.runMillis = Long.parseLong(args.next());
+
+      } else if ("--vm".equals(arg)) {
+        result.userVms.add(args.next());
+
+      } else if (arg.startsWith("-")) {
+        throw new UnrecognizedOptionException(arg);
+
+      } else {
+        if (result.suiteClassName != null) {
+          throw new MultipleBenchmarkClassesException(result.suiteClassName, arg);
+        }
+        result.suiteClassName = arg;
+      }
+    }
+
+    if (result.suiteClassName == null) {
+      throw new NoBenchmarkClassException();
+    }
+
+    return result;
+  }
+
+  public static void printUsage() {
+    Arguments defaults = new Arguments();
+
+    System.out.println();
+    System.out.println("Usage: Runner [OPTIONS...] <benchmark>");
+    System.out.println();
+    System.out.println("  <benchmark>: a benchmark class or suite");
+    System.out.println();
+    System.out.println("OPTIONS");
+    System.out.println();
+    System.out.println("  -D<param>=<value>: fix a benchmark parameter to a given value.");
+    System.out.println("        When multiple values for the same parameter are given (via");
+    System.out.println("        multiple --Dx=y args), all supplied values are used.");
+    System.out.println();
+    System.out.println("  --inProcess: run the benchmark in the same JVM rather than spawning");
+    System.out.println("        another with the same classpath. By default each benchmark is");
+    System.out.println("        run in a separate VM");
+    System.out.println();
+    System.out.println("  --postHost <host>: the URL to post benchmark results to, or \"none\"");
+    System.out.println("        to skip posting results to the web.");
+    System.out.println("        default value: " + defaults.postHost);
+    System.out.println();
+    System.out.println("  --warmupMillis <millis>: duration to warmup each benchmark");
+    System.out.println();
+    System.out.println("  --runMillis <millis>: duration to execute each benchmark");
+    System.out.println();
+    System.out.println("  --vm <vm>: executable to test benchmark on");
+
+    // adding new options? don't forget to update executeForked()
+  }
+}
diff --git a/src/com/google/caliper/Benchmark.java b/src/com/google/caliper/Benchmark.java
index 19426e6..b5d35f9 100644
--- a/src/com/google/caliper/Benchmark.java
+++ b/src/com/google/caliper/Benchmark.java
@@ -16,7 +16,6 @@
 
 package com.google.caliper;
 
-import java.lang.reflect.Method;
 import java.util.Map;
 import java.util.Set;
 
diff --git a/src/com/google/caliper/Caliper.java b/src/com/google/caliper/Caliper.java
index 315431f..6c9d625 100644
--- a/src/com/google/caliper/Caliper.java
+++ b/src/com/google/caliper/Caliper.java
@@ -26,7 +26,7 @@
   private final long warmupNanos;
   private final long runNanos;
 
-  public Caliper(long warmupMillis, long runMillis) {
+  Caliper(long warmupMillis, long runMillis) {
     checkArgument(warmupMillis > 50);
     checkArgument(runMillis > 50);
 
@@ -37,15 +37,24 @@
   public double warmUp(TimedRunnable timedRunnable) throws Exception {
     long startNanos = System.nanoTime();
     long endNanos = startNanos + warmupNanos;
-    int trials = 0;
     long currentNanos;
+    int netReps = 0;
+    int reps = 1;
+
+    /*
+     * Run progressively more reps at a time until we cross our warmup
+     * threshold. This way any just-in-time compiler will be comfortable running
+     * multiple iterations of our measurement method.
+     */
     while ((currentNanos = System.nanoTime()) < endNanos) {
-      timedRunnable.run(1);
-      trials++;
+      timedRunnable.run(reps);
+      netReps += reps;
+      reps *= 2;
     }
-    double nanosPerExecution = (currentNanos - startNanos) / trials;
+
+    double nanosPerExecution = (currentNanos - startNanos) / (double) netReps;
     if (nanosPerExecution > 1000000000 || nanosPerExecution < 2) {
-      throw new ConfigurationException("Runtime out of range");
+      throw new ConfigurationException("Runtime " + nanosPerExecution + " out of range");
     }
     return nanosPerExecution;
   }
@@ -54,15 +63,51 @@
    * In the run proper, we predict how extrapolate based on warmup how many
    * runs we're going to need, and run them all in a single batch.
    */
-  public double run(TimedRunnable test, double estimatedNanosPerTrial) throws Exception {
+  public double run(TimedRunnable test, double estimatedNanosPerTrial)
+      throws Exception {
+    @SuppressWarnings("NumericCastThatLosesPrecision")
     int trials = (int) (runNanos / estimatedNanosPerTrial);
     if (trials == 0) {
       trials = 1;
     }
+
+    double nanosPerTrial = measure(test, trials);
+
+    // if the runtime was in the expected range, return it. We're good.
+    if (isPlausible(estimatedNanosPerTrial, nanosPerTrial)) {
+      return nanosPerTrial;
+    }
+
+    // The runtime was outside of the expected range. Perhaps the VM is inlining
+    // things too aggressively? We'll run more rounds to confirm that the
+    // runtime scales with the number of trials.
+    double nanosPerTrial2 = measure(test, trials * 4);
+    if (isPlausible(nanosPerTrial, nanosPerTrial2)) {
+      return nanosPerTrial;
+    }
+
+    throw new ConfigurationException("Measurement error: "
+        + "runtime isn't proportional to the number of repetitions!");
+  }
+
+  /**
+   * Returns true if the given measurement is consistent with the expected
+   * measurement.
+   */
+  private boolean isPlausible(double expected, double measurement) {
+    double ratio = measurement / expected;
+    return ratio > 0.5 && ratio < 2.0;
+  }
+
+  private double measure(TimedRunnable test, int trials) throws Exception {
+    prepareForTest();
     long startNanos = System.nanoTime();
     test.run(trials);
-    long endNanos = System.nanoTime();
-    estimatedNanosPerTrial = (endNanos - startNanos) / trials;
-    return estimatedNanosPerTrial;
+    return (System.nanoTime() - startNanos) / (double) trials;
+  }
+
+  private void prepareForTest() {
+    System.gc();
+    System.gc();
   }
 }
\ No newline at end of file
diff --git a/src/com/google/caliper/ConfigurationException.java b/src/com/google/caliper/ConfigurationException.java
index 5ad7bde..c4a35ec 100644
--- a/src/com/google/caliper/ConfigurationException.java
+++ b/src/com/google/caliper/ConfigurationException.java
@@ -19,13 +19,15 @@
 /**
  * Thrown upon occurrence of a configuration error.
  */
-public final class ConfigurationException extends RuntimeException {
+final class ConfigurationException extends RuntimeException {
 
-  public ConfigurationException(String s) {
+  ConfigurationException(String s) {
     super(s);
   }
 
-  public ConfigurationException(Throwable cause) {
+  ConfigurationException(Throwable cause) {
     super(cause);
   }
+
+  private static final long serialVersionUID = 0;
 }
diff --git a/src/com/google/caliper/ConsoleReport.java b/src/com/google/caliper/ConsoleReport.java
index b367ec4..e59ceb6 100644
--- a/src/com/google/caliper/ConsoleReport.java
+++ b/src/com/google/caliper/ConsoleReport.java
@@ -16,8 +16,11 @@
 
 package com.google.caliper;
 
-import com.google.common.collect.*;
-
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Ordering;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -39,13 +42,11 @@
 final class ConsoleReport {
 
   private static final int bargraphWidth = 30;
-  private static final String vmKey = "vm";
 
-  private final List<Parameter> parameters;
-  private final Result result;
-  private final List<Run> runs;
+  private final List<Variable> variables;
+  private final Run run;
+  private final List<Scenario> scenarios;
 
-  private final double minValue;
   private final double maxValue;
   private final double logMaxValue;
   private final int decimalDigits;
@@ -53,53 +54,51 @@
   private final String units;
   private final int measurementColumnLength;
 
-  public ConsoleReport(Result result) {
-    this.result = result;
+  ConsoleReport(Run run) {
+    this.run = run;
 
-    double minValue = Double.POSITIVE_INFINITY;
-    double maxValue = 0;
+    double min = Double.POSITIVE_INFINITY;
+    double max = 0;
 
     Multimap<String, String> nameToValues = LinkedHashMultimap.create();
-    List<Parameter> parametersBuilder = new ArrayList<Parameter>();
-    for (Map.Entry<Run, Double> entry : result.getMeasurements().entrySet()) {
-      Run run = entry.getKey();
+    List<Variable> variablesBuilder = new ArrayList<Variable>();
+    for (Map.Entry<Scenario, Double> entry : run.getMeasurements().entrySet()) {
+      Scenario scenario = entry.getKey();
       double d = entry.getValue();
 
-      minValue = Math.min(minValue, d);
-      maxValue = Math.max(maxValue, d);
+      min = Math.min(min, d);
+      max = Math.max(max, d);
 
-      for (Map.Entry<String, String> parameter : run.getParameters().entrySet()) {
-        String name = parameter.getKey();
-        nameToValues.put(name, parameter.getValue());
+      for (Map.Entry<String, String> variable : scenario.getVariables().entrySet()) {
+        String name = variable.getKey();
+        nameToValues.put(name, variable.getValue());
       }
-
-      nameToValues.put(vmKey, run.getVm());
     }
 
     for (Map.Entry<String, Collection<String>> entry : nameToValues.asMap().entrySet()) {
-      Parameter parameter = new Parameter(entry.getKey(), entry.getValue());
-      parametersBuilder.add(parameter);
+      Variable variable = new Variable(entry.getKey(), entry.getValue());
+      variablesBuilder.add(variable);
     }
 
     /*
-     * Figure out how much influence each parameter has on the measured value.
-     * We sum the measurements taken with each value of each parameter. For
-     * parameters that have influence on the measurement, the sums will differ
-     * by value. If the parameter has little influence, the sums will be similar
+     * Figure out how much influence each variable has on the measured value.
+     * We sum the measurements taken with each value of each variable. For
+     * variable that have influence on the measurement, the sums will differ
+     * by value. If the variable has little influence, the sums will be similar
      * to one another and close to the overall average. We take the standard
-     * deviation across each parameters collection of sums. Higher standard
+     * deviation across each variable's collection of sums. Higher standard
      * deviation implies higher influence on the measured result.
      */
     double sumOfAllMeasurements = 0;
-    for (double measurement : result.getMeasurements().values()) {
+    for (double measurement : run.getMeasurements().values()) {
       sumOfAllMeasurements += measurement;
     }
-    for (Parameter parameter : parametersBuilder) {
-      int numValues = parameter.values.size();
+    for (Variable variable : variablesBuilder) {
+      int numValues = variable.values.size();
       double[] sumForValue = new double[numValues];
-      for (Map.Entry<Run, Double> entry : result.getMeasurements().entrySet()) {
-        Run run = entry.getKey();
-        sumForValue[parameter.index(run)] += entry.getValue();
+      for (Map.Entry<Scenario, Double> entry : run.getMeasurements().entrySet()) {
+        Scenario scenario = entry.getKey();
+        sumForValue[variable.index(scenario)] += entry.getValue();
       }
       double mean = sumOfAllMeasurements / sumForValue.length;
       double stdDeviationSquared = 0;
@@ -107,16 +106,15 @@
         double distance = value - mean;
         stdDeviationSquared += distance * distance;
       }
-      parameter.stdDeviation = Math.sqrt(stdDeviationSquared / numValues);
+      variable.stdDeviation = Math.sqrt(stdDeviationSquared / numValues);
     }
 
-    this.parameters = new StandardDeviationOrdering().reverse().sortedCopy(parametersBuilder);
-    this.runs = new ByParametersOrdering().sortedCopy(result.getMeasurements().keySet());
-    this.minValue = minValue;
-    this.maxValue = maxValue;
-    this.logMaxValue = Math.log(maxValue);
+    this.variables = new StandardDeviationOrdering().reverse().sortedCopy(variablesBuilder);
+    this.scenarios = new ByVariablesOrdering().sortedCopy(run.getMeasurements().keySet());
+    this.maxValue = max;
+    this.logMaxValue = Math.log(max);
 
-    int numDigitsInMin = (int) Math.ceil(Math.log10(minValue));
+    int numDigitsInMin = ceil(Math.log10(min));
     if (numDigitsInMin > 9) {
       divideBy = 1000000000;
       decimalDigits = Math.max(0, 9 + 3 - numDigitsInMin);
@@ -134,41 +132,37 @@
       decimalDigits = 0;
       units = "ns";
     }
-    measurementColumnLength = maxValue > 0
-        ? (int) Math.ceil(Math.log10(maxValue / divideBy)) + decimalDigits + 1
+    measurementColumnLength = max > 0
+        ? ceil(Math.log10(max / divideBy)) + decimalDigits + 1
         : 1;
   }
 
   /**
-   * A parameter plus all of its values.
+   * A variable and the set of values to which it has been assigned.
    */
-  static class Parameter {
+  private static class Variable {
     final String name;
     final ImmutableList<String> values;
     final int maxLength;
     double stdDeviation;
 
-    public Parameter(String name, Collection<String> values) {
+    Variable(String name, Collection<String> values) {
       this.name = name;
       this.values = ImmutableList.copyOf(values);
 
-      int maxLength = name.length();
+      int maxLen = name.length();
       for (String value : values) {
-        maxLength = Math.max(maxLength, value.length());
+        maxLen = Math.max(maxLen, value.length());
       }
-      this.maxLength = maxLength;
+      this.maxLength = maxLen;
     }
 
-    String get(Run run) {
-      if (vmKey.equals(name)) {
-        return run.getVm();
-      } else {
-        return run.getParameters().get(name);
-      }
+    String get(Scenario scenario) {
+      return scenario.getVariables().get(name);
     }
 
-    int index(Run run) {
-      return values.indexOf(get(run));
+    int index(Scenario scenario) {
+      return values.indexOf(get(scenario));
     }
 
     boolean isInteresting() {
@@ -177,23 +171,23 @@
   }
 
   /**
-   * Orders the different parameters by their standard deviation. This results
+   * Orders the different variables by their standard deviation. This results
    * in an appropriate grouping of output values.
    */
-  static class StandardDeviationOrdering extends Ordering<Parameter> {
-    public int compare(Parameter a, Parameter b) {
+  private static class StandardDeviationOrdering extends Ordering<Variable> {
+    public int compare(Variable a, Variable b) {
       return Double.compare(a.stdDeviation, b.stdDeviation);
     }
   }
 
   /**
-   * Orders runs by the parameters.
+   * Orders scenarios by the variables.
    */
-  class ByParametersOrdering extends Ordering<Run> {
-    public int compare(Run a, Run b) {
-      for (Parameter parameter : parameters) {
-        int aValue = parameter.values.indexOf(parameter.get(a));
-        int bValue = parameter.values.indexOf(parameter.get(b));
+  private class ByVariablesOrdering extends Ordering<Scenario> {
+    public int compare(Scenario a, Scenario b) {
+      for (Variable variable : variables) {
+        int aValue = variable.values.indexOf(variable.get(a));
+        int bValue = variable.values.indexOf(variable.get(b));
         int diff = aValue - bValue;
         if (diff != 0) {
           return diff;
@@ -206,7 +200,7 @@
   void displayResults() {
     printValues();
     System.out.println();
-    printUninterestingParameters();
+    printUninterestingVariables();
   }
 
   /**
@@ -214,33 +208,33 @@
    */
   private void printValues() {
     // header
-    for (Parameter parameter : parameters) {
-      if (parameter.isInteresting()) {
-        System.out.printf("%" + parameter.maxLength + "s ", parameter.name);
+    for (Variable variable : variables) {
+      if (variable.isInteresting()) {
+        System.out.printf("%" + variable.maxLength + "s ", variable.name);
       }
     }
     System.out.printf("%" + measurementColumnLength + "s logarithmic runtime%n", units);
 
     // rows
     String numbersFormat = "%" + measurementColumnLength + "." + decimalDigits + "f %s%n";
-    for (Run run : runs) {
-      for (Parameter parameter : parameters) {
-        if (parameter.isInteresting()) {
-          System.out.printf("%" + parameter.maxLength + "s ", parameter.get(run));
+    for (Scenario scenario : scenarios) {
+      for (Variable variable : variables) {
+        if (variable.isInteresting()) {
+          System.out.printf("%" + variable.maxLength + "s ", variable.get(scenario));
         }
       }
-      double measurement = result.getMeasurements().get(run);
+      double measurement = run.getMeasurements().get(scenario);
       System.out.printf(numbersFormat, measurement / divideBy, bargraph(measurement));
     }
   }
 
   /**
-   * Prints parameters with only one unique value.
+   * Prints variables with only one unique value.
    */
-  private void printUninterestingParameters() {
-    for (Parameter parameter : parameters) {
-      if (!parameter.isInteresting()) {
-        System.out.println(parameter.name + ": " + Iterables.getOnlyElement(parameter.values));
+  private void printUninterestingVariables() {
+    for (Variable variable : variables) {
+      if (!variable.isInteresting()) {
+        System.out.println(variable.name + ": " + Iterables.getOnlyElement(variable.values));
       }
     }
   }
@@ -250,17 +244,27 @@
    * value.
    */
   private String bargraph(double value) {
-    int numLinearChars = (int) ((value / maxValue) * bargraphWidth);
+    int numLinearChars = floor(value / maxValue * bargraphWidth);
     double logValue = Math.log(value);
-    int numChars = (int) ((logValue / logMaxValue) * bargraphWidth);
-    StringBuilder result = new StringBuilder(numChars);
+    int numChars = floor(logValue / logMaxValue * bargraphWidth);
+    StringBuilder sb = new StringBuilder(numChars);
     for (int i = 0; i < numLinearChars; i++) {
-      result.append("X");
+      sb.append("X");
     }
 
     for (int i = numLinearChars; i < numChars; i++) {
-      result.append("|");
+      sb.append("|");
     }
-    return result.toString();
+    return sb.toString();
+  }
+
+  @SuppressWarnings("NumericCastThatLosesPrecision")
+  private static int floor(double d) {
+    return (int) d;
+  }
+
+  @SuppressWarnings("NumericCastThatLosesPrecision")
+  private static int ceil(double d) {
+    return (int) Math.ceil(d);
   }
 }
diff --git a/src/com/google/caliper/InProcessRunner.java b/src/com/google/caliper/InProcessRunner.java
new file mode 100644
index 0000000..33e9e00
--- /dev/null
+++ b/src/com/google/caliper/InProcessRunner.java
@@ -0,0 +1,71 @@
+/*
+ * 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.caliper;
+
+import com.google.caliper.UserException.CantCustomizeInProcessVmException;
+import com.google.caliper.UserException.ExceptionFromUserCodeException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * Executes a benchmark in the current VM.
+ */
+final class InProcessRunner {
+
+  public void run(String... args) {
+    Arguments arguments = Arguments.parse(args);
+
+    if (!arguments.getUserVms().isEmpty()) {
+      throw new CantCustomizeInProcessVmException();
+    }
+
+    ScenarioSelection scenarioSelection = new ScenarioSelection(arguments);
+
+    PrintStream resultStream = System.out;
+    System.setOut(nullPrintStream());
+    System.setErr(nullPrintStream());
+
+    try {
+      Caliper caliper = new Caliper(arguments.getWarmupMillis(), arguments.getRunMillis());
+
+      for (Scenario scenario : scenarioSelection.select()) {
+        TimedRunnable timedRunnable = scenarioSelection.createBenchmark(scenario);
+        double warmupNanosPerTrial = caliper.warmUp(timedRunnable);
+        double nanosPerTrial = caliper.run(timedRunnable, warmupNanosPerTrial);
+        resultStream.println(nanosPerTrial);
+      }
+    } catch (Exception e) {
+      throw new ExceptionFromUserCodeException(e);
+    }
+  }
+
+  public static void main(String... args) {
+    try {
+      new InProcessRunner().run(args);
+    } catch (UserException e) {
+      e.display(); // TODO: send this to the host process
+      System.exit(1);
+    }
+  }
+
+  public PrintStream nullPrintStream() {
+    return new PrintStream(new OutputStream() {
+      public void write(int b) throws IOException {}
+    });
+  }
+}
diff --git a/src/com/google/caliper/Param.java b/src/com/google/caliper/Param.java
index 28d3588..bea0269 100644
--- a/src/com/google/caliper/Param.java
+++ b/src/com/google/caliper/Param.java
@@ -26,4 +26,11 @@
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.FIELD)
-public @interface Param {}
+public @interface Param {
+  /**
+   * One or more default values, as strings, that this parameter should be given if none are
+   * specified on the command line. If values are specified on the command line, the defaults given
+   * here are all ignored.
+   */
+  String[] value() default {};
+}
diff --git a/src/com/google/caliper/Parameter.java b/src/com/google/caliper/Parameter.java
index 1ba77b5..caca252 100644
--- a/src/com/google/caliper/Parameter.java
+++ b/src/com/google/caliper/Parameter.java
@@ -16,8 +16,19 @@
 
 package com.google.caliper;
 
-import java.lang.reflect.*;
-import java.util.*;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
 
 /**
  * A parameter in a {@link SimpleBenchmark}.
@@ -35,22 +46,35 @@
    */
   public static Map<String, Parameter<?>> forClass(Class<? extends Benchmark> suiteClass) {
     Map<String, Parameter<?>> parameters = new TreeMap<String, Parameter<?>>();
-    for (final Field field : suiteClass.getDeclaredFields()) {
+    for (Field field : suiteClass.getDeclaredFields()) {
       if (field.isAnnotationPresent(Param.class)) {
         field.setAccessible(true);
-        Parameter parameter = Parameter.forField(suiteClass, field);
+        Parameter<?> parameter = forField(suiteClass, field);
         parameters.put(parameter.getName(), parameter);
       }
     }
     return parameters;
   }
 
-  public static Parameter forField(
+  private static Parameter<?> forField(
       Class<? extends Benchmark> suiteClass, final Field field) {
-    Parameter result = null;
+    // First check for String values on the annotation itself
+    final Object[] defaults = field.getAnnotation(Param.class).value();
+    if (defaults.length > 0) {
+      return new Parameter<Object>(field) {
+        @Override public Collection<Object> values() throws Exception {
+          return Arrays.asList(defaults);
+        }
+      };
+      // TODO: or should we continue so we can give an error/warning if params are also give in a
+      // method or field?
+    }
+
+    Parameter<?> result = null;
     Type returnType = null;
     Member member = null;
 
+    // Now check for a fooValues() method
     try {
       final Method valuesMethod = suiteClass.getDeclaredMethod(field.getName() + "Values");
       valuesMethod.setAccessible(true);
@@ -58,13 +82,14 @@
       returnType = valuesMethod.getGenericReturnType();
       result = new Parameter<Object>(field) {
         @SuppressWarnings("unchecked") // guarded below
-        public Collection<Object> values() throws Exception {
+        @Override public Collection<Object> values() throws Exception {
           return (Collection<Object>) valuesMethod.invoke(null);
         }
       };
     } catch (NoSuchMethodException ignored) {
     }
 
+    // Now check for a fooValues field
     try {
       final Field valuesField = suiteClass.getDeclaredField(field.getName() + "Values");
       valuesField.setAccessible(true);
@@ -75,38 +100,60 @@
       returnType = valuesField.getGenericType();
       result = new Parameter<Object>(field) {
         @SuppressWarnings("unchecked") // guarded below
-        public Collection<Object> values() throws Exception {
+        @Override public Collection<Object> values() throws Exception {
           return (Collection<Object>) valuesField.get(null);
         }
       };
     } catch (NoSuchFieldException ignored) {
     }
 
+    if (member != null && !Modifier.isStatic(member.getModifiers())) {
+        throw new ConfigurationException("Values member must be static " + member);
+    }
+
+    // If there isn't a values member but the parameter is an enum, we default
+    // to EnumSet.allOf.
+    if (member == null && field.getType().isEnum()) {
+      returnType = Collection.class;
+      result = new Parameter<Object>(field) {
+        // TODO: figure out the simplest way to make this compile and be green in IDEA too
+        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType", "RedundantCast"})
+        // guarded above
+        @Override public Collection<Object> values() throws Exception {
+          Set<Enum> set = EnumSet.allOf((Class<Enum>) field.getType());
+          return (Collection) set;
+        }
+      };
+    }
+
     if (result == null) {
-      throw new ConfigurationException("No values member defined for " + field);
-    }
-
-    if (!Modifier.isStatic(member.getModifiers())) {
-      throw new ConfigurationException("Values member must be static " + member);
-    }
-
-    // validate return type
-    boolean valid = false;
-    if (returnType instanceof ParameterizedType) {
-      ParameterizedType type = (ParameterizedType) returnType;
-      if (type.getRawType() == Collection.class) {
-        valid = true;
-      }
-    }
-
-    if (!valid) {
+      return new Parameter<Object>(field) {
+        @Override public Collection<Object> values() {
+          // TODO: need tests to make sure this fails properly when no cmdline params given and
+          // works properly when they are given
+          return Collections.emptySet();
+        }
+      };
+    } else if (!isValidReturnType(returnType)) {
       throw new ConfigurationException("Invalid return type " + returnType
           + " for values member " + member + "; must be Collection");
     }
-
     return result;
   }
 
+  private static boolean isValidReturnType(Type returnType) {
+    if (returnType == Collection.class) {
+      return true;
+    }
+    if (returnType instanceof ParameterizedType) {
+      ParameterizedType type = (ParameterizedType) returnType;
+      if (type.getRawType() == Collection.class) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   /**
    * Sets the value of this property to the specified value for the given suite.
    */
@@ -129,7 +176,7 @@
   /**
    * Returns the field's name.
    */
-  public String getName() {
+  String getName() {
     return field.getName();
   }
-}
\ No newline at end of file
+}
diff --git a/src/com/google/caliper/Result.java b/src/com/google/caliper/Result.java
deleted file mode 100644
index 888a9f4..0000000
--- a/src/com/google/caliper/Result.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Copyright (C) 2009 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.caliper;
-
-import com.google.common.collect.ImmutableMap;
-
-import java.util.Map;
-
-/**
- * The complete result of a benchmark suite run.
- */
-final class Result {
-
-  private final ImmutableMap<Run, Double> measurements;
-
-  public Result(Map<Run, Double> measurements) {
-    this.measurements = ImmutableMap.copyOf(measurements);
-  }
-
-  public ImmutableMap<Run, Double> getMeasurements() {
-    return measurements;
-  }
-}
diff --git a/src/com/google/caliper/Run.java b/src/com/google/caliper/Run.java
index a9109de..f2e71de 100644
--- a/src/com/google/caliper/Run.java
+++ b/src/com/google/caliper/Run.java
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (C) 2009 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,33 +16,77 @@
 
 package com.google.caliper;
 
-import com.google.common.collect.ImmutableMap;
-
-import java.lang.reflect.Method;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 /**
- * A configured benchmark.
+ * The complete result of a benchmark suite run.
+ *
+ * <p>Gwt-safe.
  */
-final class Run {
+public final class Run
+    implements Serializable /* for GWT Serialization */ {
 
-  private final ImmutableMap<String, String> parameters;
-  private final String vm;
+  private /*final*/ Map<Scenario, Double> measurements;
+  private /*final*/ String benchmarkName;
+  private /*final*/ String executedByUuid;
+  private /*final*/ long executedTimestamp;
 
-  public Run(Map<String, String> parameters, String vm) {
-    this.parameters = ImmutableMap.copyOf(parameters);
-    this.vm = vm;
+  // TODO: add more run properites such as checksums of the executed code
+
+  public Run(Map<Scenario, Double> measurements,
+      String benchmarkName, String executedByUuid, Date executedTimestamp) {
+    if (benchmarkName == null || executedByUuid == null || executedTimestamp == null) {
+      throw new NullPointerException();
+    }
+
+    this.measurements = new LinkedHashMap<Scenario, Double>(measurements);
+    this.benchmarkName = benchmarkName;
+    this.executedByUuid = executedByUuid;
+    this.executedTimestamp = executedTimestamp.getTime();
   }
 
-  public ImmutableMap<String, String> getParameters() {
-    return parameters;
+  public Map<Scenario, Double> getMeasurements() {
+    return measurements;
   }
 
-  public String getVm() {
-    return vm;
+  public String getBenchmarkName() {
+    return benchmarkName;
+  }
+
+  public String getExecutedByUuid() {
+    return executedByUuid;
+  }
+
+  public Date getExecutedTimestamp() {
+    return new Date(executedTimestamp);
+  }
+
+  @Override public boolean equals(Object o) {
+    if (o instanceof Run) {
+      Run that = (Run) o;
+      return measurements.equals(that.measurements)
+          && benchmarkName.equals(that.benchmarkName)
+          && executedByUuid.equals(that.executedByUuid)
+          && executedTimestamp == that.executedTimestamp;
+    }
+
+    return false;
+  }
+
+  @Override public int hashCode() {
+    int result = measurements.hashCode();
+    result = result * 37 + benchmarkName.hashCode();
+    result = result * 37 + executedByUuid.hashCode();
+    result = result * 37 + (int) ((executedTimestamp >> 32) ^ executedTimestamp);
+    return result;
   }
 
   @Override public String toString() {
-    return "Run" + parameters;
+    return measurements.toString();
   }
+
+  private Run() {} // for GWT Serialization
 }
diff --git a/src/com/google/caliper/Runner.java b/src/com/google/caliper/Runner.java
index 72442db..e359df8 100644
--- a/src/com/google/caliper/Runner.java
+++ b/src/com/google/caliper/Runner.java
@@ -16,180 +16,113 @@
 
 package com.google.caliper;
 
+import com.google.caliper.UserException.ExceptionFromUserCodeException;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Multimap;
-
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.ObjectArrays;
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.UUID;
 
 /**
  * Creates, executes and reports benchmark runs.
  */
 public final class Runner {
 
-  private String suiteClassName;
-  private Benchmark suite;
-
-  /** Effective parameters to run in the benchmark. */
-  private Multimap<String, String> parameters = LinkedHashMultimap.create();
-
-  /** JVMs to run in the benchmark */
-  private Set<String> userVms = new LinkedHashSet<String>();
+  /** Command line arguments to the process */
+  private Arguments arguments;
+  private ScenarioSelection scenarioSelection;
 
   /**
-   * Parameter values specified by the user on the command line. Parameters with
-   * no value in this multimap will get their values from the benchmark suite.
+   * Returns the UUID of the executing host. Multiple runs by the same user on
+   * the same machine should yield the same result.
    */
-  private Multimap<String, String> userParameters = LinkedHashMultimap.create();
-
-  /**
-   * True if each benchmark should run in process.
-   */
-  private boolean inProcess;
-
-  private long warmupMillis = 5000;
-  private long runMillis = 5000;
-
-  /**
-   * Sets the named parameter to the specified value. This value will replace
-   * the benchmark suite's default values for the parameter. Multiple calls to
-   * this method will cause benchmarks for each value to be run.
-   */
-  void setParameter(String name, String value) {
-    userParameters.put(name, value);
-  }
-
-  private void prepareSuite() {
+  private String getExecutedByUuid() {
     try {
-      @SuppressWarnings("unchecked") // guarded by the if statement that follows
-      Class<? extends Benchmark> suiteClass
-          = (Class<? extends Benchmark>) Class.forName(suiteClassName);
-      if (!Benchmark.class.isAssignableFrom(suiteClass)) {
-        throw new ConfigurationException(suiteClass + " is not a benchmark suite.");
+      File dotCaliperRc = new File(System.getProperty("user.home"), ".caliperrc");
+      Properties properties = new Properties();
+      if (dotCaliperRc.exists()) {
+        properties.load(new FileInputStream(dotCaliperRc));
       }
 
-      Constructor<? extends Benchmark> constructor = suiteClass.getDeclaredConstructor();
-      suite = constructor.newInstance();
-    } catch (InvocationTargetException e) {
-      throw new ExecutionException(e.getCause());
-    } catch (Exception e) {
-      throw new ConfigurationException(e);
+      String userUuid = properties.getProperty("userUuid");
+      if (userUuid == null) {
+        userUuid = UUID.randomUUID().toString();
+        properties.setProperty("userUuid", userUuid);
+        properties.store(new FileOutputStream(dotCaliperRc), "");
+      }
+
+      return userUuid;
+    } catch (IOException e) {
+      throw new RuntimeException(e);
     }
   }
 
-  private void prepareParameters() {
-    for (String key : suite.parameterNames()) {
-      // first check if the user has specified values
-      Collection<String> userValues = userParameters.get(key);
-      if (!userValues.isEmpty()) {
-        parameters.putAll(key, userValues);
-        // TODO: type convert 'em to validate?
+  public void run(String... args) {
+    this.arguments = Arguments.parse(args);
+    this.scenarioSelection = new ScenarioSelection(arguments);
+    Run run = runOutOfProcess();
+    new ConsoleReport(run).displayResults();
+    postResults(run);
+  }
 
-      } else { // otherwise use the default values from the suite
-        Set<String> values = suite.parameterValues(key);
-        if (values.isEmpty()) {
-          throw new ConfigurationException(key + " has no values");
-        }
-        parameters.putAll(key, values);
+  private void postResults(Run run) {
+    String postHost = arguments.getPostHost();
+    if ("none".equals(postHost)) {
+      return;
+    }
+
+    try {
+      URL url = new URL(postHost + run.getExecutedByUuid() + "/" + run.getBenchmarkName());
+      HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+      urlConnection.setDoOutput(true);
+      Xml.runToXml(run, urlConnection.getOutputStream());
+      if (urlConnection.getResponseCode() == 200) {
+        System.out.println("");
+        System.out.println("View current and previous benchmark results online:");
+        System.out.println("  " + url);
+        return;
       }
+
+      System.out.println("Posting to " + postHost + " failed: "
+          + urlConnection.getResponseMessage());
+      BufferedReader reader = new BufferedReader(
+          new InputStreamReader(urlConnection.getInputStream()));
+      String line;
+      while ((line = reader.readLine()) != null) {
+        System.out.println(line);
+      }
+    } catch (IOException e) {
+      throw new RuntimeException(e);
     }
   }
 
-  private ImmutableSet<String> defaultVms() {
-    return "Dalvik".equals(System.getProperty("java.vm.name"))
-        ? ImmutableSet.of("dalvikvm")
-        : ImmutableSet.of("java");
-  }
-
-  /**
-   * Returns a complete set of runs with every combination of values and
-   * benchmark classes.
-   */
-  private List<Run> createRuns() throws Exception {
-    List<RunBuilder> builders = new ArrayList<RunBuilder>();
-
-    // create runs for each VMs
-    Set<String> vms = userVms.isEmpty()
-        ? defaultVms()
-        : userVms;
-    for (String vm : vms) {
-      RunBuilder runBuilder = new RunBuilder();
-      runBuilder.vm = vm;
-      builders.add(runBuilder);
-    }
-
-    for (Map.Entry<String, Collection<String>> parameter : parameters.asMap().entrySet()) {
-      Iterator<String> values = parameter.getValue().iterator();
-      if (!values.hasNext()) {
-        throw new ConfigurationException("Not enough values for " + parameter);
-      }
-
-      String key = parameter.getKey();
-
-      String firstValue = values.next();
-      for (RunBuilder builder : builders) {
-        builder.parameters.put(key, firstValue);
-      }
-
-      // multiply the size of the specs by the number of alternate values
-      int size = builders.size();
-      while (values.hasNext()) {
-        String alternate = values.next();
-        for (int s = 0; s < size; s++) {
-          RunBuilder copy = builders.get(s).copy();
-          copy.parameters.put(key, alternate);
-          builders.add(copy);
-        }
-      }
-    }
-
-    List<Run> result = new ArrayList<Run>();
-    for (RunBuilder builder : builders) {
-      result.add(builder.build());
-    }
-
-    return result;
-  }
-
-  static class RunBuilder {
-    Map<String, String> parameters = new LinkedHashMap<String, String>();
-    String vm;
-
-    RunBuilder copy() {
-      RunBuilder result = new RunBuilder();
-      result.parameters.putAll(parameters);
-      result.vm = vm;
-      return result;
-    }
-
-    public Run build() {
-      return new Run(parameters, vm);
-    }
-  }
-
-  private double executeForked(Run run) {
+  private double executeForked(Scenario scenario) {
     ProcessBuilder builder = new ProcessBuilder();
     List<String> command = builder.command();
-    command.addAll(Arrays.asList(run.getVm().split("\\s+")));
+    command.addAll(Arrays.asList(scenario.getVariables().get(Scenario.VM_KEY).split("\\s+")));
     command.add("-cp");
     command.add(System.getProperty("java.class.path"));
-    command.add(Runner.class.getName());
+    command.add(InProcessRunner.class.getName());
     command.add("--warmupMillis");
-    command.add(String.valueOf(warmupMillis));
+    command.add(String.valueOf(arguments.getWarmupMillis()));
     command.add("--runMillis");
-    command.add(String.valueOf(runMillis));
-    command.add("--inProcess");
-    for (Map.Entry<String, String> entry : run.getParameters().entrySet()) {
+    command.add(String.valueOf(arguments.getRunMillis()));
+    for (Entry<String, String> entry : scenario.getParameters().entrySet()) {
       command.add("-D" + entry.getKey() + "=" + entry.getValue());
     }
-    command.add(suiteClassName);
+    command.add(arguments.getSuiteClassName());
 
     BufferedReader reader = null;
     try {
@@ -202,7 +135,7 @@
       Double nanosPerTrial = null;
       try {
         nanosPerTrial = Double.valueOf(firstLine);
-      } catch (NumberFormatException e) {
+      } catch (NumberFormatException ignore) {
       }
 
       String anotherLine = reader.readLine();
@@ -229,163 +162,63 @@
     }
   }
 
-  private Result runOutOfProcess() {
-    ImmutableMap.Builder<Run, Double> resultsBuilder = ImmutableMap.builder();
+  // TODO: check if this is platform-independent
+  @SuppressWarnings("HardcodedLineSeparator")
+  private static final String RETURN = "\r";
+
+  private Run runOutOfProcess() {
+    String executedByUuid = getExecutedByUuid();
+    Date executedDate = new Date();
+    Builder<Scenario, Double> resultsBuilder = ImmutableMap.builder();
 
     try {
-      List<Run> runs = createRuns();
+      List<Scenario> scenarios = scenarioSelection.select();
       int i = 0;
-      for (Run run : runs) {
-        beforeRun(i++, runs.size(), run);
-        double nanosPerTrial = executeForked(run);
-        afterRun(nanosPerTrial);
-        resultsBuilder.put(run, nanosPerTrial);
+      for (Scenario scenario : scenarios) {
+        beforeMeasurement(i++, scenarios.size(), scenario);
+        double nanosPerTrial = executeForked(scenario);
+        afterMeasurement(nanosPerTrial);
+        resultsBuilder.put(scenario, nanosPerTrial);
       }
 
       // blat out our progress bar
-      System.out.print("\r");
+      System.out.print(RETURN);
       for (int j = 0; j < 80; j++) {
         System.out.print(" ");
       }
-      System.out.print("\r");
+      System.out.print(RETURN);
 
-      return new Result(resultsBuilder.build());
+      return new Run(resultsBuilder.build(), arguments.getSuiteClassName(), executedByUuid, executedDate);
     } catch (Exception e) {
-      throw new ExecutionException(e);
+      throw new ExceptionFromUserCodeException(e);
     }
   }
 
-  private void beforeRun(int index, int total, Run run) {
+  private void beforeMeasurement(int index, int total, Scenario scenario) {
     double percentDone = (double) index / total;
     int runStringLength = 63; // so the total line length is 80
-    String runString = String.valueOf(run);
+    String runString = String.valueOf(scenario);
     if (runString.length() > runStringLength) {
       runString = runString.substring(0, runStringLength);
     }
-    System.out.printf("\r%2.0f%% %-" + runStringLength + "s",
+    System.out.printf(RETURN + "%2.0f%% %-" + runStringLength + "s",
         percentDone * 100, runString);
   }
 
-  private void afterRun(double nanosPerTrial) {
+  private void afterMeasurement(double nanosPerTrial) {
     System.out.printf(" %10.0fns", nanosPerTrial);
   }
 
-  private void runInProcess() {
+  public static void main(String... args) {
     try {
-      Caliper caliper = new Caliper(warmupMillis, runMillis);
-
-      for (Run run : createRuns()) {
-        double result;
-        TimedRunnable timedRunnable = suite.createBenchmark(run.getParameters());
-        double warmupNanosPerTrial = caliper.warmUp(timedRunnable);
-        result = caliper.run(timedRunnable, warmupNanosPerTrial);
-        double nanosPerTrial = result;
-        System.out.println(nanosPerTrial);
-      }
-    } catch (Exception e) {
-      throw new ExecutionException(e);
+      new Runner().run(args);
+    } catch (UserException e) {
+      e.display();
+      System.exit(1);
     }
   }
 
-  private boolean parseArgs(String[] args) throws Exception {
-    for (int i = 0; i < args.length; i++) {
-      if ("--help".equals(args[i])) {
-        return false;
-
-      } else if ("--inProcess".equals(args[i])) {
-          inProcess = true;
-
-      } else if (args[i].startsWith("-D")) {
-        int equalsSign = args[i].indexOf('=');
-        if (equalsSign == -1) {
-          System.out.println("Malformed parameter " + args[i]);
-          return false;
-        }
-        String name = args[i].substring(2, equalsSign);
-        String value = args[i].substring(equalsSign + 1);
-        setParameter(name, value);
-
-      } else if ("--warmupMillis".equals(args[i])) {
-        warmupMillis = Long.parseLong(args[++i]);
-
-      } else if ("--runMillis".equals(args[i])) {
-        runMillis = Long.parseLong(args[++i]);
-
-      } else if ("--vm".equals(args[i])) {
-        userVms.add(args[++i]);
-
-      } else if (args[i].startsWith("-")) {
-        System.out.println("Unrecognized option: " + args[i]);
-        return false;
-
-      } else {
-        if (suiteClassName != null) {
-          System.out.println("Too many benchmark classes!");
-          return false;
-        }
-        suiteClassName = args[i];
-      }
-    }
-
-    if (inProcess && !userVms.isEmpty()) {
-      System.out.println("Cannot customize VM when running in process");
-      return false;
-    }
-
-    if (suiteClassName == null) {
-      System.out.println("No benchmark class provided.");
-      return false;
-    }
-
-    return true;
-  }
-
-  private void printUsage() {
-    System.out.println("Usage: Runner [OPTIONS...] <benchmark>");
-    System.out.println();
-    System.out.println("  <benchmark>: a benchmark class or suite");
-    System.out.println();
-    System.out.println("OPTIONS");
-    System.out.println();
-    System.out.println("  --D<param>=<value>: fix a benchmark parameter to a given value.");
-    System.out.println("        When multiple values for the same parameter are given (via");
-    System.out.println("        multiple --Dx=y args), all supplied values are used.");
-    System.out.println();
-    System.out.println("  --inProcess: run the benchmark in the same JVM rather than spawning");
-    System.out.println("        another with the same classpath. By default each benchmark is");
-    System.out.println("        run in a separate VM");
-    System.out.println();
-    System.out.println("  --warmupMillis <millis>: duration to warmup each benchmark");
-    System.out.println();
-    System.out.println("  --runMillis <millis>: duration to execute each benchmark");
-    System.out.println();
-    System.out.println("  --vm <vm>: executable to test benchmark on");
-
-    // adding new options? don't forget to update executeForked()
-  }
-
-  public static void main(String... args) throws Exception { // TODO: cleaner error reporting
-    Runner runner = new Runner();
-    if (!runner.parseArgs(args)) {
-      runner.printUsage();
-      return;
-    }
-
-    runner.prepareSuite();
-    runner.prepareParameters();
-    if (runner.inProcess) {
-      runner.runInProcess();
-      return;
-    }
-
-    Result result = runner.runOutOfProcess();
-    new ConsoleReport(result).displayResults();
-  }
-
-  public static void main(Class<? extends Benchmark> suite, String... args) throws Exception {
-    String[] argsWithSuiteName = new String[args.length + 1];
-    System.arraycopy(args, 0, argsWithSuiteName, 0, args.length);
-    argsWithSuiteName[args.length] = suite.getName();
-    main(argsWithSuiteName);
+  public static void main(Class<? extends Benchmark> suite, String... args) {
+    main(ObjectArrays.concat(args, suite.getName()));
   }
 }
diff --git a/src/com/google/caliper/Scenario.java b/src/com/google/caliper/Scenario.java
new file mode 100644
index 0000000..3fd06e4
--- /dev/null
+++ b/src/com/google/caliper/Scenario.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2009 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.caliper;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A configured benchmark.
+ *
+ * <p>Gwt-safe.
+ */
+public final class Scenario
+    implements Serializable /* for GWT */  {
+
+  static final String VM_KEY = "vm";
+
+  /**
+   * The subset of variable names that are managed by the system. It is an error
+   * to create a parameter with the same name as one of these variables.
+   */
+  static final Set<String> SYSTEM_VARIABLES = new HashSet<String>(Arrays.asList(VM_KEY));
+
+  private /*final*/ Map<String, String> variables;
+
+  public Scenario(Map<String, String> variables) {
+    this.variables = new LinkedHashMap<String, String>(variables);
+  }
+
+  public Map<String, String> getVariables() {
+    return variables;
+  }
+
+  /**
+   * Returns the user-specified parameters. This is the (possibly-empty) set of
+   * variables that may be varied from scenario to scenario in the same
+   * environment.
+   */
+  public Map<String, String> getParameters() {
+    Map<String, String> result = new LinkedHashMap<String, String>();
+    for (Map.Entry<String, String> entry : variables.entrySet()) {
+      if (!SYSTEM_VARIABLES.contains(entry.getKey())) {
+        result.put(entry.getKey(), entry.getValue());
+      }
+    }
+    return result;
+  }
+
+  @Override public boolean equals(Object o) {
+    return o instanceof Scenario
+        && ((Scenario) o).getVariables().equals(variables);
+  }
+
+  @Override public int hashCode() {
+    return variables.hashCode();
+  }
+
+  @Override public String toString() {
+    return "Scenario" + variables;
+  }
+
+  private Scenario() {} // for GWT
+}
diff --git a/src/com/google/caliper/ScenarioSelection.java b/src/com/google/caliper/ScenarioSelection.java
new file mode 100644
index 0000000..7814818
--- /dev/null
+++ b/src/com/google/caliper/ScenarioSelection.java
@@ -0,0 +1,208 @@
+/*
+ * 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.caliper;
+
+import com.google.caliper.UserException.AbstractBenchmarkException;
+import com.google.caliper.UserException.DoesntImplementBenchmarkException;
+import com.google.caliper.UserException.ExceptionFromUserCodeException;
+import com.google.caliper.UserException.NoParameterlessConstructorException;
+import com.google.caliper.UserException.NoSuchClassException;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Figures out which scenarios to benchmark given a benchmark suite, set of user
+ * parameters, and set of user VMs.
+ */
+public final class ScenarioSelection {
+
+  private final String suiteClassName;
+  private final Multimap<String, String> userParameters;
+  private final Set<String> userVms;
+
+  private Benchmark suite;
+
+  /** Effective parameters to run in the benchmark. */
+  private final Multimap<String, String> parameters = LinkedHashMultimap.create();
+
+  public ScenarioSelection(Arguments arguments) {
+    this(arguments.getSuiteClassName(), arguments.getUserParameters(), arguments.getUserVms());
+  }
+
+  public ScenarioSelection(String suiteClassName,
+      Multimap<String, String> userParameters, Set<String> userVms) {
+    this.suiteClassName = suiteClassName;
+    this.userParameters = userParameters;
+    this.userVms = userVms;
+  }
+
+  /**
+   * Returns the selected scenarios for this benchmark.
+   */
+  public List<Scenario> select() {
+    prepareSuite();
+    prepareParameters();
+    return createScenarios();
+  }
+
+  public TimedRunnable createBenchmark(Scenario scenario) {
+    return suite.createBenchmark(scenario.getParameters());
+  }
+
+  private void prepareSuite() {
+    Class<?> benchmarkClass;
+    try {
+      benchmarkClass = getClassByName(suiteClassName);
+    } catch (ExceptionInInitializerError e) {
+      throw new ExceptionFromUserCodeException(e.getCause());
+    } catch (ClassNotFoundException ignored) {
+      throw new NoSuchClassException(suiteClassName);
+    }
+
+    Object s;
+    try {
+      Constructor<?> constructor = benchmarkClass.getDeclaredConstructor();
+      constructor.setAccessible(true);
+      s = constructor.newInstance();
+    } catch (InstantiationException ignore) {
+      throw new AbstractBenchmarkException(benchmarkClass);
+    } catch (NoSuchMethodException ignore) {
+      throw new NoParameterlessConstructorException(benchmarkClass);
+    } catch (IllegalAccessException impossible) {
+      throw new AssertionError(impossible); // shouldn't happen since we setAccessible(true)
+    } catch (InvocationTargetException e) {
+      throw new ExceptionFromUserCodeException(e.getCause());
+    }
+
+    if (s instanceof Benchmark) {
+      this.suite = (Benchmark) s;
+    } else {
+      throw new DoesntImplementBenchmarkException(benchmarkClass);
+    }
+  }
+
+  private static Class<?> getClassByName(String className) throws ClassNotFoundException {
+    try {
+      return Class.forName(className);
+    } catch (ClassNotFoundException ignored) {
+      // try replacing the last dot with a $, in case that helps
+      // example: tutorial.Tutorial.Benchmark1 becomes tutorial.Tutorial$Benchmark1
+      // amusingly, the $ character means three different things in this one line alone
+      String newName = className.replaceFirst("\\.([^.]+)$", "\\$$1");
+      return Class.forName(newName);
+    }
+  }
+
+  private void prepareParameters() {
+    for (String key : suite.parameterNames()) {
+      // first check if the user has specified values
+      Collection<String> userValues = userParameters.get(key);
+      if (!userValues.isEmpty()) {
+        parameters.putAll(key, userValues);
+        // TODO: type convert 'em to validate?
+
+      } else { // otherwise use the default values from the suite
+        Set<String> values = suite.parameterValues(key);
+        if (values.isEmpty()) {
+          throw new ConfigurationException(key + " has no values");
+        }
+        parameters.putAll(key, values);
+      }
+    }
+  }
+
+  private ImmutableSet<String> defaultVms() {
+    return "Dalvik".equals(System.getProperty("java.vm.name"))
+        ? ImmutableSet.of("dalvikvm")
+        : ImmutableSet.of("java");
+  }
+
+  /**
+   * Returns a complete set of scenarios with every combination of values and
+   * benchmark classes.
+   */
+  private List<Scenario> createScenarios() {
+    List<ScenarioBuilder> builders = new ArrayList<ScenarioBuilder>();
+
+    // create scenarios for each VM
+    Set<String> vms = userVms.isEmpty()
+        ? defaultVms()
+        : userVms;
+    for (String vm : vms) {
+      ScenarioBuilder scenarioBuilder = new ScenarioBuilder();
+      scenarioBuilder.parameters.put(Scenario.VM_KEY, vm);
+      builders.add(scenarioBuilder);
+    }
+
+    for (Entry<String, Collection<String>> parameter : parameters.asMap().entrySet()) {
+      Iterator<String> values = parameter.getValue().iterator();
+      if (!values.hasNext()) {
+        throw new ConfigurationException("Not enough values for " + parameter);
+      }
+
+      String key = parameter.getKey();
+
+      String firstValue = values.next();
+      for (ScenarioBuilder builder : builders) {
+        builder.parameters.put(key, firstValue);
+      }
+
+      // multiply the size of the specs by the number of alternate values
+      int size = builders.size();
+      while (values.hasNext()) {
+        String alternate = values.next();
+        for (int s = 0; s < size; s++) {
+          ScenarioBuilder copy = builders.get(s).copy();
+          copy.parameters.put(key, alternate);
+          builders.add(copy);
+        }
+      }
+    }
+
+    List<Scenario> result = new ArrayList<Scenario>();
+    for (ScenarioBuilder builder : builders) {
+      result.add(builder.build());
+    }
+
+    return result;
+  }
+
+  private static class ScenarioBuilder {
+    final Map<String, String> parameters = new LinkedHashMap<String, String>();
+
+    ScenarioBuilder copy() {
+      ScenarioBuilder result = new ScenarioBuilder();
+      result.parameters.putAll(parameters);
+      return result;
+    }
+
+    public Scenario build() {
+      return new Scenario(parameters);
+    }
+  }
+}
diff --git a/src/com/google/caliper/SimpleBenchmark.java b/src/com/google/caliper/SimpleBenchmark.java
index 8d2d4b1..31ff6c9 100644
--- a/src/com/google/caliper/SimpleBenchmark.java
+++ b/src/com/google/caliper/SimpleBenchmark.java
@@ -16,12 +16,11 @@
 
 package com.google.caliper;
 
+import com.google.caliper.UserException.ExceptionFromUserCodeException;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.lang.reflect.Type;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Map;
@@ -88,34 +87,31 @@
       return methods.keySet();
     }
 
+    Parameter<?> parameter = parameters.get(parameterName);
+    if (parameter == null) {
+      throw new IllegalArgumentException();
+    }
     try {
-      TypeConverter typeConverter = new TypeConverter();
-      Parameter<?> parameter = parameters.get(parameterName);
-      if (parameter == null) {
-        throw new IllegalArgumentException();
-      }
       Collection<?> values = parameter.values();
-      Type type = parameter.getType();
 
       ImmutableSet.Builder<String> result = ImmutableSet.builder();
       for (Object value : values) {
-        result.add(typeConverter.toString(value, type));
+        result.add(String.valueOf(value));
       }
       return result.build();
     } catch (Exception e) {
-      throw new ExecutionException(e);
+      throw new ExceptionFromUserCodeException(e);
     }
   }
 
   public TimedRunnable createBenchmark(Map<String, String> parameterValues) {
-    TypeConverter typeConverter = new TypeConverter();
-
     if (!parameterNames().equals(parameterValues.keySet())) {
       throw new IllegalArgumentException("Invalid parameters specified. Expected "
           + parameterNames() + " but was " + parameterValues.keySet());
     }
 
     try {
+      @SuppressWarnings({"ClassNewInstance"}) // can throw any Exception, so we catch all Exceptions
       final SimpleBenchmark copyOfSelf = getClass().newInstance();
       final Method method = methods.get(parameterValues.get("benchmark"));
 
@@ -125,8 +121,8 @@
           continue;
         }
 
-        Parameter parameter = parameters.get(parameterName);
-        Object value = typeConverter.fromString(entry.getValue(), parameter.getType());
+        Parameter<?> parameter = parameters.get(parameterName);
+        Object value = TypeConverter.fromString(entry.getValue(), parameter.getType());
         parameter.set(copyOfSelf, value);
       }
       copyOfSelf.setUp();
@@ -138,7 +134,7 @@
       };
 
     } catch (Exception e) {
-      throw new ExecutionException(e);
+      throw new ExceptionFromUserCodeException(e);
     }
   }
 
@@ -148,7 +144,7 @@
    */
   private Map<String, Method> createTimedMethods() {
     ImmutableMap.Builder<String, Method> result = ImmutableMap.builder();
-    for (final Method method : getClass().getDeclaredMethods()) {
+    for (Method method : getClass().getDeclaredMethods()) {
       int modifiers = method.getModifiers();
       if (!method.getName().startsWith("time")) {
         continue;
diff --git a/src/com/google/caliper/TypeConverter.java b/src/com/google/caliper/TypeConverter.java
index 73300ec..29d00ea 100644
--- a/src/com/google/caliper/TypeConverter.java
+++ b/src/com/google/caliper/TypeConverter.java
@@ -16,42 +16,44 @@
 
 package com.google.caliper;
 
+import com.google.common.collect.ImmutableMap;
+import java.lang.reflect.Method;
 import java.lang.reflect.Type;
+import java.util.Map;
 
 /**
  * Convert objects to and from Strings.
  */
-class TypeConverter {
+final class TypeConverter {
+  private TypeConverter() {}
 
-  // the enum to strings conversion is manually checked
+  public static Object fromString(String value, Type type) {
+    Class<?> c = wrap((Class<?>) type);
+    try {
+      Method m = c.getMethod("valueOf", String.class);
+      return m.invoke(null, value);
+    } catch (Exception e) {
+      throw new UnsupportedOperationException(
+          "Cannot convert " + value + " of type " + type, e);
+    }
+  }
+
+  // safe because both Long.class and long.class are of type Class<Long>
   @SuppressWarnings("unchecked")
-  public Object fromString(String value, Type type) {
-    if (type instanceof Class) {
-      Class<?> c = (Class<?>) type;
-      if (c.isEnum()) {
-          return Enum.valueOf((Class) c, value);
-      } else if (type == Double.class || type == double.class) {
-        return Double.valueOf(value);
-      } else if (type == Integer.class || type == int.class) {
-        return Integer.valueOf(value);
-      }
-    }
-    throw new UnsupportedOperationException(
-        "Cannot convert " + value + " of type " + type);
+  private static <T> Class<T> wrap(Class<T> c) {
+    return c.isPrimitive() ? (Class<T>) PRIMITIVES_TO_WRAPPERS.get(c) : c;
   }
 
-  public String toString(Object value, Type type) {
-    if (type instanceof Class) {
-      Class<?> c = (Class<?>) type;
-      if (c.isEnum()) {
-        return value.toString();
-      } else if (type == Double.class || type == double.class) {
-        return value.toString();
-      } else if (type == Integer.class || type == int.class) {
-        return value.toString();
-      }
-    }
-    throw new UnsupportedOperationException(
-        "Cannot convert " + value + " of type " + type);
-  }
+  private static final Map<Class<?>, Class<?>> PRIMITIVES_TO_WRAPPERS
+    = new ImmutableMap.Builder<Class<?>, Class<?>>()
+      .put(boolean.class, Boolean.class)
+      .put(byte.class, Byte.class)
+      .put(char.class, Character.class)
+      .put(double.class, Double.class)
+      .put(float.class, Float.class)
+      .put(int.class, Integer.class)
+      .put(long.class, Long.class)
+      .put(short.class, Short.class)
+      .put(void.class, Void.class)
+      .build();
 }
diff --git a/src/com/google/caliper/UserException.java b/src/com/google/caliper/UserException.java
new file mode 100644
index 0000000..66fb8e3
--- /dev/null
+++ b/src/com/google/caliper/UserException.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2009 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.caliper;
+
+import java.util.Arrays;
+
+/**
+ * Signifies a problem that should be explained in user-friendly terms on the command line, without
+ * a confusing stack trace, and optionally followed by a usage summary.
+ */
+@SuppressWarnings("serial") // never going to serialize these... right?
+public abstract class UserException extends RuntimeException {
+  protected final String error;
+
+  protected UserException(String error) {
+    this.error = error;
+  }
+
+  public abstract void display();
+
+  // - - - -
+
+  public abstract static class ErrorInUsageException extends UserException {
+    protected ErrorInUsageException(String error) {
+      super(error);
+    }
+
+    @Override public void display() {
+      if (error != null) {
+        System.err.println("Error: " + error);
+      }
+      Arguments.printUsage();
+    }
+  }
+
+  public abstract static class ErrorInUserCodeException extends UserException {
+    private final String remedy;
+
+    protected ErrorInUserCodeException(String error, String remedy) {
+      super(error);
+      this.remedy = remedy;
+    }
+
+    @Override public void display() {
+      System.err.println("Error: " + error);
+      System.err.println("Typical Remedy: " + remedy);
+    }
+  }
+
+  // - - - -
+
+  // Not technically an error, but works nicely this way anyway
+  public static class DisplayUsageException extends ErrorInUsageException {
+    public DisplayUsageException() {
+      super(null);
+    }
+  }
+
+  public static class UnrecognizedOptionException extends ErrorInUsageException {
+    public UnrecognizedOptionException(String arg) {
+      super("Argument not recognized: " + arg);
+    }
+  }
+
+  public static class NoBenchmarkClassException extends ErrorInUsageException {
+    public NoBenchmarkClassException() {
+      super("No benchmark class specified.");
+    }
+  }
+
+  public static class MultipleBenchmarkClassesException extends ErrorInUsageException {
+    public MultipleBenchmarkClassesException(String a, String b) {
+      super("Multiple benchmark classes specified: " + Arrays.asList(a, b));
+    }
+  }
+
+  public static class MalformedParameterException extends ErrorInUsageException {
+    public MalformedParameterException(String arg) {
+      super("Malformed parameter: " + arg);
+    }
+  }
+
+  public static class CantCustomizeInProcessVmException extends ErrorInUsageException {
+    public CantCustomizeInProcessVmException() {
+      super("Can't customize VM when running in process.");
+    }
+  }
+
+  public static class NoSuchClassException extends ErrorInUsageException {
+    public NoSuchClassException(String name) {
+      super("No class named [" + name + "] was found (check CLASSPATH).");
+    }
+  }
+
+
+  public static class AbstractBenchmarkException extends ErrorInUserCodeException {
+    public AbstractBenchmarkException(Class<?> specifiedClass) {
+      super("Class [" + specifiedClass.getName() + "] is abstract.", "Specify a concrete class.");
+    }
+  }
+
+  public static class NoParameterlessConstructorException extends ErrorInUserCodeException {
+    public NoParameterlessConstructorException(Class<?> specifiedClass) {
+      super("Class [" + specifiedClass.getName() + "] has no parameterless constructor.",
+          "Remove all constructors or add a parameterless constructor.");
+    }
+  }
+
+  public static class DoesntImplementBenchmarkException extends ErrorInUserCodeException {
+    public DoesntImplementBenchmarkException(Class<?> specifiedClass) {
+      super("Class [" + specifiedClass + "] does not implement the " + Benchmark.class.getName()
+          + " interface.", "Add 'extends " + SimpleBenchmark.class + "' to the class declaration.");
+    }
+  }
+
+  // TODO: should remove the caliper stack frames....
+  public static class ExceptionFromUserCodeException extends UserException {
+    public ExceptionFromUserCodeException(Throwable t) {
+      super("An exception was thrown from the benchmark code.");
+      initCause(t);
+    }
+    @Override public void display() {
+      System.err.println(error);
+      getCause().printStackTrace(System.err);
+    }
+  }
+}
diff --git a/src/com/google/caliper/Xml.java b/src/com/google/caliper/Xml.java
new file mode 100644
index 0000000..f7cfafc
--- /dev/null
+++ b/src/com/google/caliper/Xml.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright (C) 2009 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.caliper;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+
+public final class Xml {
+  private static final String DATE_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssz";
+
+  /**
+   * Encodes this result as XML to the specified stream. This XML can be parsed
+   * with {@link #runFromXml(InputStream)}. Sample output:
+   * <pre>{@code
+   * <result benchmark="examples.FooBenchmark"
+   *     executedBy="A0:1F:CAFE:BABE"
+   *     executedTimestamp="2010-01-05T11:08:15PST">
+   *   <scenario bar="15" foo="A" vm="dalvikvm">1200.1</scenario>
+   *   <scenario bar="15" foo="B" vm="dalvikvm">1100.2</scenario>
+   * </result>
+   * }</pre>
+   */
+  public static void runToXml(Run run, OutputStream out) {
+    // BEGIN android-removed
+    //     we don't have DOM level 3 on Android yet
+    // try {
+    //   Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+    //   Element result = doc.createElement("result");
+    //   doc.appendChild(result);
+    //
+    //   result.setAttribute("benchmark", run.getBenchmarkName());
+    //   result.setAttribute("executedBy", run.getExecutedByUuid());
+    //   String executedTimestampString = new SimpleDateFormat(DATE_FORMAT_STRING)
+    //       .format(run.getExecutedTimestamp());
+    //   result.setAttribute("executedTimestamp", executedTimestampString);
+    //
+    //   for (Map.Entry<Scenario, Double> entry : run.getMeasurements().entrySet()) {
+    //     Element runElement = doc.createElement("scenario");
+    //     result.appendChild(runElement);
+    //
+    //     Scenario scenario = entry.getKey();
+    //     for (Map.Entry<String, String> parameter : scenario.getVariables().entrySet()) {
+    //       runElement.setAttribute(parameter.getKey(), parameter.getValue());
+    //     }
+    //     runElement.setTextContent(String.valueOf(entry.getValue()));
+    //   }
+    //
+    //   TransformerFactory.newInstance().newTransformer()
+    //       .transform(new DOMSource(doc), new StreamResult(out));
+    // } catch (Exception e) {
+    //   throw new IllegalStateException("Malformed XML document", e);
+    // }
+    // END android-removed
+  }
+
+  /**
+   * Creates a result by decoding XML from the specified stream. The XML should
+   * be consistent with the format emitted by {@link #runToXml(Run, OutputStream)}.
+   */
+  public static Run runFromXml(InputStream in) {
+    // BEGIN android-removed
+    //     we don't have DOM level 3 on Android yet
+    throw new UnsupportedOperationException();
+    // try {
+    //   Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in);
+    //   Element result = document.getDocumentElement();
+    // 
+    //   String benchmarkName = result.getAttribute("benchmark");
+    //   String executedByUuid = result.getAttribute("executedBy");
+    //   String executedDateString = result.getAttribute("executedTimestamp");
+    //   Date executedDate = new SimpleDateFormat(DATE_FORMAT_STRING).parse(executedDateString);
+    //
+    //   ImmutableMap.Builder<Scenario, Double> measurementsBuilder = ImmutableMap.builder();
+    //   for (Node node : childrenOf(result)) {
+    //     Element scenarioElement = (Element) node;
+    //     Scenario scenario = new Scenario(attributesOf(scenarioElement));
+    //     double measurement = Double.parseDouble(scenarioElement.getTextContent());
+    //     measurementsBuilder.put(scenario, measurement);
+    //   }
+    //
+    //   return new Run(measurementsBuilder.build(), benchmarkName, executedByUuid, executedDate);
+    // } catch (Exception e) {
+    //   throw new IllegalStateException("Malformed XML document", e);
+    // }
+    // END android-removed
+  }
+
+  private Xml() {}
+}
diff --git a/test/com/google/caliper/examples/ArraySortBenchmark.java b/src/examples/ArraySortBenchmark.java
similarity index 83%
rename from test/com/google/caliper/examples/ArraySortBenchmark.java
rename to src/examples/ArraySortBenchmark.java
index 2978fa2..f42390f 100644
--- a/test/com/google/caliper/examples/ArraySortBenchmark.java
+++ b/src/examples/ArraySortBenchmark.java
@@ -14,15 +14,12 @@
  * limitations under the License.
  */
 
-package com.google.caliper.examples;
+package examples;
 
 import com.google.caliper.Param;
 import com.google.caliper.Runner;
 import com.google.caliper.SimpleBenchmark;
-
 import java.util.Arrays;
-import java.util.Collection;
-import java.util.EnumSet;
 import java.util.Random;
 
 /**
@@ -30,33 +27,26 @@
  */
 public class ArraySortBenchmark extends SimpleBenchmark {
 
-  @Param int length;
+  @Param({"10", "100", "1000", "10000"}) private int length;
 
-  static Collection<Integer> lengthValues = Arrays.asList(10, 100, 1000, 10000);
+  @Param private Distribution distribution;
 
-  @Param Distribution distribution;
-
-  static final Collection<Distribution> distributionValues = EnumSet.allOf(Distribution.class);
-
-  int[] values;
-  int[] copy;
+  private int[] values;
+  private int[] copy;
 
   @Override protected void setUp() throws Exception {
     values = distribution.create(length);
     copy = new int[length];
   }
 
-  public int timeSort(int reps) {
-    int dummy = 0;
+  public void timeSort(int reps) {
     for (int i = 0; i < reps; i++) {
       System.arraycopy(values, 0, copy, 0, values.length);
       Arrays.sort(copy);
-      dummy ^= copy[0];
     }
-    return dummy;
   }
 
-  enum Distribution {
+  public enum Distribution {
     SAWTOOTH {
       @Override
       int[] create(int length) {
diff --git a/test/com/google/caliper/examples/BoxedDoubleToStringBenchmark.java b/src/examples/BoxedDoubleToStringBenchmark.java
similarity index 86%
rename from test/com/google/caliper/examples/BoxedDoubleToStringBenchmark.java
rename to src/examples/BoxedDoubleToStringBenchmark.java
index 5e6cbfa..22cb28e 100644
--- a/test/com/google/caliper/examples/BoxedDoubleToStringBenchmark.java
+++ b/src/examples/BoxedDoubleToStringBenchmark.java
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-package com.google.caliper.examples;
+package examples;
 
-import com.google.caliper.SimpleBenchmark;
 import com.google.caliper.Param;
 import com.google.caliper.Runner;
-
-import java.util.Arrays;
+import com.google.caliper.SimpleBenchmark;
+import com.google.common.collect.ImmutableList;
 import java.util.Collection;
 
 /**
@@ -30,7 +29,9 @@
 
   @Param private Double d;
 
-  private static final Collection<Double> dValues = Arrays.asList(
+  // Expressing these as strings in the annotation parameter would be annoying
+  // (and maybe not possible?)
+  public static final Collection<Double> dValues = ImmutableList.of(
       Math.PI,
       -0.0d,
       Double.NEGATIVE_INFINITY,
@@ -68,7 +69,7 @@
     Double value = d;
     int dummy = 0;
     for (int i = 0; i < reps; i++) {
-      dummy = ("" + value).length();
+      dummy += ("" + value).length();
     }
     return dummy;
   }
diff --git a/src/examples/CharacterBenchmark.java b/src/examples/CharacterBenchmark.java
new file mode 100644
index 0000000..1e013af
--- /dev/null
+++ b/src/examples/CharacterBenchmark.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2009 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 examples;
+
+import com.google.caliper.Param;
+import com.google.caliper.Runner;
+import com.google.caliper.SimpleBenchmark;
+
+/**
+ * Tests various Character methods, intended for testing multiple
+ * implementations against each other.
+ */
+public class CharacterBenchmark extends SimpleBenchmark {
+
+    @Param private CharacterSet characterSet;
+
+    @Param private Overload overload;
+
+    private char[] chars;
+
+    @Override protected void setUp() throws Exception {
+        this.chars = characterSet.chars;
+    }
+
+    public enum Overload { CHAR, INT }
+
+    public enum CharacterSet {
+        ASCII(128),
+        UNICODE(65536);
+        final char[] chars;
+        CharacterSet(int size) {
+            this.chars = new char[65536];
+            for (int i = 0; i < 65536; ++i) {
+                chars[i] = (char) (i % size);
+            }
+        }
+    }
+
+    // A fake benchmark to give us a baseline.
+    public boolean timeIsSpace(int reps) {
+        boolean dummy = false;
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    dummy ^= ((char) ch == ' ');
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    dummy ^= (ch == ' ');
+                }
+            }
+        }
+        return dummy;
+    }
+
+    public void timeDigit(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.digit(chars[ch], 10);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.digit((int) chars[ch], 10);
+                }
+            }
+        }
+    }
+
+    public void timeGetNumericValue(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.getNumericValue(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.getNumericValue((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    public void timeIsDigit(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isDigit(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isDigit((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    public void timeIsIdentifierIgnorable(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isIdentifierIgnorable(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isIdentifierIgnorable((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    public void timeIsJavaIdentifierPart(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isJavaIdentifierPart(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isJavaIdentifierPart((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    public void timeIsJavaIdentifierStart(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isJavaIdentifierStart(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isJavaIdentifierStart((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    public void timeIsLetter(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isLetter(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isLetter((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    public void timeIsLetterOrDigit(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isLetterOrDigit(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isLetterOrDigit((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    public void timeIsLowerCase(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isLowerCase(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isLowerCase((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    public void timeIsSpaceChar(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isSpaceChar(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isSpaceChar((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    public void timeIsUpperCase(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isUpperCase(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isUpperCase((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    public void timeIsWhitespace(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isWhitespace(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.isWhitespace((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    public void timeToLowerCase(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.toLowerCase(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.toLowerCase((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    public void timeToUpperCase(int reps) {
+        if (overload == Overload.CHAR) {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.toUpperCase(chars[ch]);
+                }
+            }
+        } else {
+            for (int i = 0; i < reps; ++i) {
+                for (int ch = 0; ch < 65536; ++ch) {
+                    Character.toUpperCase((int) chars[ch]);
+                }
+            }
+        }
+    }
+
+    // TODO: remove this from all examples when IDE plugins are ready
+    public static void main(String[] args) throws Exception {
+        Runner.main(CharacterBenchmark.class, args);
+    }
+}
diff --git a/test/com/google/caliper/examples/EnumSetContainsBenchmark.java b/src/examples/EnumSetContainsBenchmark.java
similarity index 86%
rename from test/com/google/caliper/examples/EnumSetContainsBenchmark.java
rename to src/examples/EnumSetContainsBenchmark.java
index a9f6f2f..b232514 100644
--- a/test/com/google/caliper/examples/EnumSetContainsBenchmark.java
+++ b/src/examples/EnumSetContainsBenchmark.java
@@ -14,13 +14,11 @@
  * limitations under the License.
  */
 
-package com.google.caliper.examples;
+package examples;
 
 import com.google.caliper.Param;
 import com.google.caliper.Runner;
 import com.google.caliper.SimpleBenchmark;
-
-import java.util.Collection;
 import java.util.EnumSet;
 import java.util.Set;
 
@@ -31,9 +29,7 @@
 
   @Param private SetMaker setMaker;
 
-  private static final Collection<SetMaker> setMakerValues = EnumSet.allOf(SetMaker.class);
-
-  enum SetMaker {
+  public enum SetMaker {
     ENUM_SET {
       @Override Set<?> newSet() {
         return EnumSet.allOf(RegularSize.class);
@@ -57,13 +53,13 @@
     abstract Object[] testValues();
   }
 
-  enum RegularSize {
+  private enum RegularSize {
     E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, E16, E17,
     E18, E19, E20, E21, E22, E23, E24, E25, E26, E27, E28, E29, E30, E31, E32,
     E33, E34, E35, E36, E37, E38, E39, E40,
   }
 
-  enum LargeSize {
+  private enum LargeSize {
     E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, E16, E17,
     E18, E19, E20, E21, E22, E23, E24, E25, E26, E27, E28, E29, E30, E31, E32,
     E33, E34, E35, E36, E37, E38, E39, E40, E41, E42, E43, E44, E45, E46, E47,
@@ -79,20 +75,18 @@
   private Set<?> set;
   private Object[] testValues;
 
-  @Override protected void setUp() throws Exception {
+  @Override protected void setUp() {
     this.set = setMaker.newSet();
     this.testValues = setMaker.testValues();
   }
 
-  public int timeContains(int reps) throws Exception {
-    int dummy = 0;
+  public void timeContains(int reps) {
     for (int i = 0; i < reps; i++) {
-      dummy ^= (set.contains(testValues[i % testValues.length]) ? i : 0);
+      set.contains(testValues[i % testValues.length]);
     }
-    return dummy;
   }
 
   public static void main(String[] args) throws Exception {
     Runner.main(EnumSetContainsBenchmark.class, args);
   }
-}
\ No newline at end of file
+}
diff --git a/test/com/google/caliper/examples/ExpensiveObjectsBenchmark.java b/src/examples/ExpensiveObjectsBenchmark.java
similarity index 87%
rename from test/com/google/caliper/examples/ExpensiveObjectsBenchmark.java
rename to src/examples/ExpensiveObjectsBenchmark.java
index 2dbcf58..ebff8e6 100644
--- a/test/com/google/caliper/examples/ExpensiveObjectsBenchmark.java
+++ b/src/examples/ExpensiveObjectsBenchmark.java
@@ -14,13 +14,10 @@
  * limitations under the License.
  */
 
-package com.google.caliper.examples;
+package examples;
 
-import com.google.caliper.Benchmark;
-import com.google.caliper.Param;
 import com.google.caliper.Runner;
 import com.google.caliper.SimpleBenchmark;
-
 import java.text.DecimalFormatSymbols;
 import java.text.NumberFormat;
 import java.text.SimpleDateFormat;
@@ -29,6 +26,7 @@
 /**
  * Benchmarks creation and cloning various expensive objects.
  */
+@SuppressWarnings({"ResultOfObjectAllocationIgnored"}) // TODO: should fix!
 public class ExpensiveObjectsBenchmark extends SimpleBenchmark {
     public void timeNewDecimalFormatSymbols(int reps) {
         for (int i = 0; i < reps; ++i) {
@@ -68,4 +66,9 @@
             sdf.clone();
         }
     }
+
+    // TODO: remove this from all examples when IDE plugins are ready
+    public static void main(String[] args) throws Exception {
+        Runner.main(ExpensiveObjectsBenchmark.class, args);
+    }
 }
diff --git a/test/com/google/caliper/examples/FormatterBenchmark.java b/src/examples/FormatterBenchmark.java
similarity index 98%
rename from test/com/google/caliper/examples/FormatterBenchmark.java
rename to src/examples/FormatterBenchmark.java
index f61f111..b4a0541 100644
--- a/test/com/google/caliper/examples/FormatterBenchmark.java
+++ b/src/examples/FormatterBenchmark.java
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 
-package com.google.caliper.examples;
+package examples;
 
 import com.google.caliper.Runner;
 import com.google.caliper.SimpleBenchmark;
-
 import java.util.Formatter;
 
 /**
diff --git a/test/com/google/caliper/examples/IntModBenchmark.java b/src/examples/IntModBenchmark.java
similarity index 82%
rename from test/com/google/caliper/examples/IntModBenchmark.java
rename to src/examples/IntModBenchmark.java
index 86e85e7..55a119c 100644
--- a/test/com/google/caliper/examples/IntModBenchmark.java
+++ b/src/examples/IntModBenchmark.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.caliper.examples;
+package examples;
 
 import com.google.caliper.Runner;
 import com.google.caliper.SimpleBenchmark;
@@ -22,6 +22,7 @@
 /**
  * Measures several candidate implementations for mod().
  */
+@SuppressWarnings("SameParameterValue")
 public class IntModBenchmark extends SimpleBenchmark {
   private static final int M = (1 << 16) - 1;
 
@@ -46,8 +47,9 @@
     return dummy;
   }
 
+  @SuppressWarnings("NumericCastThatLosesPrecision") // result of % by an int must be in int range
   private static int doubleRemainderMod(int a, int m) {
-    return (int) (((a % m) + (long) m) % m);
+    return (int) ((a % m + (long) m) % m);
   }
 
   public int timeRightShiftingMod(int reps) {
@@ -58,9 +60,10 @@
     return dummy;
   }
 
+  @SuppressWarnings("NumericCastThatLosesPrecision") // must be in int range
   private static int rightShiftingMod(int a, int m) {
      long r = a % m;
-     return (int) (r + ((r >> 63) & m));
+     return (int) (r + (r >> 63 & m));
   }
 
   public int timeLeftShiftingMod(int reps) {
@@ -71,8 +74,9 @@
     return dummy;
   }
 
+  @SuppressWarnings("NumericCastThatLosesPrecision") // result of % by an int must be in int range
   private static int leftShiftingMod(int a, int m) {
-    return (int) ((a + (((long) m) << 32)) % m);
+    return (int) ((a + ((long) m << 32)) % m);
   }
 
   public int timeWrongMod(int reps) {
diff --git a/test/com/google/caliper/examples/ListIterationBenchmark.java b/src/examples/ListIterationBenchmark.java
similarity index 75%
rename from test/com/google/caliper/examples/ListIterationBenchmark.java
rename to src/examples/ListIterationBenchmark.java
index 53bcdf8..a8cfb05 100644
--- a/test/com/google/caliper/examples/ListIterationBenchmark.java
+++ b/src/examples/ListIterationBenchmark.java
@@ -14,24 +14,21 @@
  * limitations under the License.
  */
 
-package com.google.caliper.examples;
+package examples;
 
 import com.google.caliper.Param;
 import com.google.caliper.Runner;
 import com.google.caliper.SimpleBenchmark;
-
 import java.util.AbstractList;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
 
 /**
  * Measures iterating through list elements.
  */
 public class ListIterationBenchmark extends SimpleBenchmark {
-  @Param private int length;
 
-  private static final Collection<Integer> lengthValues = Arrays.asList(0, 10, 100, 1000);
+  @Param({"0", "10", "100", "1000"})
+  private int length;
 
   private List<Object> list;
   private Object[] array;
@@ -53,24 +50,20 @@
     };
   }
 
-  public int timeListIteration(int reps) {
-    int count = 0;
+  @SuppressWarnings({"UnusedDeclaration"}) // TODO: fix
+  public void timeListIteration(int reps) {
     for (int i = 0; i < reps; i++) {
       for (Object value : list) {
-        count ^= value.hashCode(); // prevent overoptimization
       }
     }
-    return count; // ignored
   }
 
-  public int timeArrayIteration(int reps) {
-    int count = 0;
+  @SuppressWarnings({"UnusedDeclaration"}) // TODO: fix
+  public void timeArrayIteration(int reps) {
     for (int i = 0; i < reps; i++) {
       for (Object value : array) {
-        count ^= value.hashCode(); // prevent overoptimization
       }
     }
-    return count; // ignored
   }
 
   // TODO: remove this from all examples when IDE plugins are ready
diff --git a/src/examples/LoopingBackwardsBenchmark.java b/src/examples/LoopingBackwardsBenchmark.java
new file mode 100644
index 0000000..e98e5fc
--- /dev/null
+++ b/src/examples/LoopingBackwardsBenchmark.java
@@ -0,0 +1,54 @@
+/*
+ * 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 examples;
+
+import com.google.caliper.Param;
+import com.google.caliper.Runner;
+import com.google.caliper.SimpleBenchmark;
+
+/**
+ * Testing the old canard that looping backwards is faster.
+ *
+ * @author Kevin Bourrillion
+ */
+public class LoopingBackwardsBenchmark extends SimpleBenchmark {
+  @Param({"2", "20", "2000", "20000000"}) int max;
+
+  public int timeForwards(int reps) {
+    int dummy = 0;
+    for (int i = 0; i < reps; i++) {
+      for (int j = 0; j < max; j++) {
+        dummy += j;
+      }
+    }
+    return dummy;
+  }
+
+  public int timeBackwards(int reps) {
+    int dummy = 0;
+    for (int i = 0; i < reps; i++) {
+      for (int j = max - 1; j >= 0; j--) {
+        dummy += j;
+      }
+    }
+    return dummy;
+  }
+
+  public static void main(String[] args) throws Exception {
+    Runner.main(LoopingBackwardsBenchmark.class, args);
+  }
+}
diff --git a/test/com/google/caliper/examples/PrimitiveDoubleToStringBenchmark.java b/src/examples/PrimitiveDoubleToStringBenchmark.java
similarity index 93%
rename from test/com/google/caliper/examples/PrimitiveDoubleToStringBenchmark.java
rename to src/examples/PrimitiveDoubleToStringBenchmark.java
index 592acdc..d49a53d 100644
--- a/test/com/google/caliper/examples/PrimitiveDoubleToStringBenchmark.java
+++ b/src/examples/PrimitiveDoubleToStringBenchmark.java
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-package com.google.caliper.examples;
+package examples;
 
-import com.google.caliper.SimpleBenchmark;
 import com.google.caliper.Param;
 import com.google.caliper.Runner;
-
-import java.util.Arrays;
+import com.google.caliper.SimpleBenchmark;
+import com.google.common.collect.ImmutableList;
 import java.util.Collection;
 
 /**
@@ -30,7 +29,7 @@
 
   @Param private double d;
 
-  private static final Collection<Double> dValues = Arrays.asList(
+  public static final Collection<Double> dValues = ImmutableList.of(
       Math.PI,
       -0.0d,
       Double.NEGATIVE_INFINITY,
diff --git a/src/examples/SetContainsBenchmark.java b/src/examples/SetContainsBenchmark.java
new file mode 100644
index 0000000..4185d55
--- /dev/null
+++ b/src/examples/SetContainsBenchmark.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2009 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 examples;
+
+import com.google.caliper.Param;
+import com.google.caliper.Runner;
+import com.google.caliper.SimpleBenchmark;
+import com.google.common.collect.ImmutableSet;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Random;
+import java.util.Set;
+
+/**
+ * A microbenchmark that tests the performance of contains() on various Set
+ * implementations.
+ *
+ * @author Kevin Bourrillion
+ */
+public class SetContainsBenchmark extends SimpleBenchmark {
+  @Param private Impl impl;
+
+  // So far, this is the best way to test various implementations
+  public enum Impl {
+    Hash {
+      @Override Set<Integer> create(Collection<Integer> contents) {
+        return new HashSet<Integer>(contents);
+      }
+    },
+    LinkedHash {
+      @Override Set<Integer> create(Collection<Integer> contents) {
+        return new LinkedHashSet<Integer>(contents);
+      }
+    },
+    UnmodHS {
+      @Override Set<Integer> create(Collection<Integer> contents) {
+        return Collections.unmodifiableSet(new HashSet<Integer>(contents));
+      }
+    },
+    SyncHS {
+      @Override Set<Integer> create(Collection<Integer> contents) {
+        return Collections.synchronizedSet(new HashSet<Integer>(contents));
+      }
+    },
+
+    // Kind of cheating here -- Caliper just happens to bundle Google Collections so I'm testing
+    // this from it; this might not work at the command line since GC are jarjar'd for caliper.jar
+    Immutable {
+      @Override Set<Integer> create(Collection<Integer> contents) {
+        return ImmutableSet.copyOf(contents);
+      }
+    };
+
+    abstract Set<Integer> create(Collection<Integer> contents);
+  }
+
+  @Param private int size;
+  public static final Collection<Integer> sizeValues = Arrays.asList(
+      (1<<2) - 1,
+      (1<<2),
+      (1<<6) - 1,
+      (1<<6),
+      (1<<10) - 1,
+      (1<<10),
+      (1<<14) - 1,
+      (1<<14),
+      (1<<18) - 1,
+      (1<<18)
+  );
+
+  // "" means no fixed seed
+  @Param("") private SpecialRandom random;
+
+  // the following must be set during setUp
+  private Integer[] queries;
+  private Set<Integer> setToTest;
+
+  // Queries are just sequential integers. Since the contents of the set were
+  // chosen randomly, this shouldn't cause any undue bias.
+  @Override public void setUp() {
+    this.queries = new Integer[size * 2];
+    for (int i = 0; i < size * 2; i++) {
+      queries[i] = i;
+    }
+    Collections.shuffle(Arrays.asList(queries), random);
+
+    setToTest = impl.create(createData());
+  }
+
+  private Collection<Integer> createData() {
+    Set<Integer> tempSet = new HashSet<Integer>(size * 3 / 2);
+
+    // Choose 50% of the numbers between 0 and max to be in the set; thus we
+    // are measuring performance of contains() when there is a 50% hit rate
+    int max = size * 2;
+    while (tempSet.size() < size) {
+      tempSet.add(random.nextInt(max));
+    }
+    return tempSet;
+  }
+
+  public boolean timeContains(int reps) {
+    // Paranoia: acting on hearsay that accessing fields might be slow
+    // Should write a benchmark to test that!
+    Set<Integer> set = setToTest;
+    Integer[] queries = this.queries;
+
+    // Allows us to use & instead of %, acting on hearsay that division operators (/%) are
+    // disproportionately expensive; should test this too!
+    int mask = Integer.highestOneBit(size * 2) - 1;
+
+    boolean dummy = false;
+    for (int i = 0; i < reps; i++) {
+      dummy ^= set.contains(queries[i & mask]);
+    }
+    return dummy;
+  }
+
+  // TODO: remove this from all examples when IDE plugins are ready
+  public static void main(String[] args) throws Exception {
+    Runner.main(SetContainsBenchmark.class, args);
+  }
+
+
+  // Just an experiment with a slightly nicer way to create Randoms for benchies
+
+  public static class SpecialRandom extends Random {
+    public static SpecialRandom valueOf(String s) {
+      return (s.length() == 0)
+          ? new SpecialRandom()
+          : new SpecialRandom(Long.parseLong(s));
+    }
+
+    private final boolean hasSeed;
+    private final long seed;
+
+    public SpecialRandom() {
+      this.hasSeed = false;
+      this.seed = 0;
+    }
+
+    public SpecialRandom(long seed) {
+      super(seed);
+      this.hasSeed = true;
+      this.seed = seed;
+    }
+
+    @Override public String toString() {
+      return hasSeed ? "(seed:" + seed : "(default seed)";
+    }
+
+    private static final long serialVersionUID = 0;
+  }
+}
diff --git a/test/com/google/caliper/examples/StringBuilderBenchmark.java b/src/examples/StringBuilderBenchmark.java
similarity index 92%
rename from test/com/google/caliper/examples/StringBuilderBenchmark.java
rename to src/examples/StringBuilderBenchmark.java
index 2fa6819..35e34f7 100644
--- a/test/com/google/caliper/examples/StringBuilderBenchmark.java
+++ b/src/examples/StringBuilderBenchmark.java
@@ -14,23 +14,18 @@
  * limitations under the License.
  */
 
-package com.google.caliper.examples;
+package examples;
 
-import com.google.caliper.Benchmark;
 import com.google.caliper.Param;
 import com.google.caliper.Runner;
 import com.google.caliper.SimpleBenchmark;
 
-import java.util.Arrays;
-import java.util.Collection;
-
 /**
  * Tests the performance of various StringBuilder methods.
  */
 public class StringBuilderBenchmark extends SimpleBenchmark {
 
-    @Param int length;
-    static Collection<Integer> lengthValues = Arrays.asList(1, 10, 100);
+    @Param({"1", "10", "100"}) private int length;
 
     public void timeAppendBoolean(int reps) {
         for (int i = 0; i < reps; ++i) {
@@ -129,4 +124,10 @@
             }
         }
     }
+
+
+    // TODO: remove this from all examples when IDE plugins are ready
+    public static void main(String[] args) throws Exception {
+        Runner.main(StringBuilderBenchmark.class, args);
+    }
 }
diff --git a/src/scripts/caliper b/src/scripts/caliper
new file mode 100644
index 0000000..fb859a9
--- /dev/null
+++ b/src/scripts/caliper
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# rough
+
+export PATH=$PATH:$JAVA_HOME/bin
+base=`dirname $0`
+exec java -cp $base/lib/caliper-@VERSION@.jar:$CLASSPATH com.google.caliper.Runner $*
+
diff --git a/src/com/google/caliper/ExecutionException.java b/src/test/BrokenNoOpBenchmark.java
similarity index 60%
rename from src/com/google/caliper/ExecutionException.java
rename to src/test/BrokenNoOpBenchmark.java
index 7d8a592..95509fa 100644
--- a/src/com/google/caliper/ExecutionException.java
+++ b/src/test/BrokenNoOpBenchmark.java
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (C) 2009 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,15 +14,21 @@
  * limitations under the License.
  */
 
-package com.google.caliper;
+package test;
+
+import com.google.caliper.Runner;
+import com.google.caliper.SimpleBenchmark;
 
 /**
- * Thrown upon occurrence of a runtime failure during test construction or
- * execution.
+ * This fails with a runtime out of range error.
  */
-public final class ExecutionException extends RuntimeException {
+public class BrokenNoOpBenchmark extends SimpleBenchmark {
 
-  public ExecutionException(Throwable throwable) {
-    super(throwable);
+  public void timeNoOp(int reps) {
+    for (int i = 0; i < reps; i++) {}
+  }
+
+  public static void main(String[] args) throws Exception {
+    Runner.main(BrokenNoOpBenchmark.class, args);
   }
 }
diff --git a/src/test/BrokenSleepBenchmark.java b/src/test/BrokenSleepBenchmark.java
new file mode 100644
index 0000000..964cf1a
--- /dev/null
+++ b/src/test/BrokenSleepBenchmark.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2009 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 test;
+
+import com.google.caliper.Runner;
+import com.google.caliper.SimpleBenchmark;
+
+/**
+ * Should fail with a measurement error.
+ */
+public class BrokenSleepBenchmark extends SimpleBenchmark {
+  // And look, IDEA tries to warn you
+  @SuppressWarnings({"UnusedDeclaration", "UnusedParameters"})
+  public void timeSleepOneSecond(int reps) {
+    try {
+      Thread.sleep(1000);
+    } catch (InterruptedException ignored) {
+    }
+  }
+
+  public static void main(String[] args) throws Exception {
+    Runner.main(BrokenSleepBenchmark.class, args);
+  }
+}
diff --git a/src/test/ErrorsInUserCodeTest.java b/src/test/ErrorsInUserCodeTest.java
new file mode 100644
index 0000000..dbb9f88
--- /dev/null
+++ b/src/test/ErrorsInUserCodeTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2009 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 test;
+
+import com.google.caliper.Runner;
+import com.google.caliper.SimpleBenchmark;
+import com.google.caliper.UserException.AbstractBenchmarkException;
+import com.google.caliper.UserException.DoesntImplementBenchmarkException;
+import com.google.caliper.UserException.ExceptionFromUserCodeException;
+import com.google.caliper.UserException.NoParameterlessConstructorException;
+import junit.framework.TestCase;
+
+/**
+ * Unit test covering common user mistakes.
+ *
+ * @author Kevin Bourrillion
+ */
+public class ErrorsInUserCodeTest extends TestCase {
+  private Runner runner;
+
+  @Override protected void setUp() throws Exception {
+    runner = new Runner();
+  }
+
+  public void testDidntSubclassAnything() {
+    try {
+      runner.run(NotABenchmark.class.getName());
+      fail();
+    } catch (DoesntImplementBenchmarkException expected) {
+    }
+  }
+
+  static class NotABenchmark {
+    public void timeSomething(int reps) {
+      fail("" + reps);
+    }
+  }
+
+
+  public void testAbstract() {
+    try {
+      runner.run(AbstractBenchmark.class.getName());
+      fail();
+    } catch (AbstractBenchmarkException expected) {
+    }
+  }
+
+  abstract static class AbstractBenchmark extends SimpleBenchmark {
+    public void timeSomething(int reps) {
+      fail("" + reps);
+    }
+  }
+
+
+  public void testNoSuitableConstructor() {
+    try {
+      runner.run(BadConstructorBenchmark.class.getName());
+      fail();
+    } catch (NoParameterlessConstructorException expected) {
+    }
+  }
+
+  static class BadConstructorBenchmark extends SimpleBenchmark {
+    BadConstructorBenchmark(String damnParam) {
+      fail(damnParam);
+    }
+
+    public void timeSomething(int reps) {
+      fail("" + reps);
+    }
+  }
+
+
+  @SuppressWarnings("serial")
+  static class SomeUserException extends RuntimeException {}
+
+  private static void throwSomeUserException() {
+    throw new SomeUserException();
+  }
+
+
+  public void testExceptionInInit() {
+    try {
+      runner.run(ExceptionInInitBenchmark.class.getName());
+      fail();
+    } catch (ExceptionFromUserCodeException expected) {
+    }
+  }
+
+  static class ExceptionInInitBenchmark extends SimpleBenchmark {
+    static {
+      throwSomeUserException();
+    }
+
+    public void timeSomething(int reps) {
+      fail("" + reps);
+    }
+  }
+
+  public void testExceptionInConstructor() {
+    try {
+      runner.run(ExceptionInConstructorBenchmark.class.getName());
+      fail();
+    } catch (ExceptionFromUserCodeException expected) {
+    }
+  }
+
+  static class ExceptionInConstructorBenchmark extends SimpleBenchmark {
+    ExceptionInConstructorBenchmark() {
+      throw new SomeUserException();
+    }
+
+    public void timeSomething(int reps) {
+      fail("" + reps);
+    }
+  }
+
+  // TODO: enable
+  public void XXXtestExceptionInMethod() {
+    try {
+      new Runner().run(ExceptionInMethodBenchmark.class.getName());
+      fail();
+    } catch (ExceptionFromUserCodeException ignored) {
+    }
+  }
+
+  static class ExceptionInMethodBenchmark extends SimpleBenchmark {
+    public void timeSomething(int reps) {
+      throw new SomeUserException();
+    }
+  }
+}
diff --git a/src/test/RunXmlTest.java b/src/test/RunXmlTest.java
new file mode 100644
index 0000000..6dd2b63
--- /dev/null
+++ b/src/test/RunXmlTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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 test;
+
+import com.google.caliper.Run;
+import com.google.caliper.Scenario;
+import com.google.caliper.Xml;
+import com.google.common.collect.ImmutableMap;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.Date;
+import junit.framework.TestCase;
+
+public class RunXmlTest extends TestCase {
+
+  public void testXmlRoundtrip() {
+    Scenario a15dalvik = new Scenario(ImmutableMap.of(
+        "foo", "A", "bar", "15", "vm", "dalvikvm"));
+    Scenario b15dalvik = new Scenario(ImmutableMap.of(
+        "foo", "B", "bar", "15", "vm", "dalvikvm"));
+
+    Run toEncode = new Run(ImmutableMap.of(a15dalvik, 1200.1, b15dalvik, 1100.2),
+        "examples.FooBenchmark", "A0:1F:CAFE:BABE", new Date());
+    ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
+    Xml.runToXml(toEncode, bytesOut);
+
+    assertEquals("", new String(bytesOut.toByteArray()));
+
+    // we don't validate the XML directly because it's a hassle to cope with arbitrary orderings of
+    // an element's attributes
+
+    ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytesOut.toByteArray());
+    Run decoded = Xml.runFromXml(bytesIn);
+
+    assertEquals(toEncode, decoded);
+  }
+}
diff --git a/src/test/SystemOutAndErrBenchmark.java b/src/test/SystemOutAndErrBenchmark.java
new file mode 100644
index 0000000..df37d76
--- /dev/null
+++ b/src/test/SystemOutAndErrBenchmark.java
@@ -0,0 +1,37 @@
+/*
+ * 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 test;
+
+import com.google.caliper.SimpleBenchmark;
+import com.google.caliper.Runner;
+
+/**
+ * Demonstrates that the benchmark can emit output without consequence.
+ */
+public class SystemOutAndErrBenchmark extends SimpleBenchmark {
+  
+  public void timeSystemOutAndSystemErr(int reps) {
+    for (int i = 0; i < reps; i++) {
+      System.out.println("hello, out");
+      System.err.println("hello, err");
+    }
+  }
+
+  public static void main(String[] args) {
+    Runner.main(SystemOutAndErrBenchmark.class, args);
+  }
+}
diff --git a/src/test/ThreadSleepBenchmark.java b/src/test/ThreadSleepBenchmark.java
new file mode 100644
index 0000000..bfb6c05
--- /dev/null
+++ b/src/test/ThreadSleepBenchmark.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2009 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 test;
+
+import com.google.caliper.Runner;
+import com.google.caliper.SimpleBenchmark;
+
+/**
+ * If everything is working properly, this should report runtime very close to
+ * 1ms.
+ */
+public class ThreadSleepBenchmark extends SimpleBenchmark {
+
+  public void timeSleep(int reps) {
+    try {
+      Thread.sleep(reps);
+    } catch (InterruptedException ignored) {
+    }
+  }
+
+  public static void main(String[] args) throws Exception {
+    Runner.main(ThreadSleepBenchmark.class, args);
+  }
+}
diff --git a/src/test/TracingBenchmark.java b/src/test/TracingBenchmark.java
new file mode 100644
index 0000000..2f1c077
--- /dev/null
+++ b/src/test/TracingBenchmark.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 test;
+
+import com.google.caliper.Benchmark;
+import com.google.caliper.TimedRunnable;
+import com.google.caliper.Runner;
+import java.util.Set;
+import java.util.Map;
+
+/**
+ * Proof-of-concept of a decorating benchmark.
+ */
+public class TracingBenchmark implements Benchmark {
+
+  private final Benchmark delegate;
+
+  public TracingBenchmark() {
+    this.delegate = new ThreadSleepBenchmark();
+  }
+
+  public Set<String> parameterNames() {
+    return delegate.parameterNames();
+  }
+
+  public Set<String> parameterValues(String parameterName) {
+    return delegate.parameterValues(parameterName);
+  }
+
+  public TimedRunnable createBenchmark(Map<String, String> parameterValues) {
+    final TimedRunnable benchmark = delegate.createBenchmark(parameterValues);
+
+    return new TimedRunnable() {
+      public Object run(int reps) throws Exception {
+        // TODO: can we move the setup/tear down work out of the timed loop?
+        Runtime.getRuntime().traceMethodCalls(true);
+        try {
+          return benchmark.run(reps);
+        } finally {
+          Runtime.getRuntime().traceMethodCalls(false);
+        }
+      }
+    };
+  }
+
+  public static void main(String[] args) {
+    Runner.main(TracingBenchmark.class);
+  }
+}
diff --git a/src/tutorial/Tutorial.java b/src/tutorial/Tutorial.java
new file mode 100644
index 0000000..06e6e56
--- /dev/null
+++ b/src/tutorial/Tutorial.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2009 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 tutorial;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+
+/**
+ * Caliper tutorial. To run the example benchmarks in this file:
+ * {@code CLASSPATH=... [caliper_home]/caliper tutorial.Tutorial.Benchmark1}
+ *
+ * @author Kevin Bourrillion
+ */
+public class Tutorial {
+
+  /*
+   * We begin the Caliper tutorial with the simplest benchmark you can write.
+   * We'd like to know how efficient the method System.nanoTime() is.
+   *
+   * Notice:
+   *
+   *  - We write a class that extends com.google.caliper.SimpleBenchmark.
+   *  - It contains a public instance method whose name begins with 'time' and
+   *    and which accepts a single 'int reps' parameter.
+   *  - The body of the method simply executes the code we wish to measure,
+   *    'reps' times.
+   *
+   * Example run:
+   *
+   *    $ CLASSPATH=build/classes/test caliper tutorial.Tutorial.Benchmark1
+   *    [real-time results appear on this line]
+   *
+   *    Summary report for tutorial.Tutorial$Benchmark1:
+   *
+   *    Benchmark   ns
+   *    ---------  ---
+   *    NanoTime   233
+   */
+  public static class Benchmark1 extends SimpleBenchmark {
+    public void timeNanoTime(int reps) {
+      for (int i = 0; i < reps; i++) {
+        System.nanoTime();
+      }
+    }
+  }
+
+  /*
+   * Now let's compare two things: nanoTime() versus currentTimeMillis().
+   * Notice:
+   *
+   *  - We simply add another method, following the same rules as the first.
+   *
+   * Example run output:
+   *
+   *   Benchmark           ns
+   *   -----------------  ---
+   *   NanoTime           248
+   *   CurrentTimeMillis  118
+   */
+  public static class Benchmark2 extends SimpleBenchmark {
+    public void timeNanoTime(int reps) {
+      for (int i = 0; i < reps; i++) {
+        System.nanoTime();
+      }
+    }
+    public void timeCurrentTimeMillis(int reps) {
+      for (int i = 0; i < reps; i++) {
+        System.currentTimeMillis();
+      }
+    }
+  }
+
+  /*
+   * Let's try iterating over a large array. This seems simple enough, but
+   * there is a problem!
+   */
+  public static class Benchmark3 extends SimpleBenchmark {
+    private final int[] array = new int[1000000];
+
+    @SuppressWarnings("UnusedDeclaration") // IDEA tries to warn us!
+    public void timeArrayIteration_BAD(int reps) {
+      for (int i = 0; i < reps; i++) {
+        for (int ignoreMe : array) {}
+      }
+    }
+  }
+
+  /*
+   * Caliper reported that the benchmark above ran in 4 nanoseconds.
+   *
+   * Wait, what?
+   *
+   * How can it possibly iterate over a million zeroes in 4 ns!?
+   *
+   * It is very important to sanity-check benchmark results with common sense!
+   * In this case, we're indeed getting a bogus result. The problem is that the
+   * Java Virtual Machine is too smart: it detected the fact that the loop was
+   * producing no actual result, so it simply compiled it right out. The method
+   * never looped at all. To fix this, we need to use a dummy result value.
+   *
+   * Notice:
+   *
+   *  - We simply change the 'time' method from 'void' to any return type we
+   *    wish. Then we return a value that can't be known without actually
+   *    performing the work, and thus we defeat the runtime optimizations.
+   *  - We're no longer timing *just* the code we want to be testing - our
+   *    result will now be inflated by the (small) cost of addition. This is an
+   *    unfortunate fact of life with microbenchmarking. In fact, we were
+   *    already inflated by the cost of an int comparison, "i < reps" as it was.
+   *
+   * With this change, Caliper should report a much more realistic value, more
+   * on the order of an entire millisecond.
+   */
+  public static class Benchmark4 extends SimpleBenchmark {
+    private final int[] array = new int[1000000];
+
+    public int timeArrayIteration_fixed(int reps) {
+      int dummy = 0;
+      for (int i = 0; i < reps; i++) {
+        for (int doNotIgnoreMe : array) {
+          dummy += doNotIgnoreMe;
+        }
+      }
+      return dummy; // framework ignores this, but it has served its purpose!
+    }
+  }
+
+  /*
+   * Now we'd like to know how various other *sizes* of arrays perform. We
+   * don't want to have to cut and paste the whole benchmark just to provide a
+   * different size. What we need is a parameter!
+   *
+   * When you run this benchmark the same way you ran the previous ones, you'll
+   * now get an error: "No values provided for benchmark parameter 'size'".
+   * You can provide the value requested at the command line like this:
+   *
+   *   [caliper_home]/caliper tutorial.Tutorial.Benchmark5 -Dsize=100}
+   *
+   * You'll see output like this:
+   *
+   *   Benchmark       size   ns
+   *   --------------  ----  ---
+   *   ArrayIteration   100   51
+   *
+   * Now that we've parameterized our benchmark, things are starting to get fun.
+   * Try passing '-Dsize=10,100,1000' and see what happens!
+   *
+   *   Benchmark       size   ns
+   *   --------------  ----  -----------------------------------
+   *   ArrayIteration    10    7 |
+   *   ArrayIteration   100   49 ||||
+   *   ArrayIteration  1000  477 ||||||||||||||||||||||||||||||
+   *
+   */
+  public static class Benchmark5 extends SimpleBenchmark {
+    @Param int size; // set automatically by framework
+
+    private int[] array; // set by us, in setUp()
+
+    @Override protected void setUp() {
+      // @Param values are guaranteed to have been injected by now
+      array = new int[size];
+    }
+
+    public int timeArrayIteration(int reps) {
+      int dummy = 0;
+      for (int i = 0; i < reps; i++) {
+        for (int doNotIgnoreMe : array) {
+          dummy += doNotIgnoreMe;
+        }
+      }
+      return dummy;
+    }
+  }
+}
diff --git a/test/com/google/caliper/AllTests.java b/test/com/google/caliper/AllTests.java
deleted file mode 100644
index 510cc0a..0000000
--- a/test/com/google/caliper/AllTests.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2009 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.caliper;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public final class AllTests {
-  public static Test suite() {
-    TestSuite suite = new TestSuite();
-    // tests go here :)
-    return suite;
-  }
-}
diff --git a/test/com/google/caliper/examples/CharacterBenchmark.java b/test/com/google/caliper/examples/CharacterBenchmark.java
deleted file mode 100644
index 3ffeb01..0000000
--- a/test/com/google/caliper/examples/CharacterBenchmark.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2009 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.caliper.examples;
-
-import com.google.caliper.Benchmark;
-import com.google.caliper.Param;
-import com.google.caliper.Runner;
-import com.google.caliper.SimpleBenchmark;
-
-import java.util.Collection;
-import java.util.EnumSet;
-
-/**
- * Tests various Character methods, intended for testing multiple
- * implementations against each other.
- */
-public class CharacterBenchmark extends SimpleBenchmark {
-
-    @Param CharacterSet characterSet;
-    static Collection<CharacterSet> characterSetValues = EnumSet.allOf(CharacterSet.class);
-
-    char[] values;
-
-    @Override protected void setUp() throws Exception {
-        values = characterSet.chars;
-    }
-
-    enum CharacterSet {
-        ASCII(128),
-        UNICODE(65536);
-        char[] chars;
-        CharacterSet(int size) {
-            chars = new char[size];
-            for (int i = 0; i < chars.length; ++i) {
-                chars[i] = (char) i;
-            }
-        }
-    }
-
-    public void timeDigit(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.digit(ch, 10);
-            }
-        }
-    }
-
-    public void timeGetNumericValue(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.getNumericValue(ch);
-            }
-        }
-    }
-
-    public void timeIsDigit(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.isDigit(ch);
-            }
-        }
-    }
-
-    public void timeIsIdentifierIgnorable(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.isIdentifierIgnorable(ch);
-            }
-        }
-    }
-
-    public void timeIsJavaIdentifierPart(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.isJavaIdentifierPart(ch);
-            }
-        }
-    }
-
-    public void timeIsJavaIdentifierStart(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.isJavaIdentifierStart(ch);
-            }
-        }
-    }
-
-    public void timeIsLetter(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.isLetter(ch);
-            }
-        }
-    }
-
-    public void timeIsLetterOrDigit(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.isLetterOrDigit(ch);
-            }
-        }
-    }
-
-    public void timeIsLowerCase(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.isLowerCase(ch);
-            }
-        }
-    }
-
-    public void timeIsSpaceChar(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.isSpaceChar(ch);
-            }
-        }
-    }
-
-    public void timeIsUpperCase(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.isUpperCase(ch);
-            }
-        }
-    }
-
-    public void timeIsWhitespace(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.isWhitespace(ch);
-            }
-        }
-    }
-
-    public void timeIsNull(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                boolean b = (ch == ' ');
-            }
-        }
-    }
-
-    public void timeToLowerCase(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.toLowerCase(ch);
-            }
-        }
-    }
-
-    public void timeToUpperCase(int reps) {
-        for (int i = 0; i < reps; ++i) {
-            for (char ch = 0; ch < '}'; ++ch) {
-                Character.toUpperCase(ch);
-            }
-        }
-    }
-}