[jsr-275] 01/06: Imported Upstream version 1.0.0-vbeta3-0.9.1

Johan Van de Wauw johanvdw-guest at moszumanska.debian.org
Thu Aug 20 21:52:09 UTC 2015


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

johanvdw-guest pushed a commit to branch master
in repository jsr-275.

commit 2402ec7b34d0cadfef6d61fa5cb094d7824dd340
Author: Johan Van de Wauw <johan.vandewauw at gmail.com>
Date:   Thu Aug 20 22:58:41 2015 +0200

    Imported Upstream version 1.0.0-vbeta3-0.9.1
---
 pom.xml                                            |  242 +++++
 src/main/java/javax/measure/Measurable.java        |  148 +++
 src/main/java/javax/measure/Measure.java           |  598 +++++++++++
 src/main/java/javax/measure/MeasureFormat.java     |  316 ++++++
 .../java/javax/measure/converter/AddConverter.java |  117 +++
 .../measure/converter/ConversionException.java     |   57 ++
 .../java/javax/measure/converter/ExpConverter.java |  110 ++
 .../javax/measure/converter/LinearConverter.java   |  126 +++
 .../java/javax/measure/converter/LogConverter.java |  112 ++
 .../javax/measure/converter/MultiplyConverter.java |  116 +++
 .../javax/measure/converter/RationalConverter.java |  148 +++
 .../javax/measure/converter/UnitConverter.java     |  230 +++++
 .../java/javax/measure/quantity/Acceleration.java  |   46 +
 src/main/java/javax/measure/quantity/Action.java   |   50 +
 .../javax/measure/quantity/AmountOfSubstance.java  |   46 +
 src/main/java/javax/measure/quantity/Angle.java    |   47 +
 .../measure/quantity/AngularAcceleration.java      |   49 +
 .../javax/measure/quantity/AngularVelocity.java    |   49 +
 src/main/java/javax/measure/quantity/Area.java     |   47 +
 .../javax/measure/quantity/CatalyticActivity.java  |   46 +
 .../java/javax/measure/quantity/DataAmount.java    |   46 +
 src/main/java/javax/measure/quantity/DataRate.java |   47 +
 .../java/javax/measure/quantity/Dimensionless.java |   44 +
 src/main/java/javax/measure/quantity/Duration.java |   46 +
 .../javax/measure/quantity/DynamicViscosity.java   |   51 +
 .../measure/quantity/ElectricCapacitance.java      |   46 +
 .../javax/measure/quantity/ElectricCharge.java     |   46 +
 .../measure/quantity/ElectricConductance.java      |   46 +
 .../javax/measure/quantity/ElectricCurrent.java    |   47 +
 .../javax/measure/quantity/ElectricInductance.java |   46 +
 .../measure/quantity/ElectricPermittivity.java     |   50 +
 .../javax/measure/quantity/ElectricPotential.java  |   46 +
 .../javax/measure/quantity/ElectricResistance.java |   46 +
 src/main/java/javax/measure/quantity/Energy.java   |   46 +
 src/main/java/javax/measure/quantity/Force.java    |   47 +
 .../java/javax/measure/quantity/Frequency.java     |   47 +
 .../java/javax/measure/quantity/Illuminance.java   |   46 +
 .../javax/measure/quantity/IonizingRadiation.java  |   50 +
 .../javax/measure/quantity/KinematicViscosity.java |   50 +
 src/main/java/javax/measure/quantity/Length.java   |   47 +
 .../java/javax/measure/quantity/Luminance.java     |   48 +
 .../java/javax/measure/quantity/LuminousFlux.java  |   46 +
 .../javax/measure/quantity/LuminousIntensity.java  |   47 +
 .../measure/quantity/MagneticFieldStrength.java    |   47 +
 .../java/javax/measure/quantity/MagneticFlux.java  |   46 +
 .../measure/quantity/MagneticFluxDensity.java      |   46 +
 .../measure/quantity/MagneticPermeability.java     |   50 +
 .../javax/measure/quantity/MagnetomotiveForce.java |   49 +
 src/main/java/javax/measure/quantity/Mass.java     |   48 +
 .../java/javax/measure/quantity/MassFlowRate.java  |   50 +
 src/main/java/javax/measure/quantity/Power.java    |   46 +
 src/main/java/javax/measure/quantity/Pressure.java |   46 +
 src/main/java/javax/measure/quantity/Quantity.java |   50 +
 .../measure/quantity/RadiationDoseAbsorbed.java    |   46 +
 .../measure/quantity/RadiationDoseEffective.java   |   47 +
 .../measure/quantity/RadioactiveActivity.java      |   46 +
 .../java/javax/measure/quantity/SolidAngle.java    |   47 +
 .../java/javax/measure/quantity/Temperature.java   |   46 +
 src/main/java/javax/measure/quantity/Torque.java   |   53 +
 src/main/java/javax/measure/quantity/Velocity.java |   46 +
 src/main/java/javax/measure/quantity/Volume.java   |   47 +
 .../javax/measure/quantity/VolumetricDensity.java  |   49 +
 .../javax/measure/quantity/VolumetricFlowRate.java |   51 +
 .../java/javax/measure/quantity/Wavenumber.java    |   49 +
 .../javax/measure/quantity/icons/Acceleration.png  |  Bin 0 -> 2770 bytes
 .../java/javax/measure/quantity/icons/Angle.png    |  Bin 0 -> 3121 bytes
 .../java/javax/measure/quantity/icons/Area.png     |  Bin 0 -> 732 bytes
 .../java/javax/measure/quantity/icons/Clothing.png |  Bin 0 -> 2903 bytes
 .../java/javax/measure/quantity/icons/Currency.png |  Bin 0 -> 4356 bytes
 .../javax/measure/quantity/icons/DataAmount.png    |  Bin 0 -> 2817 bytes
 .../java/javax/measure/quantity/icons/DataRate.png |  Bin 0 -> 4701 bytes
 .../java/javax/measure/quantity/icons/Energy.png   |  Bin 0 -> 2457 bytes
 .../javax/measure/quantity/icons/Flow_Volume.png   |  Bin 0 -> 2420 bytes
 .../java/javax/measure/quantity/icons/Force.png    |  Bin 0 -> 2085 bytes
 .../measure/quantity/icons/FuelConsumption.png     |  Bin 0 -> 2376 bytes
 .../java/javax/measure/quantity/icons/Kitchen.png  |  Bin 0 -> 3162 bytes
 .../java/javax/measure/quantity/icons/Length.png   |  Bin 0 -> 3052 bytes
 .../javax/measure/quantity/icons/Luminance.png     |  Bin 0 -> 3255 bytes
 .../java/javax/measure/quantity/icons/Power.png    |  Bin 0 -> 3548 bytes
 .../java/javax/measure/quantity/icons/Prefixes.png |  Bin 0 -> 763 bytes
 .../java/javax/measure/quantity/icons/Pressure.png |  Bin 0 -> 3893 bytes
 .../java/javax/measure/quantity/icons/Speed.png    |  Bin 0 -> 2989 bytes
 .../javax/measure/quantity/icons/Temperature.png   |  Bin 0 -> 2651 bytes
 .../java/javax/measure/quantity/icons/Time.png     |  Bin 0 -> 4528 bytes
 .../java/javax/measure/quantity/icons/Torque.png   |  Bin 0 -> 2716 bytes
 .../java/javax/measure/quantity/icons/Volume.png   |  Bin 0 -> 3367 bytes
 .../java/javax/measure/quantity/icons/Weight.png   |  Bin 0 -> 2376 bytes
 .../java/javax/measure/quantity/icons/close.png    |  Bin 0 -> 2176 bytes
 .../java/javax/measure/quantity/icons/nav_dis.png  |  Bin 0 -> 1853 bytes
 .../java/javax/measure/quantity/icons/nav_down.png |  Bin 0 -> 2113 bytes
 .../java/javax/measure/quantity/icons/nav_up.png   |  Bin 0 -> 2300 bytes
 .../java/javax/measure/unit/AlternateUnit.java     |  133 +++
 .../java/javax/measure/unit/AnnotatedUnit.java     |  125 +++
 src/main/java/javax/measure/unit/BaseUnit.java     |  113 +++
 src/main/java/javax/measure/unit/CompoundUnit.java |  139 +++
 src/main/java/javax/measure/unit/DerivedUnit.java  |   48 +
 src/main/java/javax/measure/unit/Dimension.java    |  291 ++++++
 src/main/java/javax/measure/unit/NonSI.java        | 1070 ++++++++++++++++++++
 src/main/java/javax/measure/unit/ProductUnit.java  |  478 +++++++++
 src/main/java/javax/measure/unit/SI.java           |  744 ++++++++++++++
 .../java/javax/measure/unit/SystemOfUnits.java     |   50 +
 .../java/javax/measure/unit/TransformedUnit.java   |  127 +++
 src/main/java/javax/measure/unit/Unit.java         |  571 +++++++++++
 src/main/java/javax/measure/unit/UnitFormat.java   |  164 +++
 .../javax/measure/unit/format/LocalFormat.java     |  522 ++++++++++
 .../measure/unit/format/LocalFormat.properties     |  139 +++
 .../measure/unit/format/LocalFormat_de.properties  |   21 +
 .../unit/format/LocalFormat_en_GB.properties       |    4 +
 .../javax/measure/unit/format/ParseException.java  |  192 ++++
 .../java/javax/measure/unit/format/Prefix.java     |   81 ++
 .../measure/unit/format/SimpleCharStream.java      |  439 ++++++++
 .../java/javax/measure/unit/format/SymbolMap.java  |  222 ++++
 src/main/java/javax/measure/unit/format/Token.java |   81 ++
 .../javax/measure/unit/format/TokenMgrError.java   |  133 +++
 src/main/java/javax/measure/unit/format/UCUM.java  |  630 ++++++++++++
 .../java/javax/measure/unit/format/UCUMFormat.java |  405 ++++++++
 .../java/javax/measure/unit/format/UCUMParser.java |  496 +++++++++
 .../java/javax/measure/unit/format/UCUMParser.jj   |  189 ++++
 .../measure/unit/format/UCUMParserConstants.java   |   42 +
 .../unit/format/UCUMParserTokenManager.java        |  399 ++++++++
 .../javax/measure/unit/format/UCUM_CI.properties   |  248 +++++
 .../javax/measure/unit/format/UCUM_CS.properties   |  250 +++++
 .../measure/unit/format/UCUM_Print.properties      |  252 +++++
 .../java/javax/measure/unit/format/UnitParser.java |  759 ++++++++++++++
 .../java/javax/measure/unit/format/UnitParser.jj   |  332 ++++++
 .../measure/unit/format/UnitParserConstants.java   |   54 +
 .../unit/format/UnitParserTokenManager.java        |  449 ++++++++
 127 files changed, 15178 insertions(+)

diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..7318fb5
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,242 @@
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!-- Project Information -->
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>javax.measure</groupId>
+    <artifactId>jsr-275</artifactId>
+    <packaging>jar</packaging>
+    <version>0.9.1</version>
+    <name>JSR-275</name>
+    <url>http://jcp.org/en/jsr/detail?id=275</url>
+    <description>JSR-275 specifies Java packages for the programmatic handling
+    of physical quantities and their expression as numbers of units.
+    </description>
+    <licenses>
+        <license>
+            <name>BSD License</name>
+            <url>http://jscience.org/LICENSE.txt</url>
+        </license>
+    </licenses>
+    <organization>
+        <name>JScience</name>
+        <url>http://jscience.org</url>
+    </organization>
+    <scm>
+        <connection>scm:cvs:pserver:guest at cvs.dev.java.net:/cvs:jsr-275</connection>
+        <developerConnection>scm:cvs:pserver:${maven.username}@cvs.dev.java.net:/cvs:jsr-275</developerConnection>
+        <url>https://jsr-275.dev.java.net/source/browse/jsr-275/</url>
+    </scm>
+    <dependencies>
+        <dependency> <!-- Validation tests -->
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.1</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+	<!-- ==================================================== -->
+	<!--     Developers and contributors                      -->
+	<!-- ==================================================== -->
+	<developers>
+	    <developer>
+	      <name>Jean-Marie Dautelle</name>
+	      <id>dautelle</id>
+	      <email>jean-marie at dautelle.com</email>
+	      <organization>Thales</organization>
+	      <organizationUrl>http://www.thalesraytheon-fr.com</organizationUrl>
+	      <timezone>CET</timezone>
+	      <roles>
+	        <role>Spec Lead</role>
+	        <role>Java Developer</role>
+	        <role>Architect</role>
+	      </roles>
+	    </developer>
+	    <developer>
+	      <name>Werner Keil</name>
+	      <id>cat</id>
+	      <organization>Creative Arts & Technologies</organization>
+	      <organizationUrl>http://www.catmedia.us</organizationUrl>
+	      <email>jsr275 at catmedia.us</email>
+	      <timezone>CET</timezone>
+	      <roles>
+	        <role>Spec Lead</role>
+	        <role>Architect</role>
+	        <role>Java Developer</role>
+	      </roles>
+	    </developer>
+	    <developer>
+	    	<name>Karen Legrand</name>
+	    	<organization>Innovation Emergency Management (IEM)</organization>
+	    	<organizationUrl>http://www.iem.com</organizationUrl>
+	    	 <email>karen.legrand at iem.com</email>
+	    	 <timezone>EST</timezone>
+	    	<roles>
+	        	<role>Architect</role>
+	        	<role>Java Developer</role>
+	      </roles>
+	    </developer> 
+	    <developer>
+	      <name>Chris Senior</name>
+	      <organization>Teradyne</organization>
+	      <email>chris.senior at teradyne.com</email>
+	      <roles>
+	        <role>Java Developer</role>
+	      </roles>
+	    </developer>
+	    <developer>
+	      <name>Daniel Leuck</name>
+	      <organization>Ikayzo</organization>
+	      <email>dan at ikayzo.com</email>
+	      <timezone>HST</timezone>
+	      <roles>
+	        <role>Java Developer</role>
+	      </roles>
+	    </developer>
+	    <developer>
+	      <name>Martin Desruisseaux</name>
+	      <id>desruisseaux</id>
+	      <email>desruisseaux at users.sourceforge.net</email>
+	      <organization>Institut de Recherche pour le Developpement (IRD)</organization>
+	      <timezone>CET</timezone>
+	      <roles>
+	        <role>Java Developer</role>
+	      </roles>
+	    </developer>
+	    <developer>
+	      <name>Michael Gruebsch</name>
+	      <email>michael at mkm-rabis.de</email>
+	      <roles>
+	        <role>Java Developer</role>
+	      </roles>
+	    </developer>
+	    <developer>
+	    	<name>Eric Russell</name>
+	    	<email>eric-r at northwestern.edu</email>
+	    	<timezone>CDT</timezone>
+	    	<roles>
+	        	<role>Java Developer</role>
+	      </roles>
+	    </developer>
+	  </developers>
+	  
+	  <contributors>
+	       <contributor>
+	      <name>Brian Frank</name>
+	      <organization>Tridium</organization>
+	      <email>bfrank at tridium.com</email>
+	      <roles>
+	        <role>EG Member</role>
+	      </roles>
+	    </contributor>
+	    <contributor>
+	      <name>Bruce Hamilton</name>
+	      <organization>Agilent</organization>
+	      <email>bruce_hamilton at agilent.com</email>
+	      <roles>
+	        <role>EG Member</role>
+	      </roles>
+	    </contributor>
+	    <contributor>
+	      <name>Chris Downey</name>
+	      <email>cdowney at gmail.com</email>
+	      <roles>
+	        <role>EG Member</role>
+	      </roles>
+	    </contributor>
+	    <contributor>
+	      <name>John Murray</name>
+	      <organization>Sobetech</organization>
+	      <email>john.murray at sobetech.com</email>
+	      <roles>
+	        <role>EG Member</role>
+	      </roles>
+	    </contributor>
+	    <contributor>
+	    	<name>Gordan Vosicki</name>
+	    	<roles>
+	        	<role>EG Member</role>
+	      	</roles>
+	    </contributor>
+	    <contributor>
+	    	<name>Steve Metsker</name>
+	    	<organization>CapTech Ventures</organization>
+	    	<roles>
+	    		<role>Spec Lead (Emeritus)</role>
+	    	</roles>
+	    </contributor>
+	</contributors>
+
+    <!-- Build Settings -->
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <configuration>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.javolution</groupId>
+                <artifactId>colapi</artifactId>
+                <version>1.0.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>colorize</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.5</source>
+                    <target>1.5</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+        </plugins>
+        <extensions>
+            <extension>
+                <groupId>org.jvnet.wagon-svn</groupId>
+                <artifactId>wagon-svn</artifactId>
+                <version>1.9</version>
+            </extension>
+        </extensions>
+    </build>
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                    <docfilessubdirs>true</docfilessubdirs>
+                    <quiet>true</quiet>
+                </configuration>
+            </plugin>
+        </plugins>
+    </reporting>
+
+    <!-- Environment Settings -->
+    <pluginRepositories>
+        <pluginRepository>
+            <id>maven2-repository.dev.java.net</id>
+            <name>Java.net Repository for Maven</name>
+            <url>http://download.java.net/maven/2/</url>
+        </pluginRepository>
+    </pluginRepositories>
+    <distributionManagement>
+        <repository>
+            <uniqueVersion>false</uniqueVersion>
+            <id>java.net-maven2-repository</id>
+            <url>java-net:/maven2-repository/trunk/repository/</url>
+        </repository>
+    </distributionManagement>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+</project>
\ No newline at end of file
diff --git a/src/main/java/javax/measure/Measurable.java b/src/main/java/javax/measure/Measurable.java
new file mode 100644
index 0000000..b592a57
--- /dev/null
+++ b/src/main/java/javax/measure/Measurable.java
@@ -0,0 +1,148 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import javax.measure.quantity.Quantity;
+import javax.measure.unit.Unit;
+
+/**
+ * <p> This interface represents the measurable, countable, or comparable 
+ *     property or aspect of a thing.</p>
+ *     
+ * <p> Measurable instances are for the most part scalar quantities.[code]
+ *     class Delay implements Measurable<Duration> {
+ *          private final double seconds; // Implicit internal unit.
+ *          public Delay(double value, Unit<Duration> unit) { 
+ *              seconds = unit.getConverterTo(SI.SECOND).convert(value);
+ *          }
+ *          public double doubleValue(Unit<Duration> unit) { 
+ *              return SI.SECOND.getConverterTo(unit).convert(seconds);
+ *          }
+ *          ...
+ *     }
+ *     Thread.wait(new Delay(24, NonSI.HOUR)); // Assuming Thread.wait(Measurable<Duration>) method.
+ *     [/code]
+ *     Non-scalar quantities are nevertheless allowed as long as an aggregate
+ *     value makes sense.[code]
+ *     class Velocity3D implements Measurable<Velocity> {
+ *          private double x, y, z; // Meters per second.
+ *          public double doubleValue(Unit<Velocity> unit) { // Returns the vector norm.
+ *              double meterPerSecond = Math.sqrt(x * x + y * y + z * z);
+ *              return SI.METER_PER_SECOND.getConverterTo(unit).convert(meterPerSecond);
+ *          }
+ *          ...
+ *     }
+ *     class ComplexCurrent implements extends Measurable<ElectricCurrent> {
+ *          private Complex amperes;
+ *          public double doubleValue(Unit<ElectricCurrent> unit) { // Returns the magnitude.
+ *              return AMPERE.getConverterTo(unit).convert(amperes.magnitude());
+ *          }
+ *          ...
+ *          public Complex complexValue(Unit<ElectricCurrent> unit) { ... }
+ *     } [/code]</p>
+ *
+ *   <p> For convenience, measurable instances of any type can be created
+ *       using the {@link Measure} factory methods.[code]
+ *       Thread.wait(Measure.valueOf(24, NonSI.HOUR));[/code]</p>
+ *
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Measurable<Q extends Quantity> extends Comparable<Measurable<Q>> {
+
+    /**
+     * Returns the integral <code>int</code> value of this measurable when
+     * stated in the specified unit.
+     *
+     * <p> Note: This method differs from the <code>Number.intValue()</code>
+     *           in the sense that an ArithmeticException is raised instead
+     *           of a bit truncation in case of overflow (safety critical).</p>
+     *
+     * @param unit the unit in which the returned value is stated.
+     * @return the numeric value after conversion to type <code>int</code>.
+     * @throws ArithmeticException if this measurable cannot be represented
+     *         by a <code>int</code> number in the specified unit.
+     */
+    int intValue(Unit<Q> unit) throws ArithmeticException;
+
+    /**
+     * Returns the integral <code>long</code> value of this measurable when
+     * stated in the specified unit.
+     *
+     * <p> Note: This method differs from the <code>Number.longValue()</code>
+     *           in the sense that an ArithmeticException is raised instead
+     *           of a bit truncation in case of overflow (safety critical).</p>
+     *
+     * @param unit the unit in which the returned value is stated.
+     * @return the numeric value after conversion to type <code>long</code>.
+     * @throws ArithmeticException if this measurable cannot be represented
+     *         by a <code>int</code> number in the specified unit.
+     */
+    long longValue(Unit<Q> unit) throws ArithmeticException;
+
+    /**
+     * Returns the <code>float</code> value of this measurable
+     * when stated in the specified unit. If the measurable has too great of
+     * a magnitude to be represented as a <code>float</code>,
+     * <code>FLOAT.NEGATIVE_INFINITY</code> or
+     * <code>FLOAT.POSITIVE_INFINITY</code> is returned as appropriate.
+     *
+     * @param unit the unit in which this returned value is stated.
+     * @return the numeric value after conversion to type <code>float</code>.
+     */
+    float floatValue(Unit<Q> unit);
+
+    /**
+     * Returns the <code>double</code> value of this measurable
+     * when stated in the specified unit. If the measurable has too great of
+     * a magnitude to be represented as a <code>double</code>,
+     * <code>Double.NEGATIVE_INFINITY</code> or
+     * <code>Double.POSITIVE_INFINITY</code> is returned as appropriate.
+     * 
+     * @param unit the unit in which this returned value is stated.
+     * @return the numeric value after conversion to type <code>double</code>.
+     */
+    double doubleValue(Unit<Q> unit);
+
+    /**
+     * Returns the <code>BigDecimal</code> value of this measurable when
+     * stated in the specified unit.
+     * 
+     * @param unit the unit in which the returned value is stated.
+     * @param ctx the math context being used for conversion.
+     * @return the decimal value after conversion.
+     * @throws ArithmeticException if the result is inexact but the
+     *         rounding mode is <code>UNNECESSARY</code> or 
+     *         <code>mathContext.precision == 0</code> and the quotient has a 
+     *         non-terminating decimal expansion.
+     */
+    BigDecimal decimalValue(Unit<Q> unit, MathContext ctx) throws ArithmeticException;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/Measure.java b/src/main/java/javax/measure/Measure.java
new file mode 100644
index 0000000..1165058
--- /dev/null
+++ b/src/main/java/javax/measure/Measure.java
@@ -0,0 +1,598 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.MathContext;
+
+import java.text.ParsePosition;
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Quantity;
+import javax.measure.unit.Unit;
+
+/**
+ * <p> This class represents the immutable result of a scalar measurement stated
+ *     in a known unit.</p>
+ * 
+ * <p> To avoid any lost of precision, known exact measure (e.g. physical 
+ *     constants) should not be created from <code>double</code> constants but
+ *     from their decimal representation.[code]
+ *         public static final Measure<Velocity> C = Measure.valueOf("299792458 m/s", Velocity.class); // Speed of Light (exact).
+ *    [/code]</p>
+ * 
+ * <p> Measures can be converted to different units, the conversion precision is
+ *     determined by the specified {@link MathContext}.[code]
+ *         Measure<Velocity> milesPerHour = C.to(MILES_PER_HOUR, MathContext.DECIMAL128); // Use BigDecimal implementation.
+ *         System.out.println(milesPerHour);
+ * 
+ *         > 670616629.3843951324266284896206156 [mi_i]/h
+ *     [/code]
+ *     If no precision is specified <code>double</code> precision is assumed.[code]
+ *         Measure<Velocity> milesPerHour = C.to(MILES_PER_HOUR); // Use double implementation (fast).
+ *         System.out.println(milesPerHour);
+ * 
+ *         > 670616629.3843951 [mi_i]/h
+ *     [/code]</p>
+ * 
+ * <p> Applications may sub-class {@link Measure} for particular measurements
+ *     types.[code]
+ *         // Measurement of type Mass based on <code>double</code> primitive types.
+ *         public class Weight extends Measure<Mass> { 
+ *             private final double _kilograms; // Internal SI representation. 
+ *             private Weight(double kilograms) { _kilograms = kilograms; }
+ *             public static Weight valueOf(double value, Unit<Mass> unit) {
+ *                 return new Weight(unit.getConverterTo(SI.KILOGRAM).convert(value));
+ *             } 
+ *             public Unit<Mass> getUnit() { return SI.KILOGRAM; } 
+ *             public Double getValue() { return _kilograms; } 
+ *             ...
+ *         }
+ * 
+ *         // Complex numbers measurements.
+ *         public class ComplexMeasure<Q extends Quantity> extends Measure<Q> {
+ *             public Complex getValue() { ... } // Assuming Complex is a Number.
+ *             ... 
+ *         }
+ * 
+ *         // Specializations of complex numbers measurements.
+ *         public class Current extends ComplexMeasure<ElectricCurrent> {...} 
+ *         public class Tension extends ComplexMeasure<ElectricPotential> {...}
+ *         [/code]</p>
+ * 
+ * <p> All instances of this class shall be immutable.</p>
+ * 
+ * @author <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public abstract class Measure<Q extends Quantity> implements Measurable<Q>,
+		Serializable {
+
+	/**
+	 * Default constructor.
+	 */
+	protected Measure() {
+	}
+
+	/**
+	 * Returns the measurement numeric value.
+	 * 
+	 * @return the measurement value.
+	 */
+	public abstract Number getValue();
+
+	/**
+	 * Returns the measurement unit.
+	 * 
+	 * @return the measurement unit.
+	 */
+	public abstract Unit<Q> getUnit();
+
+	/**
+	 * Convenient method equivalent to {@link #to(javax.measure.unit.Unit)
+	 * to(this.getUnit().toSI())}.
+	 * 
+	 * @return this measure or a new measure equivalent to this measure but
+	 *         stated in SI units.
+	 * @throws ArithmeticException if the result is inexact and the quotient 
+	 *         has a non-terminating decimal expansion.
+	 */
+	public Measure<Q> toSI() {
+		return to(this.getUnit().toSI());
+	}
+
+	/**
+	 * Returns this measure after conversion to specified unit. The default
+	 * implementation returns
+	 * <code>Measure.valueOf(doubleValue(unit), unit)</code>. If this measure is
+	 * already stated in the specified unit, then this measure is returned and
+	 * no conversion is performed.
+	 * 
+	 * @param unit the unit in which the returned measure is stated.
+	 * @return this measure or a new measure equivalent to this measure but
+	 *         stated in the specified unit.
+	 * @throws ArithmeticException if the result is inexact and the quotient has
+	 *         a
+	 *             non-terminating decimal expansion.
+	 */
+	public Measure<Q> to(Unit<Q> unit) {
+		if (unit.equals(this.getUnit()))
+			return this;
+		return Measure.valueOf(doubleValue(unit), unit);
+	}
+
+	/**
+	 * Returns this measure after conversion to specified unit. The default
+	 * implementation returns
+	 * <code>Measure.valueOf(decimalValue(unit, ctx), unit)</code>. If this
+	 * measure is already stated in the specified unit, then this measure is
+	 * returned and no conversion is performed.
+	 * 
+	 * @param unit
+	 *            the unit in which the returned measure is stated.
+	 * @param ctx
+	 *            the math context to use for conversion.
+	 * @return this measure or a new measure equivalent to this measure but
+	 *         stated in the specified unit.
+	 * @throws ArithmeticException
+	 *             if the result is inexact but the rounding mode is
+	 *             <code>UNNECESSARY</code> or
+	 *             <code>mathContext.precision == 0</code> and the quotient has
+	 *             a non-terminating decimal expansion.
+	 */
+	public Measure<Q> to(Unit<Q> unit, MathContext ctx) {
+		if (unit.equals(this.getUnit()))
+			return this;
+		return Measure.valueOf(decimalValue(unit, ctx), unit);
+	}
+
+	/**
+	 * Compares this measure and the specified measurable to the given accuracy.
+	 * Measurements are considered approximately equals if their absolute
+	 * differences when stated in the same unit is less than the specified
+	 * accuracy.
+	 * 
+	 * @param that
+	 *            the measurable to compare with.
+	 * @param accuracy
+	 *            the absolute error allowed.
+	 * @return
+	 *         <code>abs(this.doubleValue(getUnit())- that.doubleValue(getUnit())) <= accuracy</code>
+	 */
+	public boolean approximates(Measurable<Q> that, double accuracy) {
+		Unit<Q> unit = this.getUnit();
+		return Math.abs(this.doubleValue(unit) - that.doubleValue(unit)) <= accuracy;
+	}
+
+	/**
+	 * Compares this measure to the specified measurable quantity. The default
+	 * implementation compares the {@link Measurable#doubleValue(Unit)} of both
+	 * this measure and the specified measurable stated in the same unit (this
+	 * measure's {@link #getUnit() unit}).
+	 * 
+	 * @return a negative integer, zero, or a positive integer as this measure
+	 *         is less than, equal to, or greater than the specified measurable
+	 *         quantity.
+	 * @return <code>Double.compare(this.doubleValue(getUnit()),
+	 *         that.doubleValue(getUnit()))</code>
+	 */
+	public int compareTo(Measurable<Q> that) {
+		Unit<Q> unit = getUnit();
+		return Double.compare(doubleValue(unit), that.doubleValue(unit));
+	}
+
+	/**
+	 * Compares this measure against the specified object for <b>strict</b>
+	 * equality (same unit and same amount).
+	 * 
+	 * <p> Similarly to the {@link BigDecimal#equals} method which consider 2.0
+	 *     and 2.00 as different objects because of different internal scales, 
+	 *     measurements such as <code>Measure.valueOf(3.0, KILOGRAM)</code>
+	 *     <code>Measure.valueOf(3, KILOGRAM)</code> and
+	 *     <code>Measure.valueOf("3 kg")</code> might not be considered equals
+	 *     because of possible differences in their implementations.</p>
+	 * 
+	 * <p> To compare measures stated using different units or using different
+	 *     amount implementations the {@link #compareTo} or 
+	 *     {@link #approximates} methods should be used.</p>
+	 * 
+	 * @param obj the object to compare with.
+	 * @return <code>this.getUnit.equals(obj.getUnit()) 
+	 *         && this.getValue().equals(obj.getValue())</code>
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if (!(obj instanceof Measure))
+			return false;
+		Measure<?> that = (Measure<?>) obj;
+		return this.getUnit().equals(that.getUnit())
+				&& this.getValue().equals(that.getValue());
+	}
+
+	/**
+	 * Returns the hash code for this measure.
+	 * 
+	 * @return the hash code value.
+	 */
+	@Override
+	public int hashCode() {
+		return getUnit().hashCode() + getValue().hashCode();
+	}
+
+	/**
+	 * Returns the <code>String</code> representation of this measure. The
+	 * string produced for a given measure is always the same; it is not
+	 * affected by locale. This means that it can be used as a canonical string
+	 * representation for exchanging measure, or as a key for a Hashtable, etc.
+	 * Locale-sensitive measure formatting and parsing is handled by the
+	 * {@link MeasureFormat} class and its subclasses.
+	 * 
+	 * @return <code>UnitFormat.getInternational().format(this)</code>
+	 */
+	@Override
+	public final String toString() {
+		return MeasureFormat.getStandard().format(this);
+	}
+
+	// Implements Measurable
+	public final int intValue(Unit<Q> unit) throws ArithmeticException {
+		long longValue = longValue(unit);
+		if ((longValue < Integer.MIN_VALUE) || (longValue > Integer.MAX_VALUE))
+			throw new ArithmeticException("Cannot convert " + longValue
+					+ " to int (overflow)");
+		return (int) longValue;
+	}
+
+	// Implements Measurable
+	public long longValue(Unit<Q> unit) throws ArithmeticException {
+		double result = doubleValue(unit);
+		if ((result < Long.MIN_VALUE) || (result > Long.MAX_VALUE))
+			throw new ArithmeticException("Overflow (" + result + ")");
+		return (long) result;
+	}
+
+	// Implements Measurable
+	public final float floatValue(Unit<Q> unit) {
+		return (float) doubleValue(unit);
+	}
+
+	/**
+	 * Casts this measure to a parameterized unit of specified nature or throw a
+	 * <code>ClassCastException</code> if the dimension of the specified
+	 * quantity and this measure unit's dimension do not match. For
+	 * example:[code] 
+	 *     Measure<Length> length = Measure.valueOf("2 km").asType(Length.class);
+	 * [/code]
+	 * 
+	 * @param type the quantity class identifying the nature of the measure.
+	 * @return this measure parameterized with the specified type.
+	 * @throws ClassCastException if the dimension of this unit is different 
+	 *         from the specified quantity dimension.
+	 * @throws UnsupportedOperationException
+	 *             if the specified quantity class does not have a public static
+	 *             field named "UNIT" holding the SI unit for the quantity.
+	 * @see Unit#asType(Class)
+	 */
+	@SuppressWarnings("unchecked")
+	public final <T extends Quantity> Measure<T> asType(Class<T> type)
+			throws ClassCastException {
+		this.getUnit().asType(type); // Raises ClassCastException is dimension
+										// mismatches.
+		return (Measure<T>) this;
+	}
+
+	/**
+	 * Returns the
+	 * {@link #valueOf(java.math.BigDecimal, javax.measure.unit.Unit) decimal}
+	 * measure of unknown type corresponding to the specified representation.
+	 * This method can be used to parse dimensionless quantities.[code]
+	 *     Measure<Dimensionless> proportion = Measure.valueOf("0.234").asType(Dimensionless.class);
+	 * [/code]
+	 * 
+	 * <p> Note: This method handles only
+	 * {@link javax.measure.unit.UnitFormat#getStandard standard} unit format
+	 * (<a href="http://unitsofmeasure.org/">UCUM</a> based). Locale-sensitive
+	 * measure formatting and parsing are handled by the {@link MeasureFormat}
+	 * class and its subclasses.</p>
+	 * 
+	 * @param csq the decimal value and its unit (if any) separated by space(s).
+	 * @return <code>MeasureFormat.getInternational().parse(csq, new ParsePosition(0))</code>
+	 */
+	public static Measure<?> valueOf(CharSequence csq) {
+		return MeasureFormat.getStandard().parse(csq, new ParsePosition(0));
+	}
+
+	/**
+	 * Returns the scalar measure for the specified <code>int</code> stated in
+	 * the specified unit.
+	 * 
+	 * @param intValue the measurement value.
+	 * @param unit the measurement unit.
+	 * @return the corresponding <code>int</code> measure.
+	 */
+	public static <Q extends Quantity> Measure<Q> valueOf(int intValue,
+			Unit<Q> unit) {
+		return new IntegerMeasure<Q>(intValue, unit);
+	}
+
+	private static class IntegerMeasure<T extends Quantity> extends Measure<T> {
+
+		int _value;
+
+		Unit<T> _unit;
+
+		public IntegerMeasure(int value, Unit<T> unit) {
+			_value = value;
+			_unit = unit;
+		}
+
+		@Override
+		public Integer getValue() {
+			return _value;
+		}
+
+		@Override
+		public Unit<T> getUnit() {
+			return _unit;
+		}
+
+		// Implements Measurable
+		public double doubleValue(Unit<T> unit) {
+			return (_unit.equals(unit)) ? _value : _unit.getConverterTo(unit)
+					.convert(_value);
+		}
+
+		// Implements Measurable
+		public BigDecimal decimalValue(Unit<T> unit, MathContext ctx)
+				throws ArithmeticException {
+			BigDecimal decimal = BigDecimal.valueOf(_value);
+			return (_unit.equals(unit)) ? decimal : _unit.getConverterTo(unit)
+					.convert(decimal, ctx);
+		}
+
+		private static final long serialVersionUID = 1L;
+
+	}
+
+	/**
+	 * Returns the scalar measure for the specified <code>long</code> stated in
+	 * the specified unit.
+	 * 
+	 * @param longValue the measurement value.
+	 * @param unit the measurement unit.
+	 * @return the corresponding <code>long</code> measure.
+	 */
+	public static <Q extends Quantity> Measure<Q> valueOf(long longValue,
+			Unit<Q> unit) {
+		return new LongMeasure<Q>(longValue, unit);
+	}
+
+	private static class LongMeasure<T extends Quantity> extends Measure<T> {
+
+		long _value;
+
+		Unit<T> _unit;
+
+		public LongMeasure(long value, Unit<T> unit) {
+			_value = value;
+			_unit = unit;
+		}
+
+		@Override
+		public Long getValue() {
+			return _value;
+		}
+
+		@Override
+		public Unit<T> getUnit() {
+			return _unit;
+		}
+
+		@Override
+		// Avoid loss of precision if no conversion.
+		public long longValue(Unit<T> unit) {
+			return ((_unit.equals(unit)) || (_unit.getConverterTo(unit) == UnitConverter.IDENTITY)) ? _value
+					: super.longValue(unit);
+		}
+
+		// Implements Measurable
+		public double doubleValue(Unit<T> unit) {
+			return (_unit.equals(unit)) ? _value : _unit.getConverterTo(unit)
+					.convert(_value);
+		}
+
+		// Implements Measurable
+		public BigDecimal decimalValue(Unit<T> unit, MathContext ctx)
+				throws ArithmeticException {
+			BigDecimal decimal = BigDecimal.valueOf(_value);
+			return (_unit.equals(unit)) ? decimal : _unit.getConverterTo(unit)
+					.convert(decimal, ctx);
+		}
+
+		private static final long serialVersionUID = 1L;
+
+	}
+
+	/**
+	 * Returns the scalar measure for the specified <code>float</code> stated in
+	 * the specified unit.
+	 * 
+	 * @param floatValue the measurement value.
+	 * @param unit the measurement unit.
+	 * @return the corresponding <code>float</code> measure.
+	 */
+	public static <Q extends Quantity> Measure<Q> valueOf(float floatValue,
+			Unit<Q> unit) {
+		return new FloatMeasure<Q>(floatValue, unit);
+	}
+
+	private static class FloatMeasure<T extends Quantity> extends Measure<T> {
+
+		float _value;
+
+		Unit<T> _unit;
+
+		public FloatMeasure(float value, Unit<T> unit) {
+			_value = value;
+			_unit = unit;
+		}
+
+		@Override
+		public Float getValue() {
+			return _value;
+		}
+
+		@Override
+		public Unit<T> getUnit() {
+			return _unit;
+		}
+
+		// Implements Measurable
+		public double doubleValue(Unit<T> unit) {
+			return (_unit.equals(unit)) ? _value : _unit.getConverterTo(unit)
+					.convert(_value);
+		}
+
+		// Implements Measurable
+		public BigDecimal decimalValue(Unit<T> unit, MathContext ctx)
+				throws ArithmeticException {
+			BigDecimal decimal = BigDecimal.valueOf(_value);
+			return (_unit.equals(unit)) ? decimal : _unit.getConverterTo(unit)
+					.convert(decimal, ctx);
+		}
+
+		private static final long serialVersionUID = 1L;
+
+	}
+
+	/**
+	 * Returns the scalar measure for the specified <code>double</code> stated
+	 * in the specified unit.
+	 * 
+	 * @param doubleValue the measurement value.
+	 * @param unit the measurement unit.
+	 * @return the corresponding <code>double</code> measure.
+	 */
+	public static <Q extends Quantity> Measure<Q> valueOf(double doubleValue,
+			Unit<Q> unit) {
+		return new DoubleMeasure<Q>(doubleValue, unit);
+	}
+
+	private static class DoubleMeasure<T extends Quantity> extends Measure<T> {
+
+		double _value;
+
+		Unit<T> _unit;
+
+		public DoubleMeasure(double value, Unit<T> unit) {
+			_value = value;
+			_unit = unit;
+		}
+
+		@Override
+		public Double getValue() {
+			return _value;
+		}
+
+		@Override
+		public Unit<T> getUnit() {
+			return _unit;
+		}
+
+		// Implements Measurable
+		public double doubleValue(Unit<T> unit) {
+			return (_unit.equals(unit)) ? _value : _unit.getConverterTo(unit)
+					.convert(_value);
+		}
+
+		// Implements Measurable
+		public BigDecimal decimalValue(Unit<T> unit, MathContext ctx)
+				throws ArithmeticException {
+			BigDecimal decimal = BigDecimal.valueOf(_value);
+			return (_unit.equals(unit)) ? decimal : _unit.getConverterTo(unit)
+					.convert(decimal, ctx);
+		}
+
+		private static final long serialVersionUID = 1L;
+
+	}
+
+	/**
+	 * Returns the scalar measure for the specified <code>BigDecimal</code>
+	 * stated in the specified unit.
+	 * 
+	 * @param decimalValue the measurement value.
+	 * @param unit the measurement unit.
+	 * @return the corresponding <code>BigDecimal</code> measure.
+	 */
+	public static <Q extends Quantity> Measure<Q> valueOf(
+			BigDecimal decimalValue, Unit<Q> unit) {
+		return new DecimalMeasure<Q>(decimalValue, unit);
+	}
+
+	private static class DecimalMeasure<T extends Quantity> extends Measure<T> {
+
+		BigDecimal _value;
+
+		Unit<T> _unit;
+
+		public DecimalMeasure(BigDecimal value, Unit<T> unit) {
+			_value = value;
+			_unit = unit;
+		}
+
+		@Override
+		public BigDecimal getValue() {
+			return _value;
+		}
+
+		@Override
+		public Unit<T> getUnit() {
+			return _unit;
+		}
+
+		// Implements Measurable
+		public double doubleValue(Unit<T> unit) {
+			return (_unit.equals(unit)) ? _value.doubleValue() : _unit
+					.getConverterTo(unit).convert(_value.doubleValue());
+		}
+
+		// Implements Measurable
+		public BigDecimal decimalValue(Unit<T> unit, MathContext ctx)
+				throws ArithmeticException {
+			return (_unit.equals(unit)) ? _value : _unit.getConverterTo(unit)
+					.convert(_value, ctx);
+		}
+
+		private static final long serialVersionUID = 1L;
+
+	}
+
+	private static final long serialVersionUID = 1L;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/MeasureFormat.java b/src/main/java/javax/measure/MeasureFormat.java
new file mode 100644
index 0000000..c3c4233
--- /dev/null
+++ b/src/main/java/javax/measure/MeasureFormat.java
@@ -0,0 +1,316 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure;
+
+import java.math.BigDecimal;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.io.IOException;
+
+import java.math.MathContext;
+import javax.measure.unit.CompoundUnit;
+import javax.measure.unit.Unit;
+import javax.measure.unit.UnitFormat;
+
+/**
+ * <p> This class provides the interface for formatting and parsing {@link Measure
+ *     measurements}.</p>
+ * 
+ * <p> Instances of this class should be able to format measurements stated in
+ *     {@link CompoundUnit}. See {@link #formatCompound formatCompound(...)}.
+ * </p>
+ * 
+ * @author <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public abstract class MeasureFormat extends Format {
+
+	/**
+	 * Holds the default format instance.
+	 */
+	private static final NumberSpaceUnit DEFAULT = new NumberSpaceUnit(
+			NumberFormat.getInstance(), UnitFormat.getInstance());
+
+	/**
+	 * Holds the standard format instance.
+	 */
+	private static final Standard STANDARD = new Standard();
+
+	/**
+	 * Returns the measure format for the default locale. The default format
+	 * assumes the measure is composed of a decimal number and a {@link Unit}
+	 * separated by whitespace(s).
+	 * 
+	 * @return <code>MeasureFormat.getInstance(NumberFormat.getInstance(), UnitFormat.getInstance())</code>
+	 */
+	public static MeasureFormat getInstance() {
+		return DEFAULT;
+	}
+
+	/**
+	 * Returns the measure format using the specified number format and unit
+	 * format (the number and unit are separated by one space).
+	 * 
+	 * @param numberFormat the number format.
+	 * @param unitFormat the unit format.
+	 * @return the corresponding format.
+	 */
+	public static MeasureFormat getInstance(NumberFormat numberFormat,
+			UnitFormat unitFormat) {
+		return new NumberSpaceUnit(numberFormat, unitFormat);
+	}
+
+	/**
+	 * Returns the culture invariant format based upon {@link BigDecimal}
+	 * canonical format and the {@link UnitFormat#getStandard() standard} unit
+	 * format. This format <b>is not</b> locale-sensitive and can be used for
+	 * unambiguous electronic communication of quantities together with their
+	 * units without loss of information. For example:
+	 * <code>"1.23456789 kg.m/s2"</code> returns
+	 * <code>Measure.valueOf(new BigDecimal("1.23456789"), Unit.valueOf("kg.m/s2")));</code>
+	 * 
+	 * @return the standard measure format.
+	 */
+	public static MeasureFormat getStandard() {
+		return STANDARD;
+	}
+
+	/**
+	 * Formats the specified measure into an <code>Appendable</code>.
+	 * 
+	 * @param measure the measure to format.
+	 * @param dest the appendable destination.
+	 * @return the specified <code>Appendable</code>.
+	 * @throws IOException if an I/O exception occurs.
+	 */
+	public abstract Appendable format(Measure<?> measure, Appendable dest)
+			throws IOException;
+
+	/**
+	 * Parses a portion of the specified <code>CharSequence</code> from the
+	 * specified position to produce an object. If parsing succeeds, then the
+	 * index of the <code>cursor</code> argument is updated to the index after
+	 * the last character used.
+	 * 
+	 * @param csq the <code>CharSequence</code> to parse.
+	 * @param cursor the cursor holding the current parsing index.
+	 * @return the object parsed from the specified character sub-sequence.
+	 * @throws IllegalArgumentException
+	 *             if any problem occurs while parsing the specified character
+	 *             sequence (e.g. illegal syntax).
+	 */
+	public abstract Measure<?> parse(CharSequence csq, ParsePosition cursor)
+			throws IllegalArgumentException;
+
+	/**
+	 * Formats the specified value using {@link CompoundUnit} compound units}.
+	 * The default implementation is locale sensitive and does not use space to
+	 * separate units. For example:[code]
+	 *     Unit<Length> FOOT_INCH = FOOT.compound(INCH);
+	 *     Measure<Length> height = Measure.valueOf(1.81, METER);
+	 *     System.out.println(height.to(FOOT_INCH));
+	 * 
+	 *     > 5ft11,26in // French Local
+	 * 
+	 *     Unit<Angle> DMS = DEGREE_ANGLE.compound(MINUTE_ANGLE).compound(SECOND_ANGLE);
+	 *     Measure<Angle> rotation = Measure.valueOf(35.857497, DEGREE_ANGLE);
+	 *     System.out.println(rotation.to(DMS));
+	 * 
+	 *     > 35°51'26,989" // French Local 
+	 * [/code]
+	 * 
+	 * @param value the value to format using compound units.
+	 * @param unit the compound unit.
+	 * @param dest the appendable destination.
+	 * @return the specified <code>Appendable</code>.
+	 * @throws IOException if an I/O exception occurs.
+	 */
+	@SuppressWarnings("unchecked")
+	protected Appendable formatCompound(double value, CompoundUnit<?> unit,
+			Appendable dest) throws IOException {
+		Unit high = unit.getHigh();
+		Unit low = unit.getLow(); // The unit in which the value is stated.
+		long highValue = (long) low.getConverterTo(high).convert(value);
+		double lowValue = value - high.getConverterTo(low).convert(highValue);
+		if (high instanceof CompoundUnit)
+			formatCompound(highValue, (CompoundUnit) high, dest);
+		else {
+			dest.append(DEFAULT._numberFormat.format(highValue));
+			DEFAULT._unitFormat.format(high, dest);
+		}
+		dest.append(DEFAULT._numberFormat.format(lowValue));
+		return DEFAULT._unitFormat.format(low, dest);
+	}
+
+	@Override
+	public final StringBuffer format(Object obj, final StringBuffer toAppendTo,
+			FieldPosition pos) {
+		if (!(obj instanceof Measure))
+			throw new IllegalArgumentException(
+					"obj: Not an instance of Measure");
+		if ((toAppendTo == null) || (pos == null))
+			throw new NullPointerException();
+		try {
+			return (StringBuffer) format((Measure<?>) obj,
+					(Appendable) toAppendTo);
+		} catch (IOException ex) {
+			throw new Error(ex); // Cannot happen.
+		}
+	}
+
+	@Override
+	public final Measure<?> parseObject(String source, ParsePosition pos) {
+		try {
+			return parse(source, pos);
+		} catch (IllegalArgumentException e) {
+			return null; // Unfortunately the message why the parsing failed
+		} // is lost; but we have to follow the Format spec.
+
+	}
+
+	/**
+	 * Convenience method equivalent to {@link #format(Measure, Appendable)}
+	 * except it does not raise an IOException.
+	 * 
+	 * @param measure the measure to format.
+	 * @param dest the appendable destination.
+	 * @return the specified <code>StringBuilder</code>.
+	 */
+	public final StringBuilder format(Measure<?> measure, StringBuilder dest) {
+		try {
+			return (StringBuilder) this.format(measure, (Appendable) dest);
+		} catch (IOException ex) {
+			throw new RuntimeException(ex); // Should not happen.
+		}
+	}
+
+	// Holds default implementation.
+	private static final class NumberSpaceUnit extends MeasureFormat {
+
+		private final NumberFormat _numberFormat;
+
+		private final UnitFormat _unitFormat;
+
+		private NumberSpaceUnit(NumberFormat numberFormat, UnitFormat unitFormat) {
+			_numberFormat = numberFormat;
+			_unitFormat = unitFormat;
+		}
+
+		@SuppressWarnings("unchecked")
+		@Override
+		public Appendable format(Measure<?> measure, Appendable dest)
+				throws IOException {
+			Unit unit = measure.getUnit();
+			if (unit instanceof CompoundUnit)
+				return formatCompound(measure.doubleValue(unit),
+						(CompoundUnit) unit, dest);
+			else {
+				dest.append(_numberFormat.format(measure.getValue()));
+				if (measure.getUnit().equals(Unit.ONE))
+					return dest;
+				dest.append(' ');
+				return _unitFormat.format(measure.getUnit(), dest);
+			}
+		}
+
+		@SuppressWarnings("unchecked")
+		@Override
+		public Measure<?> parse(CharSequence csq, ParsePosition cursor)
+				throws IllegalArgumentException {
+			String str = csq.toString();
+			Number number = _numberFormat.parse(str, cursor);
+			if (number == null)
+				throw new IllegalArgumentException("Number cannot be parsed");
+			Unit unit = _unitFormat.parse(csq, cursor);
+			if (number instanceof BigDecimal)
+				return Measure.valueOf((BigDecimal) number, unit);
+			else if (number instanceof Long)
+				return Measure.valueOf(((Long) number).longValue(), unit);
+			else if (number instanceof Double)
+				return Measure.valueOf(((Double) number).doubleValue(), unit);
+			else
+				throw new UnsupportedOperationException("Number of type "
+						+ number.getClass() + " are not supported");
+		}
+
+		private static final long serialVersionUID = 1L;
+
+	}
+
+	// Holds standard implementation.
+	private static final class Standard extends MeasureFormat {
+
+		@SuppressWarnings("unchecked")
+		@Override
+		public Appendable format(Measure measure, Appendable dest)
+				throws IOException {
+			Unit unit = measure.getUnit();
+			if (unit instanceof CompoundUnit)
+				return formatCompound(measure.doubleValue(unit),
+						(CompoundUnit) unit, dest);
+			else {
+				BigDecimal decimal = measure.decimalValue(unit,
+						MathContext.UNLIMITED);
+				dest.append(decimal.toString());
+				if (measure.getUnit().equals(Unit.ONE))
+					return dest;
+				dest.append(' ');
+				return UnitFormat.getStandard().format(unit, dest);
+			}
+		}
+
+		@SuppressWarnings("unchecked")
+		@Override
+		public Measure<?> parse(CharSequence csq, ParsePosition cursor)
+				throws IllegalArgumentException {
+			int startDecimal = cursor.getIndex();
+			while ((startDecimal < csq.length())
+					&& Character.isWhitespace(csq.charAt(startDecimal))) {
+				startDecimal++;
+			}
+			int endDecimal = startDecimal + 1;
+			while ((endDecimal < csq.length())
+					&& !Character.isWhitespace(csq.charAt(endDecimal))) {
+				endDecimal++;
+			}
+			BigDecimal decimal = new BigDecimal(csq.subSequence(startDecimal,
+					endDecimal).toString());
+			cursor.setIndex(endDecimal + 1);
+			Unit unit = UnitFormat.getStandard().parse(csq, cursor);
+			return Measure.valueOf(decimal, unit);
+		}
+
+		private static final long serialVersionUID = 1L;
+
+	}
+
+	private static final long serialVersionUID = 1L;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/converter/AddConverter.java b/src/main/java/javax/measure/converter/AddConverter.java
new file mode 100644
index 0000000..7cf97b8
--- /dev/null
+++ b/src/main/java/javax/measure/converter/AddConverter.java
@@ -0,0 +1,117 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.converter;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+
+/**
+ * <p> This class represents a converter adding a constant offset 
+ *     to numeric values (<code>double</code> based).</p>
+ *
+ * <p> Instances of this class are immutable.</p>
+ *
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public final class AddConverter extends UnitConverter {
+
+    /**
+     * Holds the offset.
+     */
+    private final double _offset;
+
+    /**
+     * Creates an add converter with the specified offset.
+     *
+     * @param  offset the offset value.
+     * @throws IllegalArgumentException if offset is <code>0.0</code>
+     *         (would result in identity converter).
+     */
+    public AddConverter(double offset) {
+        if (offset == 0.0) {
+            throw new IllegalArgumentException("Would result in identity converter");
+        }
+        _offset = offset;
+    }
+
+    /**
+     * Returns the offset value for this add converter.
+     *
+     * @return the offset value.
+     */
+    public double getOffset() {
+        return _offset;
+    }
+
+    @Override
+    public UnitConverter concatenate(UnitConverter converter) {
+        if (converter instanceof AddConverter) {
+            double offset = _offset + ((AddConverter) converter)._offset;
+            return offset == 0.0 ? IDENTITY : new AddConverter(offset);
+        } else {
+            return super.concatenate(converter);
+        }
+    }
+
+    @Override
+    public AddConverter inverse() {
+        return new AddConverter(-_offset);
+    }
+
+    @Override
+    public double convert(double value) {
+        return value + _offset;
+    }
+
+    @Override
+    public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException {
+        return value.add(BigDecimal.valueOf(_offset), ctx);
+    }
+
+    @Override
+    public final String toString() {
+        return "AddConverter(" + _offset + ")";
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof AddConverter)) {
+            return false;
+        }
+        AddConverter that = (AddConverter) obj;
+        return this._offset == that._offset;
+    }
+
+    @Override
+    public int hashCode() {
+        long bits = Double.doubleToLongBits(_offset);
+        return (int) (bits ^ (bits >>> 32));
+    }
+    private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/converter/ConversionException.java b/src/main/java/javax/measure/converter/ConversionException.java
new file mode 100644
index 0000000..5d16d2a
--- /dev/null
+++ b/src/main/java/javax/measure/converter/ConversionException.java
@@ -0,0 +1,57 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.converter;
+
+/**
+ * Signals that a problem of some sort has occurred either when creating a
+ * converter between two units or during the conversion itself.
+ *
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public class ConversionException extends RuntimeException {
+
+    /**
+     * Constructs a <code>ConversionException</code> with no detail message.
+     */
+    public ConversionException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>ConversionException</code> with the specified detail
+     * message.
+     *
+     * @param  message the detail message.
+     */
+    public ConversionException(String message) {
+        super(message);
+    }
+
+    private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/converter/ExpConverter.java b/src/main/java/javax/measure/converter/ExpConverter.java
new file mode 100644
index 0000000..3cc78e7
--- /dev/null
+++ b/src/main/java/javax/measure/converter/ExpConverter.java
@@ -0,0 +1,110 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.converter;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+
+/**
+ * <p> This class represents a exponential converter of limited precision.
+ *     Such converter  is typically used to create inverse of logarithmic unit.
+ *     
+ * <p> Instances of this class are immutable.</p>
+ *
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public final class ExpConverter extends UnitConverter {
+
+    /**
+     * Holds the logarithmic base.
+     */
+    private final double _base;
+
+    /**
+     * Holds the natural logarithm of the base.
+     */
+    private final double _logBase;
+
+    /**
+     * Creates a logarithmic converter having the specified base.
+     * 
+     * @param  base the logarithmic base (e.g. <code>Math.E</code> for
+     *         the Natural Logarithm).
+     */
+    public ExpConverter(double base) {
+        _base = base;
+        _logBase = Math.log(base);
+    }
+
+    /**
+     * Returns the exponential base of this converter.
+     *
+     * @return the exponential base (e.g. <code>Math.E</code> for
+     *         the Natural Exponential).
+     */
+    public double getBase() {
+        return _base;
+    }
+
+    @Override
+    public UnitConverter inverse() {
+        return new LogConverter(_base);
+    }
+
+    @Override
+    public final String toString() {
+        return "ExpConverter("+ _base + ")";
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof ExpConverter))
+            return false;
+        ExpConverter that = (ExpConverter) obj;
+        return this._base == that._base;
+    }
+
+    @Override
+    public int hashCode() {
+        long bits = Double.doubleToLongBits(_base);
+        return (int) (bits ^ (bits >>> 32));
+    }
+
+    @Override
+    public double convert(double amount) {
+            return Math.exp(_logBase * amount);
+    }
+
+    @Override
+    public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException {
+        return BigDecimal.valueOf(convert(value.doubleValue())); // Reverts to double conversion.
+    }
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/src/main/java/javax/measure/converter/LinearConverter.java b/src/main/java/javax/measure/converter/LinearConverter.java
new file mode 100644
index 0000000..200d48a
--- /dev/null
+++ b/src/main/java/javax/measure/converter/LinearConverter.java
@@ -0,0 +1,126 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.converter;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+
+/**
+ * <p> This class represents a linear converter. A converter is linear if
+ * <code>convert(u + v) == convert(u) + convert(v)</code> and
+ * <code>convert(r * u) == r * convert(u)</code>. For linear converters the
+ * following property always hold:[code]
+ *     y1 = c1.convert(x1); 
+ *     y2 = c2.convert(x2); 
+ *     // then y1*y2 == c1.concatenate(c2).convert(x1*x2)
+ * [/code] </p>
+ * 
+ * <p> {@link LinearConverter#concatenate Concatenation} of linear converters 
+ *     always result into a linear converter.</p>
+ * 
+ * @author <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public abstract class LinearConverter extends UnitConverter {
+
+	@Override
+	public UnitConverter concatenate(UnitConverter converter) {
+		if (converter == IDENTITY)
+			return this;
+		if (!(converter instanceof LinearConverter))
+			return super.concatenate(converter); // Compound non-linear
+													// converter.
+		return new CompoundLinear(this, (LinearConverter) converter);
+	}
+
+	@Override
+	public abstract LinearConverter inverse(); // Inverse of a linear converter
+												// should be linear.
+
+	/**
+	 * This inner class represents a compound linear converter.
+	 */
+	private static class CompoundLinear extends LinearConverter {
+
+		/**
+		 * Holds the first converter.
+		 */
+		private final LinearConverter _first;
+		/**
+		 * Holds the second converter.
+		 */
+		private final LinearConverter _second;
+
+		/**
+		 * Creates a compound linear converter resulting from the combined
+		 * transformation of the specified converters.
+		 * 
+		 * @param first the first converter.
+		 * @param second the second converter.
+		 */
+		private CompoundLinear(LinearConverter first, LinearConverter second) {
+			_first = first;
+			_second = second;
+		}
+
+		@Override
+		public LinearConverter inverse() {
+			return new CompoundLinear(_second.inverse(), _first.inverse());
+		}
+
+		@Override
+		public double convert(double value) {
+			return _second.convert(_first.convert(value));
+		}
+
+		@Override
+		public BigDecimal convert(BigDecimal value, MathContext ctx) {
+			return _second.convert(_first.convert(value, ctx), ctx);
+		}
+
+		@Override
+		public boolean equals(Object cvtr) {
+			if (this == cvtr)
+				return true;
+			if (!(cvtr instanceof CompoundLinear))
+				return false;
+			CompoundLinear that = (CompoundLinear) cvtr;
+			return (this._first.equals(that._first))
+					&& (this._second.equals(that._second));
+		}
+
+		@Override
+		public int hashCode() {
+			return _first.hashCode() + _second.hashCode();
+		}
+
+		private static final long serialVersionUID = 1L;
+	}
+
+	private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/converter/LogConverter.java b/src/main/java/javax/measure/converter/LogConverter.java
new file mode 100644
index 0000000..c726a01
--- /dev/null
+++ b/src/main/java/javax/measure/converter/LogConverter.java
@@ -0,0 +1,112 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.converter;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+
+/**
+ * <p> This class represents a logarithmic converter of limited precision.
+ *     Such converter  is typically used to create logarithmic unit.
+ *     For example:[code]
+ *     Unit<Dimensionless> BEL = Unit.ONE.transform(new LogConverter(10).inverse());
+ *     [/code]</p>
+ *     
+ * <p> Instances of this class are immutable.</p>
+ *
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public final class LogConverter extends UnitConverter {
+
+    /**
+     * Holds the logarithmic base.
+     */
+    private final double _base;
+    /**
+     * Holds the natural logarithm of the base.
+     */
+    private final double _logBase;
+
+    /**
+     * Creates a logarithmic converter having the specified base.
+     * 
+     * @param  base the logarithmic base (e.g. <code>Math.E</code> for
+     *         the Natural Logarithm).
+     */
+    public LogConverter(double base) {
+        _base = base;
+        _logBase = Math.log(base);
+    }
+
+    /**
+     * Returns the logarithmic base of this converter.
+     *
+     * @return the logarithmic base (e.g. <code>Math.E</code> for
+     *         the Natural Logarithm).
+     */
+    public double getBase() {
+        return _base;
+    }
+
+    @Override
+    public UnitConverter inverse() {
+        return new ExpConverter(_base);
+    }
+
+    @Override
+    public final String toString() {
+        return "LogConverter("+ _base + ")";
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof LogConverter))
+            return false;
+        LogConverter that = (LogConverter) obj;
+        return this._base ==that._base;
+    }
+
+    @Override
+    public int hashCode() {
+        long bits = Double.doubleToLongBits(_base);
+        return (int) (bits ^ (bits >>> 32));
+    }
+
+    @Override
+    public double convert(double amount) {
+        return Math.log(amount) / _logBase;
+    }
+
+    @Override
+    public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException {
+        return BigDecimal.valueOf(convert(value.doubleValue())); // Reverts to double conversion.
+    }
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/src/main/java/javax/measure/converter/MultiplyConverter.java b/src/main/java/javax/measure/converter/MultiplyConverter.java
new file mode 100644
index 0000000..88f7f65
--- /dev/null
+++ b/src/main/java/javax/measure/converter/MultiplyConverter.java
@@ -0,0 +1,116 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.converter;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+
+/**
+ * <p> This class represents a converter multiplying numeric values by a 
+ *     constant scaling factor (<code>double</code> based).</p>
+ *      
+ * <p> Instances of this class are immutable.</p>
+ *
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public final class MultiplyConverter extends LinearConverter {
+
+    /**
+     * Holds the scale factor.
+     */
+    private final double _factor;
+
+    /**
+     * Creates a multiply converter with the specified scale factor.
+     *
+     * @param  factor the scaling factor.
+     * @throws IllegalArgumentException if coefficient is <code>1.0</code>
+     *        (would result in identity converter)
+     */
+    public MultiplyConverter(double factor) {
+        if (factor == 1.0)
+            throw new IllegalArgumentException("Would result in identity converter");
+        _factor = factor;
+    }
+
+    /**
+     * Returns the scale factor of this converter.
+     *
+     * @return the scale factor.
+     */
+    public double getFactor() {
+        return _factor;
+    }
+
+    @Override
+    public UnitConverter concatenate(UnitConverter converter) {
+        if (converter instanceof MultiplyConverter) {
+            double factor = _factor * ((MultiplyConverter) converter)._factor;
+            return factor == 1.0 ? IDENTITY : new MultiplyConverter(factor);
+        } else
+            return super.concatenate(converter);
+    }
+
+    @Override
+    public MultiplyConverter inverse() {
+        return new MultiplyConverter(1.0 / _factor);
+    }
+
+    @Override
+    public double convert(double value) {
+        return value * _factor;
+    }
+
+    @Override
+    public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException {
+        return value.multiply(BigDecimal.valueOf(_factor), ctx);
+    }
+
+    @Override
+    public final String toString() {
+        return "MultiplyConverter("+ _factor + ")";
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof MultiplyConverter))
+            return false;
+        MultiplyConverter that = (MultiplyConverter) obj;
+        return this._factor == that._factor;
+    }
+
+    @Override
+    public int hashCode() {
+        long bits = Double.doubleToLongBits(_factor);
+	return (int)(bits ^ (bits >>> 32));
+    }
+
+    private static final long serialVersionUID = 1L;
+
+}
diff --git a/src/main/java/javax/measure/converter/RationalConverter.java b/src/main/java/javax/measure/converter/RationalConverter.java
new file mode 100644
index 0000000..e6b6176
--- /dev/null
+++ b/src/main/java/javax/measure/converter/RationalConverter.java
@@ -0,0 +1,148 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.converter;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+
+/**
+ * <p> This class represents a converter multiplying numeric values by an
+ *     exact scaling factor (represented as the quotient of two 
+ *     <code>BigInteger</code> numbers).</p>
+ *  
+ * <p> Instances of this class are immutable.</p>
+ *
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public final class RationalConverter extends LinearConverter {
+
+    /**
+     * Holds the converter dividend.
+     */
+    private final BigInteger _dividend;
+    /**
+     * Holds the converter divisor (always positive).
+     */
+    private final BigInteger _divisor;
+
+    /**
+     * Creates a rational converter with the specified dividend and 
+     * divisor.
+     *
+     * @param dividend the dividend.
+     * @param divisor the positive divisor.
+     * @throws IllegalArgumentException if <code>divisor <= 0</code>
+     * @throws IllegalArgumentException if <code>dividend == divisor</code>
+     */
+    public RationalConverter(BigInteger dividend, BigInteger divisor) {
+          if (divisor.compareTo(BigInteger.ZERO) <= 0)
+            throw new IllegalArgumentException("Negative or zero divisor");
+        if (dividend.equals(divisor))
+            throw new IllegalArgumentException("Would result in identity converter");
+        _dividend = dividend; // Exact conversion.
+        _divisor = divisor; // Exact conversion.
+    }
+
+    /**
+     * Returns the integer dividend for this rational converter.
+     *
+     * @return this converter dividend.
+     */
+    public BigInteger getDividend() {
+        return _dividend;
+    }
+
+    /**
+     * Returns the integer (positive) divisor for this rational converter.
+     *
+     * @return this converter divisor.
+     */
+    public BigInteger getDivisor() {
+        return _divisor;
+    }
+
+    @Override
+    public double convert(double value) {
+        return value * toDouble(_dividend) / toDouble(_divisor);
+    }
+
+    // Optimization of BigInteger.doubleValue() (implementation too inneficient).
+    private static double toDouble(BigInteger integer) {
+        return (integer.bitLength() < 64) ? integer.longValue() : integer.doubleValue();
+    }
+
+    @Override
+    public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException {
+        return value.multiply(new BigDecimal(_dividend, ctx), ctx).divide(new BigDecimal(_divisor, ctx), ctx);
+    }
+
+    @Override
+    public UnitConverter concatenate(UnitConverter converter) {
+        if (converter instanceof RationalConverter) {
+            RationalConverter that = (RationalConverter) converter;
+            BigInteger dividend = this.getDividend().multiply(that.getDividend());
+            BigInteger divisor = this.getDivisor().multiply(that.getDivisor());
+            BigInteger gcd = dividend.gcd(divisor);
+            dividend = dividend.divide(gcd);
+            divisor = divisor.divide(gcd);
+            return (dividend.equals(BigInteger.ONE) && divisor.equals(BigInteger.ONE))
+                    ? IDENTITY : new RationalConverter(dividend, divisor);
+        } else
+            return super.concatenate(converter);
+    }
+
+    @Override
+    public RationalConverter inverse() {
+        return _dividend.signum() == -1 ? new RationalConverter(getDivisor().negate(), getDividend().negate())
+                : new RationalConverter(getDivisor(), getDividend());
+    }
+
+    @Override
+    public final String toString() {
+        return "RationalConverter("+ _dividend +  "," + _divisor + ")";
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof RationalConverter))
+            return false;
+        RationalConverter that = (RationalConverter) obj;
+        return this._dividend.equals(that._dividend) &&
+                this._divisor.equals(that._divisor);
+    }
+
+    @Override
+    public int hashCode() {
+        return _dividend.hashCode() + _divisor.hashCode();
+    }
+
+    private static final long serialVersionUID = 1L;
+
+}
diff --git a/src/main/java/javax/measure/converter/UnitConverter.java b/src/main/java/javax/measure/converter/UnitConverter.java
new file mode 100644
index 0000000..1568f35
--- /dev/null
+++ b/src/main/java/javax/measure/converter/UnitConverter.java
@@ -0,0 +1,230 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.converter;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.MathContext;
+
+/**
+ * <p> This class represents a converter of numeric values.</p>
+ * 
+ * <p> It is not required for sub-classes to be immutable
+ *     (e.g. currency converter).</p>
+ *     
+ * <p> Sub-classes must ensure unicity of the {@link #IDENTITY identity} 
+ *     converter. In other words, if the result of an operation is equivalent
+ *     to the identity converter, then the unique {@link #IDENTITY} instance 
+ *     should be returned.</p>
+ *
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public abstract class UnitConverter implements Serializable {
+
+    /**
+     * Holds the identity converter (unique). This converter does nothing
+     * (<code>ONE.convert(x) == x</code>). This instance is unique.
+     * (
+     */
+    public static final UnitConverter IDENTITY = new Identity();
+
+    /**
+     * Default constructor.
+     */
+    protected UnitConverter() {
+    }
+
+    /**
+     * Returns the inverse of this converter. If <code>x</code> is a valid
+     * value, then <code>x == inverse().convert(convert(x))</code> to within
+     * the accuracy of computer arithmetic.
+     *
+     * @return the inverse of this converter.
+     */
+    public abstract UnitConverter inverse();
+
+    /**
+     * Converts a <code>double</code> value. 
+     *
+     * @param  value the numeric value to convert.
+     * @return the <code>double</code> value after conversion.
+     */
+    public abstract double convert(double value);
+
+    /**
+     * Converts a {@link BigDecimal} value.
+     *
+     * @param value the numeric value to convert.
+     * @param ctx the math context being used for conversion.
+     * @return the decimal value after conversion.
+     * @throws ArithmeticException if the result is inexact but the
+     *         rounding mode is <code>MathContext.UNNECESSARY</code> or
+     *         <code>mathContext.precision == 0</code> and the quotient has a
+     *         non-terminating decimal expansion.
+     */
+    public abstract BigDecimal convert(BigDecimal value,  MathContext ctx) throws ArithmeticException;
+
+    /**
+     * Indicates whether this converter is considered to be the the same as the
+     * one specified.
+     *
+     * @param  cvtr the converter with which to compare.
+     * @return <code>true</code> if the specified object is a converter 
+     *         considered equals to this converter;<code>false</code> otherwise.
+     */
+    @Override
+    public abstract boolean equals(Object cvtr);
+
+    /**
+     * Returns a hash code value for this converter. Equals object have equal
+     * hash codes.
+     *
+     * @return this converter hash code value.
+     * @see    #equals
+     */
+    @Override
+    public abstract int hashCode();
+
+    /**
+     * Concatenates this converter with another converter. The resulting
+     * converter is equivalent to first converting by the specified converter,
+     * and then converting by this converter. 
+     * 
+     * <p>Note: Implementations must ensure that the {@link #IDENTITY} instance
+     *          is returned if the resulting converter is an identity 
+     *          converter.</p> 
+     * 
+     * @param  converter the other converter.
+     * @return the concatenation of this converter with the other converter.
+     */
+    public UnitConverter concatenate(UnitConverter converter) {
+        return (converter == IDENTITY) ? this : new Compound(converter, this);
+    }
+
+    /**
+     * This inner class represents the identity converter (singleton).
+     */
+    private static final class Identity extends LinearConverter {
+
+        @Override
+        public Identity inverse() {
+            return this;
+        }
+
+        @Override
+        public double convert(double value) {
+            return value;
+        }
+
+        @Override
+        public BigDecimal convert(BigDecimal value, MathContext ctx) {
+            return value;
+        }
+
+        @Override
+        public UnitConverter concatenate(UnitConverter converter) {
+            return converter;
+        }
+
+        @Override
+        public boolean equals(Object cvtr) {
+            return this == cvtr; // Unique instance.
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+
+        private static final long serialVersionUID = 1L;
+
+    }
+
+    /**
+     * This inner class represents a compound converter (non-linear).
+     */
+    private static final class Compound extends UnitConverter {
+
+        /**
+         * Holds the first converter.
+         */
+        private final UnitConverter _first;
+        /**
+         * Holds the second converter.
+         */
+        private final UnitConverter _second;
+
+        /**
+         * Creates a compound converter resulting from the combined
+         * transformation of the specified converters.
+         *
+         * @param  first the first converter.
+         * @param  second the second converter.
+         */
+        private Compound(UnitConverter first, UnitConverter second) {
+            _first = first;
+            _second = second;
+        }
+
+        @Override
+        public UnitConverter inverse() {
+            return new Compound(_second.inverse(), _first.inverse());
+        }
+
+        @Override
+        public double convert(double value) {
+            return _second.convert(_first.convert(value));
+        }
+
+        @Override
+        public BigDecimal convert(BigDecimal value, MathContext ctx) {
+            return _second.convert(_first.convert(value, ctx), ctx);
+        }
+
+        @Override
+        public boolean equals(Object cvtr) {
+            if (this == cvtr)
+                return true;
+            if (!(cvtr instanceof Compound)) 
+                return false;            
+            Compound that = (Compound) cvtr;
+            return (this._first.equals(that._first)) &&
+                    (this._second.equals(that._second));
+        }
+
+        @Override
+        public int hashCode() {
+            return _first.hashCode() + _second.hashCode();
+        }
+
+        private static final long serialVersionUID = 1L;
+    }
+    private static final long serialVersionUID = 1L;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Acceleration.java b/src/main/java/javax/measure/quantity/Acceleration.java
new file mode 100644
index 0000000..f546604
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Acceleration.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the rate of change of velocity with respect to 
+ * time. The system unit for this quantity is "m/s²" (metre per square second).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Acceleration extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Acceleration> UNIT = SI.METRES_PER_SQUARE_SECOND;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Action.java b/src/main/java/javax/measure/quantity/Action.java
new file mode 100644
index 0000000..0be0e66
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Action.java
@@ -0,0 +1,50 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents an energy multiplied by a duration (quantity associated
+ * to the <a href="http://en.wikipedia.org/wiki/Planck%27s_constant">Planck Constant</a>).
+ * The system unit for this quantity is "J·s" (joules second).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ * @see     <a href="http://en.wikipedia.org/wiki/Action_(physics)">Wikipedia's Action</a>
+ *
+ */
+public interface Action extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Action> UNIT = new ProductUnit<Action>(SI.JOULE.times(SI.SECOND));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/AmountOfSubstance.java b/src/main/java/javax/measure/quantity/AmountOfSubstance.java
new file mode 100644
index 0000000..0381f3f
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/AmountOfSubstance.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the number of elementary entities (molecules, for
+ * example) of a substance. The system unit for this quantity is "mol" (mole).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface AmountOfSubstance extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<AmountOfSubstance> UNIT = SI.MOLE;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Angle.java b/src/main/java/javax/measure/quantity/Angle.java
new file mode 100644
index 0000000..7499cdd
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Angle.java
@@ -0,0 +1,47 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the figure formed by two lines diverging from a 
+ * common point. The system unit for this quantity is "rad" (radian).
+ * This quantity is dimensionless.
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Angle extends Dimensionless {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Angle> UNIT = SI.RADIAN;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/AngularAcceleration.java b/src/main/java/javax/measure/quantity/AngularAcceleration.java
new file mode 100644
index 0000000..ba5c8e7
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/AngularAcceleration.java
@@ -0,0 +1,49 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the rate of change of angular velocity with respect
+ * to time. The system unit for this quantity is "rad/s²" (radian per 
+ * square second).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface AngularAcceleration extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<AngularAcceleration> UNIT 
+        = new ProductUnit<AngularAcceleration>(SI.RADIAN.divide(SI.SECOND.pow(2)));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/AngularVelocity.java b/src/main/java/javax/measure/quantity/AngularVelocity.java
new file mode 100644
index 0000000..a9097f4
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/AngularVelocity.java
@@ -0,0 +1,49 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the rate of change of angular displacement
+ * with respect to time. The system unit for this quantity is "rad/s"
+ * (radian per second).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface AngularVelocity extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<AngularVelocity> UNIT 
+        = new ProductUnit<AngularVelocity>(SI.RADIAN.divide(SI.SECOND));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Area.java b/src/main/java/javax/measure/quantity/Area.java
new file mode 100644
index 0000000..b761ca7
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Area.java
@@ -0,0 +1,47 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the extent of a planar region or of the surface of
+ * a solid measured in square units. The system unit for this quantity
+ * is "m²" (square metre).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Area extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Area> UNIT = SI.SQUARE_METRE;
+
+}
diff --git a/src/main/java/javax/measure/quantity/CatalyticActivity.java b/src/main/java/javax/measure/quantity/CatalyticActivity.java
new file mode 100644
index 0000000..d4f2b3c
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/CatalyticActivity.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a catalytic activity. The system unit for this
+ * quantity is "kat" (katal).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface CatalyticActivity extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<CatalyticActivity> UNIT = SI.KATAL;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/DataAmount.java b/src/main/java/javax/measure/quantity/DataAmount.java
new file mode 100644
index 0000000..77f2528
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/DataAmount.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a measure of data amount.
+ * The system unit for this quantity is "bit". This quantity is dimensionless.
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface DataAmount extends Dimensionless {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<DataAmount> UNIT = SI.BIT;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/DataRate.java b/src/main/java/javax/measure/quantity/DataRate.java
new file mode 100644
index 0000000..dd19333
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/DataRate.java
@@ -0,0 +1,47 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the speed of data-transmission.
+ * The system unit for this quantity is "bit/s" (bit per second).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface DataRate extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<DataRate> UNIT = new ProductUnit<DataRate>(SI.BIT.divide(SI.SECOND));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Dimensionless.java b/src/main/java/javax/measure/quantity/Dimensionless.java
new file mode 100644
index 0000000..b6d6ec1
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Dimensionless.java
@@ -0,0 +1,44 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a dimensionless quantity.
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Dimensionless extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Dimensionless> UNIT = Unit.ONE;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Duration.java b/src/main/java/javax/measure/quantity/Duration.java
new file mode 100644
index 0000000..be155a3
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Duration.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a period of existence or persistence. The system
+ * unit for this quantity is "s" (second).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Duration extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Duration> UNIT = SI.SECOND;
+
+}
diff --git a/src/main/java/javax/measure/quantity/DynamicViscosity.java b/src/main/java/javax/measure/quantity/DynamicViscosity.java
new file mode 100644
index 0000000..6548cc6
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/DynamicViscosity.java
@@ -0,0 +1,51 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the dynamic viscosity. 
+ * The system unit for this quantity is "Pa·s" (Pascal-Second).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 3.0, March 2, 2006
+ * @see <a href="http://en.wikipedia.org/wiki/Viscosity">
+ *      Wikipedia: Viscosity</a>
+ */
+public interface DynamicViscosity extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<DynamicViscosity> UNIT
+       = new ProductUnit<DynamicViscosity>(SI.PASCAL.times(SI.SECOND));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/ElectricCapacitance.java b/src/main/java/javax/measure/quantity/ElectricCapacitance.java
new file mode 100644
index 0000000..aee3b02
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/ElectricCapacitance.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents an electric capacitance. The system unit for this
+ * quantity is "F" (Farad).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface ElectricCapacitance extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<ElectricCapacitance> UNIT = SI.FARAD;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/ElectricCharge.java b/src/main/java/javax/measure/quantity/ElectricCharge.java
new file mode 100644
index 0000000..207e95c
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/ElectricCharge.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents an electric charge. The system unit for this
+ * quantity is "C" (Coulomb).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface ElectricCharge extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<ElectricCharge> UNIT = SI.COULOMB;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/ElectricConductance.java b/src/main/java/javax/measure/quantity/ElectricConductance.java
new file mode 100644
index 0000000..9521b0d
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/ElectricConductance.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents an electric conductance. The system unit for this
+ * quantity "S" (Siemens).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface ElectricConductance extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<ElectricConductance> UNIT = SI.SIEMENS;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/ElectricCurrent.java b/src/main/java/javax/measure/quantity/ElectricCurrent.java
new file mode 100644
index 0000000..d3c46d1
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/ElectricCurrent.java
@@ -0,0 +1,47 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the amount of electric charge flowing past
+ * a specified circuit point per unit time. The system unit for
+ * this quantity is "A" (Ampere).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface ElectricCurrent extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<ElectricCurrent> UNIT = SI.AMPERE;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/ElectricInductance.java b/src/main/java/javax/measure/quantity/ElectricInductance.java
new file mode 100644
index 0000000..f2e1f6f
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/ElectricInductance.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents an electric inductance. The system unit for this
+ * quantity is "H" (Henry).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface ElectricInductance extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<ElectricInductance> UNIT = SI.HENRY;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/ElectricPermittivity.java b/src/main/java/javax/measure/quantity/ElectricPermittivity.java
new file mode 100644
index 0000000..4b5278c
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/ElectricPermittivity.java
@@ -0,0 +1,50 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents how an electric field affects, and is affected by
+ * a dielectric medium. The system unit for this quantity is "F/m"
+ * (farads per meter).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ * @see     <a href="http://en.wikipedia.org/wiki/Electric_permittivity">Wikipedia's Electric Permittivity</a>
+ *
+ */
+public interface ElectricPermittivity extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<ElectricPermittivity> UNIT = new ProductUnit<ElectricPermittivity>(SI.FARAD.divide(SI.METER));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/ElectricPotential.java b/src/main/java/javax/measure/quantity/ElectricPotential.java
new file mode 100644
index 0000000..554643a
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/ElectricPotential.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents an electric potential or electromotive force.
+ * The system unit for this quantity is "V" (Volt).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface ElectricPotential extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<ElectricPotential> UNIT = SI.VOLT;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/ElectricResistance.java b/src/main/java/javax/measure/quantity/ElectricResistance.java
new file mode 100644
index 0000000..151f909
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/ElectricResistance.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents an electric resistance.
+ * The system unit for this quantity is "Ω" (Ohm).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface ElectricResistance extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<ElectricResistance> UNIT = SI.OHM;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Energy.java b/src/main/java/javax/measure/quantity/Energy.java
new file mode 100644
index 0000000..2e07e51
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Energy.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the capacity of a physical system to do work.
+ * The system unit for this quantity "J" (Joule).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Energy extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Energy> UNIT = SI.JOULE;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Force.java b/src/main/java/javax/measure/quantity/Force.java
new file mode 100644
index 0000000..599187e
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Force.java
@@ -0,0 +1,47 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a quantity that tends to produce an acceleration
+ * of a body in the direction of its application. The system unit for
+ * this quantity is "N" (Newton).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Force extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Force> UNIT = SI.NEWTON;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Frequency.java b/src/main/java/javax/measure/quantity/Frequency.java
new file mode 100644
index 0000000..17a0e06
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Frequency.java
@@ -0,0 +1,47 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the number of times a specified phenomenon occurs
+ * within a specified interval. The system unit for this quantity is "Hz"
+ * (Hertz).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Frequency extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Frequency> UNIT = SI.HERTZ;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Illuminance.java b/src/main/java/javax/measure/quantity/Illuminance.java
new file mode 100644
index 0000000..697d17b
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Illuminance.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents an illuminance. The system unit for this quantity
+ * is "lx" (lux).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Illuminance extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Illuminance> UNIT = SI.LUX;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/IonizingRadiation.java b/src/main/java/javax/measure/quantity/IonizingRadiation.java
new file mode 100644
index 0000000..5f21c03
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/IonizingRadiation.java
@@ -0,0 +1,50 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the quantity of subatomic particles or
+ * electromagnetic waves that are energetic enough to detach electrons
+ * from atoms or molecules, ionizing them.
+ * The system unit for this quantity is "C/kg ("coulomb per kilogram).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ * @see     <a href="http://en.wikipedia.org/wiki/Ionizing_radiation">Wikipedia's Ionizing Radiation</a>
+ */
+public interface IonizingRadiation extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<IonizingRadiation> UNIT = new ProductUnit<IonizingRadiation>(SI.COULOMB.divide(SI.KILOGRAM));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/KinematicViscosity.java b/src/main/java/javax/measure/quantity/KinematicViscosity.java
new file mode 100644
index 0000000..a1295a6
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/KinematicViscosity.java
@@ -0,0 +1,50 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the diffusion of momentum. 
+ * The system unit for this quantity is "m²/s".
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 3.0, March 2, 2006
+ * @see <a href="http://en.wikipedia.org/wiki/Viscosity">
+ *      Wikipedia: Viscosity</a>
+ */
+public interface KinematicViscosity extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<KinematicViscosity> UNIT 
+         = new ProductUnit<KinematicViscosity>(SI.METRE.pow(2).divide(SI.SECOND));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Length.java b/src/main/java/javax/measure/quantity/Length.java
new file mode 100644
index 0000000..21dc649
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Length.java
@@ -0,0 +1,47 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the extent of something along its greatest 
+ * dimension or the extent of space between two objects or places. 
+ * The system unit for this quantity is "m" (metre).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Length extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Length> UNIT = SI.METRE;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Luminance.java b/src/main/java/javax/measure/quantity/Luminance.java
new file mode 100644
index 0000000..1cb4886
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Luminance.java
@@ -0,0 +1,48 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the luminous intensity per unit area of light
+ * travelling in a given direction. The system unit for this quantity
+ * is "cd/m²" (candela per square meter).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Luminance extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Luminance> UNIT = new ProductUnit<Luminance>(SI.CANDELA.divide(SI.SQUARE_METRE));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/LuminousFlux.java b/src/main/java/javax/measure/quantity/LuminousFlux.java
new file mode 100644
index 0000000..74dbddf
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/LuminousFlux.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a luminous flux. The system unit for this quantity
+ * is "lm" (lumen).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface LuminousFlux extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<LuminousFlux> UNIT = SI.LUMEN;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/LuminousIntensity.java b/src/main/java/javax/measure/quantity/LuminousIntensity.java
new file mode 100644
index 0000000..20c4731
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/LuminousIntensity.java
@@ -0,0 +1,47 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the luminous flux density per solid angle as
+ * measured in a given direction relative to the emitting source. 
+ * The system unit for this quantity is "cd" (candela).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface LuminousIntensity extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<LuminousIntensity> UNIT = SI.CANDELA;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/MagneticFieldStrength.java b/src/main/java/javax/measure/quantity/MagneticFieldStrength.java
new file mode 100644
index 0000000..b838fb7
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/MagneticFieldStrength.java
@@ -0,0 +1,47 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a magnetic field strength. The system unit for this
+ * quantity is "A/m" (ampere per meter).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface MagneticFieldStrength extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<MagneticFieldStrength> UNIT = new ProductUnit<MagneticFieldStrength>(SI.AMPERE.divide(SI.METER));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/MagneticFlux.java b/src/main/java/javax/measure/quantity/MagneticFlux.java
new file mode 100644
index 0000000..757339b
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/MagneticFlux.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a magnetic flux. The system unit for this quantity
+ * is "Wb" (Weber).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface MagneticFlux extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<MagneticFlux> UNIT = SI.WEBER;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/MagneticFluxDensity.java b/src/main/java/javax/measure/quantity/MagneticFluxDensity.java
new file mode 100644
index 0000000..1385498
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/MagneticFluxDensity.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a magnetic flux density. The system unit for this
+ * quantity is "T" (Tesla).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface MagneticFluxDensity extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<MagneticFluxDensity> UNIT = SI.TESLA;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/MagneticPermeability.java b/src/main/java/javax/measure/quantity/MagneticPermeability.java
new file mode 100644
index 0000000..8e7483a
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/MagneticPermeability.java
@@ -0,0 +1,50 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the degree of magnetization of a material that
+ * responds linearly to an applied magnetic field. 
+ * The system unit for this quantity is "H/m" (henry per meter).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ * @see     <a href="http://en.wikipedia.org/wiki/Permeability_(electromagnetism)">Wikipedia's Permeability</a>
+ *
+ */
+public interface MagneticPermeability extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<MagneticPermeability> UNIT = new ProductUnit<MagneticPermeability>(SI.HENRY.divide(SI.METER));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/MagnetomotiveForce.java b/src/main/java/javax/measure/quantity/MagnetomotiveForce.java
new file mode 100644
index 0000000..b1d84c7
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/MagnetomotiveForce.java
@@ -0,0 +1,49 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a force that produces magnetic flux.
+ *
+ * The system unit for this quantity is "At" (ampere-turn).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ * @see     <a href="http://en.wikipedia.org/wiki/Magnetomotive_force">Wikipedia's Magnetomotive Force</a>
+ *
+ */
+public interface MagnetomotiveForce extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<MagnetomotiveForce> UNIT = SI.AMPERE.alternate("At");
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Mass.java b/src/main/java/javax/measure/quantity/Mass.java
new file mode 100644
index 0000000..6f8fafd
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Mass.java
@@ -0,0 +1,48 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the measure of the quantity of matter that a body
+ * or an object contains. The mass of the body is not dependent on gravity
+ * and therefore is different from but proportional to its weight.
+ * The system unit for this quantity is "kg" (kilogram).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Mass extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Mass> UNIT = SI.KILOGRAM;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/MassFlowRate.java b/src/main/java/javax/measure/quantity/MassFlowRate.java
new file mode 100644
index 0000000..da8f6a4
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/MassFlowRate.java
@@ -0,0 +1,50 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the movement of mass per time.
+ * The system unit for this quantity is "kg/s" (kilogram per second).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 3.0, March 2, 2006
+ * @see <a href="http://en.wikipedia.org/wiki/Mass_flow_rate">
+ *      Wikipedia: Mass Flow Rate</a>
+ */
+public interface MassFlowRate extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<MassFlowRate> UNIT 
+       = new ProductUnit<MassFlowRate>(SI.KILOGRAM.divide(SI.SECOND));
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Power.java b/src/main/java/javax/measure/quantity/Power.java
new file mode 100644
index 0000000..1d26734
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Power.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the rate at which work is done. The system unit
+ * for this quantity is "W" (Watt).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Power extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Power> UNIT = SI.WATT;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Pressure.java b/src/main/java/javax/measure/quantity/Pressure.java
new file mode 100644
index 0000000..aa14b19
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Pressure.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a force applied uniformly over a surface.
+ * The system unit for this quantity is "Pa" (Pascal).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Pressure extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Pressure> UNIT = SI.PASCAL;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Quantity.java b/src/main/java/javax/measure/quantity/Quantity.java
new file mode 100644
index 0000000..ff2b2be
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Quantity.java
@@ -0,0 +1,50 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+
+/**
+ * <p> This interface represents any type of quantitative properties or 
+ *     attributes of thing. Mass, time, distance, heat, and angular separation 
+ *     are among the familiar examples of quantitative properties.</p>
+ *     
+ * <p> Distinct quantities have usually different physical dimensions; although 
+ *     it is not required nor necessary, for example {@link Torque} and 
+ *     {@link Energy} have same dimension but are of different nature 
+ *     (vector for torque, scalar for energy).</p>
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 4.0, February 25, 2007
+ * @see <a href="http://en.wikipedia.org/wiki/Quantity">Wikipedia: Quantity</a>
+ * @see <a href="http://en.wikipedia.org/wiki/Dimensional_analysis">
+ *      Wikipedia: Dimensional Analysis</a>
+ */
+public interface Quantity  {
+    
+    // No method - Tagging interface.
+    
+}
diff --git a/src/main/java/javax/measure/quantity/RadiationDoseAbsorbed.java b/src/main/java/javax/measure/quantity/RadiationDoseAbsorbed.java
new file mode 100644
index 0000000..b1a826c
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/RadiationDoseAbsorbed.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the amount of energy deposited per unit of
+ * mass. The system unit for this quantity is "Gy" (Gray).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface RadiationDoseAbsorbed extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<RadiationDoseAbsorbed> UNIT = SI.GRAY;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/RadiationDoseEffective.java b/src/main/java/javax/measure/quantity/RadiationDoseEffective.java
new file mode 100644
index 0000000..f125368
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/RadiationDoseEffective.java
@@ -0,0 +1,47 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the effective (or "equivalent") dose of radiation
+ * received by a human or some other living organism. The system unit for
+ * this quantity is "Sv" (Sievert).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface RadiationDoseEffective extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<RadiationDoseEffective> UNIT = SI.SIEVERT;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/RadioactiveActivity.java b/src/main/java/javax/measure/quantity/RadioactiveActivity.java
new file mode 100644
index 0000000..96cef4b
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/RadioactiveActivity.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a radioactive activity. The system unit for
+ * this quantity is "Bq" (Becquerel).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface RadioactiveActivity extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<RadioactiveActivity> UNIT = SI.BECQUEREL;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/SolidAngle.java b/src/main/java/javax/measure/quantity/SolidAngle.java
new file mode 100644
index 0000000..eea689e
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/SolidAngle.java
@@ -0,0 +1,47 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the angle formed by three or more planes intersecting
+ * at a common point. The system unit for this quantity is "sr" (steradian).
+ * This quantity is dimensionless.
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface SolidAngle extends Dimensionless {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<SolidAngle> UNIT = SI.STERADIAN;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Temperature.java b/src/main/java/javax/measure/quantity/Temperature.java
new file mode 100644
index 0000000..31b24a8
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Temperature.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This class represents the degree of hotness or coldness of a body or
+ * an environment. The system unit for this quantity is "K" (Kelvin).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Temperature extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Temperature> UNIT = SI.KELVIN;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Torque.java b/src/main/java/javax/measure/quantity/Torque.java
new file mode 100644
index 0000000..fb9fdff
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Torque.java
@@ -0,0 +1,53 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the moment of a force. The system unit for this
+ * quantity is "N·m" (Newton-Metre).
+ * 
+ * <p> Note: The Newton-metre ("N·m") is also a way of exressing a Joule (unit
+ *     of energy). However, torque is not energy. So, to avoid confusion, we
+ *     will use the units "N·m" for torque and not "J". This distinction occurs
+ *     due to the scalar nature of energy and the vector nature of torque.</p>
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Torque extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Torque> UNIT = 
+        new ProductUnit<Torque>(SI.NEWTON.times(SI.METRE));
+
+}
diff --git a/src/main/java/javax/measure/quantity/Velocity.java b/src/main/java/javax/measure/quantity/Velocity.java
new file mode 100644
index 0000000..97e0da1
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Velocity.java
@@ -0,0 +1,46 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a distance traveled divided by the time of travel.
+ * The system unit for this quantity is "m/s" (metre per second).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Velocity extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Velocity> UNIT = SI.METRES_PER_SECOND;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Volume.java b/src/main/java/javax/measure/quantity/Volume.java
new file mode 100644
index 0000000..f3198e7
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Volume.java
@@ -0,0 +1,47 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the amount of space occupied by a three-dimensional
+ * object or region of space, expressed in cubic units. The system unit for
+ * this quantity is "m³" (cubic metre).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface Volume extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Volume> UNIT = SI.CUBIC_METRE;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/VolumetricDensity.java b/src/main/java/javax/measure/quantity/VolumetricDensity.java
new file mode 100644
index 0000000..298c58e
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/VolumetricDensity.java
@@ -0,0 +1,49 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a mass per unit volume of a substance under
+ * specified conditions of pressure and temperature. The system unit for
+ * this quantity is "kg/m³" (kilogram per cubic metre).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public interface VolumetricDensity extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<VolumetricDensity> UNIT = new ProductUnit<VolumetricDensity>(
+            SI.KILOGRAM.divide(SI.METRE.pow(3)));
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/VolumetricFlowRate.java b/src/main/java/javax/measure/quantity/VolumetricFlowRate.java
new file mode 100644
index 0000000..390862f
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/VolumetricFlowRate.java
@@ -0,0 +1,51 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents the volume of fluid passing a point in a system
+ * per unit of time. The system unit for this quantity is "m³/s" 
+ * (cubic metre per second).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 3.0, March 2, 2006
+ * @see <a href="http://en.wikipedia.org/wiki/Rate_of_fluid_flow">
+ *      Wikipedia: Volumetric Flow Rate</a>
+ */
+public interface VolumetricFlowRate extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<VolumetricFlowRate> UNIT 
+       = new ProductUnit<VolumetricFlowRate>(SI.METRE.pow(3).divide(SI.SECOND));
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/Wavenumber.java b/src/main/java/javax/measure/quantity/Wavenumber.java
new file mode 100644
index 0000000..adda242
--- /dev/null
+++ b/src/main/java/javax/measure/quantity/Wavenumber.java
@@ -0,0 +1,49 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.quantity;
+import javax.measure.unit.ProductUnit;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+/**
+ * This interface represents a wave property inversely related to wavelength.
+ * The system unit for this quantity is "1/m" (reciprocal meters).
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ * @see     <a href="http://en.wikipedia.org/wiki/Wavenumber">Wikipedia's Wavenumber</a>
+ *
+ */
+public interface Wavenumber extends Quantity {
+
+    /**
+     * Holds the SI unit (Système International d'Unités) for this quantity.
+     */
+    public final static Unit<Wavenumber> UNIT = new ProductUnit<Wavenumber>(Unit.ONE.divide(SI.METER));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/quantity/icons/Acceleration.png b/src/main/java/javax/measure/quantity/icons/Acceleration.png
new file mode 100644
index 0000000..a11dd6f
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Acceleration.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Angle.png b/src/main/java/javax/measure/quantity/icons/Angle.png
new file mode 100644
index 0000000..02c4edf
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Angle.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Area.png b/src/main/java/javax/measure/quantity/icons/Area.png
new file mode 100644
index 0000000..e3d83a8
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Area.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Clothing.png b/src/main/java/javax/measure/quantity/icons/Clothing.png
new file mode 100644
index 0000000..8a029fa
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Clothing.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Currency.png b/src/main/java/javax/measure/quantity/icons/Currency.png
new file mode 100644
index 0000000..4e175c1
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Currency.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/DataAmount.png b/src/main/java/javax/measure/quantity/icons/DataAmount.png
new file mode 100644
index 0000000..8a21672
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/DataAmount.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/DataRate.png b/src/main/java/javax/measure/quantity/icons/DataRate.png
new file mode 100644
index 0000000..e39d67f
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/DataRate.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Energy.png b/src/main/java/javax/measure/quantity/icons/Energy.png
new file mode 100644
index 0000000..2d460d8
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Energy.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Flow_Volume.png b/src/main/java/javax/measure/quantity/icons/Flow_Volume.png
new file mode 100644
index 0000000..2fd14c0
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Flow_Volume.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Force.png b/src/main/java/javax/measure/quantity/icons/Force.png
new file mode 100644
index 0000000..f2051c0
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Force.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/FuelConsumption.png b/src/main/java/javax/measure/quantity/icons/FuelConsumption.png
new file mode 100644
index 0000000..713907a
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/FuelConsumption.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Kitchen.png b/src/main/java/javax/measure/quantity/icons/Kitchen.png
new file mode 100644
index 0000000..8cf4425
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Kitchen.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Length.png b/src/main/java/javax/measure/quantity/icons/Length.png
new file mode 100644
index 0000000..3867f66
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Length.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Luminance.png b/src/main/java/javax/measure/quantity/icons/Luminance.png
new file mode 100644
index 0000000..e7e8b85
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Luminance.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Power.png b/src/main/java/javax/measure/quantity/icons/Power.png
new file mode 100644
index 0000000..2deb5f1
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Power.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Prefixes.png b/src/main/java/javax/measure/quantity/icons/Prefixes.png
new file mode 100644
index 0000000..6ce3ac6
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Prefixes.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Pressure.png b/src/main/java/javax/measure/quantity/icons/Pressure.png
new file mode 100644
index 0000000..9e39ece
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Pressure.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Speed.png b/src/main/java/javax/measure/quantity/icons/Speed.png
new file mode 100644
index 0000000..a435f5f
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Speed.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Temperature.png b/src/main/java/javax/measure/quantity/icons/Temperature.png
new file mode 100644
index 0000000..9496acb
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Temperature.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Time.png b/src/main/java/javax/measure/quantity/icons/Time.png
new file mode 100644
index 0000000..8067ff8
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Time.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Torque.png b/src/main/java/javax/measure/quantity/icons/Torque.png
new file mode 100644
index 0000000..1be38b5
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Torque.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Volume.png b/src/main/java/javax/measure/quantity/icons/Volume.png
new file mode 100644
index 0000000..2da1df0
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Volume.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/Weight.png b/src/main/java/javax/measure/quantity/icons/Weight.png
new file mode 100644
index 0000000..2493f6f
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/Weight.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/close.png b/src/main/java/javax/measure/quantity/icons/close.png
new file mode 100644
index 0000000..964f1fe
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/close.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/nav_dis.png b/src/main/java/javax/measure/quantity/icons/nav_dis.png
new file mode 100644
index 0000000..0821aeb
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/nav_dis.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/nav_down.png b/src/main/java/javax/measure/quantity/icons/nav_down.png
new file mode 100644
index 0000000..2bba1a9
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/nav_down.png differ
diff --git a/src/main/java/javax/measure/quantity/icons/nav_up.png b/src/main/java/javax/measure/quantity/icons/nav_up.png
new file mode 100644
index 0000000..94de580
Binary files /dev/null and b/src/main/java/javax/measure/quantity/icons/nav_up.png differ
diff --git a/src/main/java/javax/measure/unit/AlternateUnit.java b/src/main/java/javax/measure/unit/AlternateUnit.java
new file mode 100644
index 0000000..730f6de
--- /dev/null
+++ b/src/main/java/javax/measure/unit/AlternateUnit.java
@@ -0,0 +1,133 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Quantity;
+
+/**
+ * <p> This class represents the units used in expressions to distinguish
+ *     between quantities of a different nature but of the same dimensions.</p>
+ *     
+ * <p> Instances of this class are created through the 
+ *     {@link Unit#alternate(String)} method.</p>
+ *
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public final class AlternateUnit<Q extends Quantity> extends DerivedUnit<Q> {
+
+    /**
+     * Holds the symbol.
+     */
+    private final String _symbol;
+
+    /**
+     * Holds the parent unit (a system unit).
+     */
+    private final Unit<?> _parent;
+
+    /**
+     * Creates an alternate unit for the specified unit identified by the 
+     * specified symbol. 
+     *
+     * @param symbol the symbol for this alternate unit.
+     * @param parent the system unit from which this alternate unit is
+     *        derived.
+     * @throws UnsupportedOperationException if the source is not 
+     *         a standard unit.
+     * @throws IllegalArgumentException if the specified symbol is 
+     *         associated to a different unit.
+     */
+    AlternateUnit(String symbol, Unit<?> parent) {
+        if (!parent.isSI())
+            throw new UnsupportedOperationException(this + " is not a standard unit");
+        _symbol = symbol;
+        _parent = parent;
+        // Checks if the symbol is associated to a different unit.
+        synchronized (Unit.SYMBOL_TO_UNIT) {
+            Unit<?> unit = Unit.SYMBOL_TO_UNIT.get(symbol);
+            if (unit == null) {
+                Unit.SYMBOL_TO_UNIT.put(symbol, this);
+                return;
+            }
+            if (unit instanceof AlternateUnit) {
+                AlternateUnit<?> existingUnit = (AlternateUnit<?>) unit;
+                if (symbol.equals(existingUnit._symbol) && _parent.equals(existingUnit._parent))
+                    return; // OK, same unit.
+            }
+            throw new IllegalArgumentException("Symbol " + symbol + " is associated to a different unit");
+        }
+    }
+
+    /**
+     * Returns the symbol for this alternate unit.
+     *
+     * @return this alternate unit symbol.
+     */
+    public final String getSymbol() {
+        return _symbol;
+    }
+
+    /**
+     * Returns the parent unit from which this alternate unit is derived 
+     * (a system unit itself).
+     *
+     * @return the parent of the alternate unit.
+     */
+    public final Unit<?> getParent() {
+        return _parent;
+    }
+
+    @Override
+    public final Unit<Q> toSI() {
+        return this;
+    }
+
+    @Override
+    public final UnitConverter getConverterTo(Unit<Q> unit) {
+        return unit.equals(this) ? UnitConverter.IDENTITY : super.getConverterTo(unit);
+    }
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that)
+            return true;
+        if (!(that instanceof AlternateUnit))
+            return false;
+        AlternateUnit<?> thatUnit = (AlternateUnit<?>) that;
+        return this._symbol.equals(thatUnit._symbol); // Symbols are unique.
+    }
+
+    @Override
+    public int hashCode() {
+        return _symbol.hashCode();
+    }
+    private static final long serialVersionUID = 1L;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/unit/AnnotatedUnit.java b/src/main/java/javax/measure/unit/AnnotatedUnit.java
new file mode 100644
index 0000000..828baec
--- /dev/null
+++ b/src/main/java/javax/measure/unit/AnnotatedUnit.java
@@ -0,0 +1,125 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Quantity;
+
+/**
+ * <p> This class represents an annotated unit. It  allows for unit specialization
+ *     and annotation without changing the unit semantic. For example:[code]
+ *        public class Size extends Measurable<Length> {
+ *             private double meters;
+ *             ...
+ *             public static class Unit extends AnnotatedUnit<Length> {
+ *                  private Unit(javax.measure.unit.Unit<Length> realUnit, String annotation) {
+ *                      super(realUnit, annotation);
+ *                  }
+ *                  public static Size.Unit METER = new Size.Unit(SI.METER, "SIZE"); // Equivalent to SI.METER
+ *                  public static Size.Unit INCH = new Size.Unit(NonSI.INCH, "SIZE"); // Equivalent to NonSI.INCH
+ *             }
+ *        }[/code]</p>
+ * <p> Annotation are often written between curly braces behind units 
+ *     but they do not change, for example "%{vol}", "kg{total}", or
+ *     "{RBC}" (for "red blood cells") are equivalent to "%", "kg", and "1"
+ *      respectively.</p>
+ *       
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public class AnnotatedUnit<Q extends Quantity> extends DerivedUnit<Q> {
+
+    /**
+     * Holds the annotation.
+     */
+    private final String _annotation;
+
+    /**
+     * Holds the real unit.
+     */
+    private final Unit<Q> _realUnit;
+
+    /**
+     * Creates an annotated unit for the specified unit.
+     *
+     * @param realUnit the real unit.
+     * @param annotation the annotation.
+     */
+    public AnnotatedUnit(Unit<Q> realUnit, String annotation) {
+        _realUnit = (realUnit instanceof AnnotatedUnit)
+                ? ((AnnotatedUnit<Q>) realUnit).getRealUnit() : realUnit;
+        _annotation = annotation;
+    }
+
+    /**
+     * Returns the annotation of this unit.
+     *
+     * @return the annotation of this unit.
+     */
+    public String getAnnotation() {
+        return _annotation;
+    }
+
+    /**
+     * Returns the equivalent non-annotated unit.
+     *
+     * @return the real unit.
+     */
+    public final Unit<Q> getRealUnit() {
+        return _realUnit;
+    }
+
+    @Override
+    public final Unit<Q> toSI() {
+        return _realUnit.toSI();
+    }
+
+    @Override
+    public final UnitConverter getConverterTo(Unit<Q> unit) {
+        return _realUnit.getConverterTo(unit);
+    }
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that)
+            return true;
+        if (!(that instanceof AnnotatedUnit))
+            return false;
+        AnnotatedUnit<?> thatUnit = (AnnotatedUnit<?>) that;
+        return this._realUnit.equals(thatUnit._realUnit) &&
+                this._annotation.equals(thatUnit._annotation);
+    }
+
+    @Override
+    public int hashCode() {
+        return _realUnit.hashCode() + _annotation.hashCode();
+    }
+    
+    private static final long serialVersionUID = 1L;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/unit/BaseUnit.java b/src/main/java/javax/measure/unit/BaseUnit.java
new file mode 100644
index 0000000..19b3fb8
--- /dev/null
+++ b/src/main/java/javax/measure/unit/BaseUnit.java
@@ -0,0 +1,113 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Quantity;
+
+/**
+ * <p> This class represents the building blocks on top of which all others
+ *     units are created. Base units are typically dimensionally independent.
+ *     Although, the actual unit dimension is determinate by the current
+ *     {@link Dimension.Model model}. Using the {@link
+ *     Dimension.Model#STANDARD standard} model, all seven SI base units 
+ *     are dimensionally independent.</p>
+ *
+ * <p> This class defines the "standard base units" which includes SI base
+ *     units and possibly others user-defined base units. It does not represent 
+ *     the base units of a specific {@link SystemOfUnits}.</p>
+ *           
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ * @see <a href="http://en.wikipedia.org/wiki/SI_base_unit">
+ *       Wikipedia: SI base unit</a>
+ */
+public class BaseUnit<Q extends Quantity> extends Unit<Q> {
+
+    /**
+     * Holds the symbol.
+     */
+    private final String _symbol;
+
+    /**
+     * Creates a base unit having the specified symbol. 
+     *
+     * @param symbol the symbol of this base unit.
+     * @throws IllegalArgumentException if the specified symbol is 
+     *         associated to a different unit.
+     */
+    public BaseUnit(String symbol) {
+        _symbol = symbol;
+        // Checks if the symbol is associated to a different unit.
+        synchronized (Unit.SYMBOL_TO_UNIT) {
+            Unit<?> unit = Unit.SYMBOL_TO_UNIT.get(symbol);
+            if (unit == null) {
+                Unit.SYMBOL_TO_UNIT.put(symbol, this);
+                return;
+            }
+            if (!(unit instanceof BaseUnit))
+                throw new IllegalArgumentException("Symbol " + symbol + " is associated to a different unit");
+        }
+    }
+
+    /**
+     * Returns the unique symbol for this base unit. 
+     *
+     * @return this base unit symbol.
+     */
+    public final String getSymbol() {
+        return _symbol;
+    }
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that)
+            return true;
+        if (!(that instanceof BaseUnit))
+            return false;
+        BaseUnit<?> thatUnit = (BaseUnit<?>) that;
+        return this._symbol.equals(thatUnit._symbol);
+    }
+
+    @Override
+    public int hashCode() {
+        return _symbol.hashCode();
+    }
+
+    @Override
+    public Unit<Q> toSI() {
+        return this;
+    }
+
+    @Override
+    public final UnitConverter getConverterTo(Unit<Q> unit) {
+        return unit.equals(this) ? UnitConverter.IDENTITY : super.getConverterTo(unit);
+    }
+    private static final long serialVersionUID = 1L;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/unit/CompoundUnit.java b/src/main/java/javax/measure/unit/CompoundUnit.java
new file mode 100644
index 0000000..ccadb42
--- /dev/null
+++ b/src/main/java/javax/measure/unit/CompoundUnit.java
@@ -0,0 +1,139 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Quantity;
+
+/**
+ * <p> This class represents the multi-radix units (such as "hour:min:sec").
+ *     Instances of this class are created using the {@link Unit#compound
+ *     Unit.compound} method. Instances of this class are used mostly for
+ *     {@link javax.measure.MeasureFormat formatting} purpose.</p>
+ *
+ * <p> Examples of compound units:[code]
+ *     Unit<Duration> HOUR_MINUTE_SECOND = HOUR.compound(MINUTE).compound(SECOND);
+ *     Unit<Angle> DEGREE_MINUTE_ANGLE = DEGREE_ANGLE.compound(MINUTE_ANGLE);
+ *     Unit<Length> FOOT_INCH = FOOT.compound(INCH);
+ *     [/code]</p>
+ *
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public final class CompoundUnit<Q extends Quantity> extends DerivedUnit<Q> {
+
+    /**
+     * Holds the lowest (main) unit.
+     */
+    private final Unit<Q> _low;
+
+    /**
+     * Holds the highest unit(s).
+     */
+    private final Unit<Q> _high;
+
+    /**
+     * Creates a compound unit from the specified units.
+     *
+     * @param  high the highest unit(s).
+     * @param  low the lowest unit(s).
+     * @throws IllegalArgumentException if both units are not of same type
+     *         (<code>!high.toSI().equals(low.toSI())</code>).
+     */
+    CompoundUnit(Unit<Q> high, Unit<Q> low) {
+        if (!high.toSI().equals(low.toSI()))
+            throw new IllegalArgumentException(
+                    "Cannot compound " + high + " with " + low);
+        if (low instanceof CompoundUnit) {
+            _high = high.compound(((CompoundUnit<Q>) low).getHigh());
+            _low = ((CompoundUnit<Q>) low).getLow();
+        } else {
+            _high = high;
+            _low = low;
+        }
+    }
+
+    /**
+     * Returns the lowest unit or main unit of this compound unit
+     * (never a {@link CompoundUnit}).
+     *
+     * @return the lower unit.
+     */
+    public Unit<Q> getLow() {
+        return _low;
+    }
+
+    /**
+     * Returns the high unit(s) of this compound unit (can be a
+     * {@link CompoundUnit} itself).
+     *
+     * @return the high unit(s).
+     */
+    public Unit<Q> getHigh() {
+        return _high;
+    }
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that)
+            return true;
+        if (!(that instanceof CompoundUnit))
+            return false;
+        CompoundUnit<?> thatUnit = (CompoundUnit<?>) that;
+        return this._low.equals(thatUnit._low) && this._high.equals(thatUnit._high);
+    }
+
+    @Override
+    public int hashCode() {
+        return _high.hashCode() ^ _low.hashCode();
+    }
+
+    /**
+     * Overrides the {@link Unit#toString() default implementation} as
+     * compound units are not recognized by the standard UCUM format.
+     *
+     * @return the textual representation of this compound unit.
+     */
+    @Override
+    public String toString() {
+        return _high + ":" + _low;
+    }
+
+    @Override
+    public Unit<Q> toSI() {
+        return _low.toSI();
+    }
+
+    @Override
+    public final UnitConverter getConverterTo(Unit<Q> unit) {
+        return _low.getConverterTo(unit);
+    }
+    
+    private static final long serialVersionUID = 1L;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/unit/DerivedUnit.java b/src/main/java/javax/measure/unit/DerivedUnit.java
new file mode 100644
index 0000000..cf4a6b7
--- /dev/null
+++ b/src/main/java/javax/measure/unit/DerivedUnit.java
@@ -0,0 +1,48 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import javax.measure.quantity.Quantity;
+
+/**
+ * <p> This class identifies the units created by combining or transforming
+ *     other units.</p>
+ * 
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public abstract class DerivedUnit<Q extends Quantity> extends Unit<Q> {
+
+    /**
+     * Default constructor.
+     */
+    protected DerivedUnit() {
+    }
+    
+    private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/unit/Dimension.java b/src/main/java/javax/measure/unit/Dimension.java
new file mode 100644
index 0000000..1f5a075
--- /dev/null
+++ b/src/main/java/javax/measure/unit/Dimension.java
@@ -0,0 +1,291 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import java.io.Serializable;
+
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Dimensionless;
+
+/**
+ * <p> This class represents the dimension of an unit. Two units <code>u1</code>
+ *     and <code>u2</code> are {@link Unit#isCompatible compatible} if and
+ *     only if <code>(u1.getDimension().equals(u2.getDimension())))</code>
+ *     </p>
+ *     
+ * <p> Instances of this class are immutable.</p>
+ *
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ * @see <a href="http://en.wikipedia.org/wiki/Dimensional_analysis">
+ *      Wikipedia: Dimensional Analysis</a>
+ */
+public final class Dimension implements Serializable {
+
+    /**
+     * Holds the current physical model.
+     */
+    private static Model CurrentModel = Model.STANDARD;
+
+    /**
+     * Holds dimensionless.
+     */
+    public static final Dimension NONE = new Dimension(Unit.ONE);
+
+    /**
+     * Holds length dimension (L).
+     */
+    public static final Dimension LENGTH = new Dimension('L');
+
+    /**
+     * Holds mass dimension (M).
+     */
+    public static final Dimension MASS = new Dimension('M');
+
+    /**
+     * Holds time dimension (T).
+     */
+    public static final Dimension TIME = new Dimension('T');
+
+    /**
+     * Holds electric current dimension (I).
+     */
+    public static final Dimension ELECTRIC_CURRENT = new Dimension('I');
+
+    /**
+     * Holds temperature dimension (Q).
+     */
+    public static final Dimension TEMPERATURE = new Dimension('Q');
+
+    /**
+     * Holds amount of substance dimension (N).
+     */
+    public static final Dimension AMOUNT_OF_SUBSTANCE = new Dimension('N');
+
+    /**
+     * Holds luminous intensity dimension (J).
+     */
+    public static final Dimension LUMINOUS_INTENSITY = new Dimension('J');
+
+    /**
+     * Holds the pseudo unit associated to this dimension.
+     */
+    private final Unit<?> _pseudoUnit;
+
+    /**
+     * Creates a new dimension associated to the specified symbol.
+     * 
+     * @param symbol the associated symbol.
+     */
+    public Dimension(char symbol) {
+        _pseudoUnit = new BaseUnit<Dimensionless>("[" + symbol + "]");
+    }
+
+    /**
+     * Creates a dimension having the specified pseudo-unit 
+     * (base unit or product of base unit).
+     * 
+     * @param pseudoUnit the pseudo-unit identifying this dimension.
+     */
+    private Dimension(Unit<?> pseudoUnit) {
+        _pseudoUnit = pseudoUnit;
+    }
+
+    /**
+     * Returns the product of this dimension with the one specified.
+     *
+     * @param  that the dimension multiplicand.
+     * @return <code>this * that</code>
+     */
+    public final Dimension times(Dimension that) {
+        return new Dimension(this._pseudoUnit.times(that._pseudoUnit));
+    }
+
+    /**
+     * Returns the quotient of this dimension with the one specified.
+     *
+     * @param  that the dimension divisor.
+     * @return <code>this / that</code>
+     */
+    public final Dimension divide(Dimension that) {
+        return new Dimension(this._pseudoUnit.divide(that._pseudoUnit));
+    }
+
+    /**
+     * Returns this dimension raised to an exponent.
+     *
+     * @param  n the exponent.
+     * @return the result of raising this dimension to the exponent.
+     */
+    public final Dimension pow(int n) {
+        return new Dimension(this._pseudoUnit.pow(n));
+    }
+
+    /**
+     * Returns the given root of this dimension.
+     *
+     * @param  n the root's order.
+     * @return the result of taking the given root of this dimension.
+     * @throws ArithmeticException if <code>n == 0</code>.
+     */
+    public final Dimension root(int n) {
+        return new Dimension(this._pseudoUnit.root(n));
+    }
+
+    /**
+     * Returns the representation of this dimension.
+     *
+     * @return the representation of this dimension.
+     */
+    @Override
+    public String toString() {
+        return _pseudoUnit.toString();
+    }
+
+    /**
+     * Indicates if the specified dimension is equals to the one specified.
+     *
+     * @param that the object to compare to.
+     * @return <code>true</code> if this dimension is equals to that dimension;
+     *         <code>false</code> otherwise.
+     */
+    @Override
+    public boolean equals(Object that) {
+        if (this == that)
+            return true;
+        return (that instanceof Dimension) && _pseudoUnit.equals(((Dimension) that)._pseudoUnit);
+    }
+
+    /**
+     * Returns the hash code for this dimension.
+     *
+     * @return this dimension hashcode value.
+     */
+    @Override
+    public int hashCode() {
+        return _pseudoUnit.hashCode();
+    }
+
+    /**
+     * Sets the model used to determinate the units dimensions.
+     *  
+     * @param model the new model to be used when calculating unit dimensions.
+     */
+    public static void setModel(Model model) {
+        Dimension.CurrentModel = model;
+    }
+
+    /**
+     * Returns the model used to determinate the units dimensions
+     * (default {@link Model#STANDARD STANDARD}).
+     *  
+     * @return the model used when calculating unit dimensions.
+     */
+    public static Model getModel() {
+        return Dimension.CurrentModel;
+    }
+
+    /**
+     * This interface represents the mapping between {@link BaseUnit base units}
+     * and {@link Dimension dimensions}. Custom models may allow
+     * conversions not possible using the {@link #STANDARD standard} model.
+     * For example:[code]
+     * public static void main(String[] args) {
+     *     Dimension.Model relativistic = new Dimension.Model() {
+     *         RationalConverter metreToSecond = new RationalConverter(BigInteger.ONE, BigInteger.valueOf(299792458)); // 1/c
+     *   
+     *         public Dimension getDimension(BaseUnit unit) {
+     *             if (unit.equals(METRE)) return Dimension.TIME;
+     *             return Dimension.Model.STANDARD.getDimension(unit);
+     *         }
+     *
+     *         public UnitConverter getTransform(BaseUnit unit) {
+     *             if (unit.equals(METRE)) return metreToSecond;
+     *             return Dimension.Model.STANDARD.getTransform(unit);
+     *         }};
+     *     Dimension.setModel(relativistic);
+     * 
+     *     // Converts 1.0 GeV (energy) to kg (mass).
+     *     System.out.println(Unit.valueOf("GeV").getConverterTo(KILOGRAM).convert(1.0));
+     * }
+     *   
+     * > 1.7826617302520883E-27[/code]
+     */
+    public interface Model {
+
+        /**
+         * Holds the standard model (default).
+         */
+        public Model STANDARD = new Model() {
+
+            public Dimension getDimension(BaseUnit<?> unit) {
+                if (unit.equals(SI.METRE))
+                    return Dimension.LENGTH;
+                if (unit.equals(SI.KILOGRAM))
+                    return Dimension.MASS;
+                if (unit.equals(SI.KELVIN))
+                    return Dimension.TEMPERATURE;
+                if (unit.equals(SI.SECOND))
+                    return Dimension.TIME;
+                if (unit.equals(SI.AMPERE))
+                    return Dimension.ELECTRIC_CURRENT;
+                if (unit.equals(SI.MOLE))
+                    return Dimension.AMOUNT_OF_SUBSTANCE;
+                if (unit.equals(SI.CANDELA))
+                    return Dimension.LUMINOUS_INTENSITY;
+                return new Dimension(new BaseUnit<Dimensionless>("[" + unit.getSymbol() + "]"));
+            }
+
+            public UnitConverter getTransform(BaseUnit<?> unit) {
+                return UnitConverter.IDENTITY;
+            }
+        };
+
+        /**
+         * Returns the dimension of the specified base unit (a dimension 
+         * particular to the base unit if the base unit is not recognized).
+         * 
+         * @param unit the base unit for which the dimension is returned.
+         * @return the dimension of the specified unit.
+         */
+        Dimension getDimension(BaseUnit<?> unit);
+
+        /**
+         * Returns the normalization transform of the specified base unit
+         * ({@link UnitConverter#IDENTITY IDENTITY} if the base unit is 
+         * not recognized).
+         * 
+         * @param unit the base unit for which the transform is returned.
+         * @return the normalization transform.
+         */
+        UnitConverter getTransform(BaseUnit<?> unit);
+    }
+    
+    private static final long serialVersionUID = 1L;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/unit/NonSI.java b/src/main/java/javax/measure/unit/NonSI.java
new file mode 100644
index 0000000..c2fec0a
--- /dev/null
+++ b/src/main/java/javax/measure/unit/NonSI.java
@@ -0,0 +1,1070 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences Copyright
+ * (c) 2005-2009, JScience (http://jscience.org/) All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.measure.converter.LogConverter;
+import javax.measure.converter.RationalConverter;
+import javax.measure.quantity.*;
+
+import static javax.measure.unit.SI.*;
+
+/**
+ * <p> This class contains units that are not part of the International System 
+ *     of Units, that is, they are outside the SI, but are important and widely
+ *     used.</p>
+ * 
+ * @author <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public final class NonSI extends SystemOfUnits {
+
+	/**
+	 * Holds collection of NonSI units.
+	 */
+	private static HashSet<Unit<?>> UNITS = new HashSet<Unit<?>>();
+
+	/**
+	 * Holds the standard gravity constant: 9.80665 m/s² exact.
+	 */
+	private static final int STANDARD_GRAVITY_DIVIDEND = 980665;
+
+	private static final int STANDARD_GRAVITY_DIVISOR = 100000;
+
+	/**
+	 * Holds the international foot: 0.3048 m exact.
+	 */
+	private static final int INTERNATIONAL_FOOT_DIVIDEND = 3048;
+
+	private static final int INTERNATIONAL_FOOT_DIViSOR = 10000;
+
+	/**
+	 * Holds the avoirdupois pound: 0.45359237 kg exact
+	 */
+	private static final int AVOIRDUPOIS_POUND_DIVIDEND = 45359237;
+
+	private static final int AVOIRDUPOIS_POUND_DIVISOR = 100000000;
+
+	/**
+	 * Holds the Avogadro constant.
+	 */
+	private static final double AVOGADRO_CONSTANT = 6.02214199e23; // (1/mol).
+
+	/**
+	 * Holds the electric charge of one electron.
+	 */
+	private static final double ELEMENTARY_CHARGE = 1.602176462e-19; // (C).
+
+	/**
+	 * Default constructor (prevents this class from being instantiated).
+	 */
+	private NonSI() {
+	}
+
+	/**
+	 * Returns the unique instance of this class.
+	 * 
+	 * @return the NonSI instance.
+	 */
+	public static NonSI getInstance() {
+		return INSTANCE;
+	}
+
+	private static final NonSI INSTANCE = new NonSI();
+
+	// /////////////////
+	// Dimensionless //
+	// /////////////////
+	/**
+	 * A dimensionless unit equals to <code>pi</code> (standard name
+	 * <code>π</code>).
+	 */
+	public static final Unit<Dimensionless> PI = nonSI(Unit.ONE
+			.times(StrictMath.PI));
+
+	/**
+	 * A dimensionless unit equals to <code>0.01</code> (standard name
+	 * <code>%</code>).
+	 */
+	public static final Unit<Dimensionless> PERCENT = nonSI(Unit.ONE
+			.divide(100));
+
+	/**
+	 * A logarithmic unit used to describe a ratio (standard name
+	 * <code>dB</code>).
+	 */
+	public static final Unit<Dimensionless> DECIBEL = nonSI(Unit.ONE
+			.transform(new LogConverter(10).inverse().concatenate(
+					new RationalConverter(BigInteger.ONE, BigInteger.TEN))));
+
+	// ///////////////////////
+	// Amount of substance //
+	// ///////////////////////
+	/**
+	 * A unit of amount of substance equals to one atom (standard name
+	 * <code>atom</code>).
+	 */
+	public static final Unit<AmountOfSubstance> ATOM = nonSI(MOLE
+			.divide(AVOGADRO_CONSTANT));
+
+	// //////////
+	// Length //
+	// //////////
+	/**
+	 * A unit of length equal to <code>0.3048 m</code> (standard name
+	 * <code>ft</code>).
+	 */
+	public static final Unit<Length> FOOT = nonSI(METRE.times(
+			INTERNATIONAL_FOOT_DIVIDEND).divide(INTERNATIONAL_FOOT_DIViSOR));
+
+	/**
+	 * A unit of length equal to <code>1200/3937 m</code> (standard name
+	 * <code>foot_survey_us</code>). See also: <a
+	 * href="http://www.sizes.com/units/foot.htm">foot</a>
+	 */
+	public static final Unit<Length> FOOT_SURVEY_US = nonSI(METRE.times(1200)
+			.divide(3937));
+
+	/**
+	 * A unit of length equal to <code>0.9144 m</code> (standard name
+	 * <code>yd</code>).
+	 */
+	public static final Unit<Length> YARD = nonSI(FOOT.times(3));
+
+	/**
+	 * A unit of length equal to <code>0.0254 m</code> (standard name
+	 * <code>in</code>).
+	 */
+	public static final Unit<Length> INCH = nonSI(FOOT.divide(12));
+
+	/**
+	 * A unit of length equal to <code>1609.344 m</code> (standard name
+	 * <code>mi</code>).
+	 */
+	public static final Unit<Length> MILE = nonSI(METRE.times(1609344).divide(
+			1000));
+
+	/**
+	 * A unit of length equal to <code>1852.0 m</code> (standard name
+	 * <code>nmi</code>).
+	 */
+	public static final Unit<Length> NAUTICAL_MILE = nonSI(METRE.times(1852));
+
+	/**
+	 * A unit of length equal to <code>1E-10 m</code> (standard name
+	 * <code>Å</code>).
+	 */
+	public static final Unit<Length> ANGSTROM = nonSI(METRE
+			.divide(10000000000L));
+
+	/**
+	 * A unit of length equal to the average distance from the center of the
+	 * Earth to the center of the Sun (standard name <code>ua</code>).
+	 */
+	public static final Unit<Length> ASTRONOMICAL_UNIT = nonSI(METRE
+			.times(149597870691.0));
+
+	/**
+	 * A unit of length equal to the distance that light travels in one year
+	 * through a vacuum (standard name <code>ly</code>).
+	 */
+	public static final Unit<Length> LIGHT_YEAR = nonSI(METRE
+			.times(9.460528405e15));
+
+	/**
+	 * A unit of length equal to the distance at which a star would appear to
+	 * shift its position by one arcsecond over the course the time (about 3
+	 * months) in which the Earth moves a distance of {@link #ASTRONOMICAL_UNIT}
+	 * in the direction perpendicular to the direction to the star (standard
+	 * name <code>pc</code>).
+	 */
+	public static final Unit<Length> PARSEC = nonSI(METRE.times(30856770e9));
+
+	/**
+	 * A unit of length equal to <code>0.013837 {@link #INCH}</code> exactly (standard name
+	 * <code>pt</code>).
+	 * 
+	 * @see #PIXEL
+	 */
+	public static final Unit<Length> POINT = nonSI(INCH.times(13837).divide(
+			1000000));
+
+	/**
+	 * A unit of length equal to <code>1/72 {@link #INCH}</code> (standard name <code>pixel</code>). It is
+	 * the American point rounded to an even 1/72 inch.
+	 * 
+	 * @see #POINT
+	 */
+	public static final Unit<Length> PIXEL = nonSI(INCH.divide(72));
+
+	/**
+	 * Equivalent {@link #PIXEL}
+	 */
+	public static final Unit<Length> COMPUTER_POINT = PIXEL;
+
+	// ////////////
+	// Duration //
+	// ////////////
+	/**
+	 * A unit of duration equal to <code>60 s</code> (standard name
+	 * <code>min</code>).
+	 */
+	public static final Unit<Duration> MINUTE = nonSI(SI.SECOND.times(60));
+
+	/**
+	 * A unit of duration equal to <code>60 {@link #MINUTE}</code> (standard name <code>h</code>).
+	 */
+	public static final Unit<Duration> HOUR = nonSI(MINUTE.times(60));
+
+	/**
+	 * A unit of duration equal to <code>24 {@link #HOUR}</code> (standard name <code>d</code>).
+	 */
+	public static final Unit<Duration> DAY = nonSI(HOUR.times(24));
+
+	/**
+	 * A unit of duration equal to the time required for a complete rotation of
+	 * the earth in reference to any star or to the vernal equinox at the
+	 * meridian, equal to 23 hours, 56 minutes, 4.09 seconds (standard name
+	 * <code>day_sidereal</code>).
+	 */
+	public static final Unit<Duration> DAY_SIDEREAL = nonSI(SECOND
+			.times(86164.09));
+
+	/**
+	 * A unit of duration equal to 7 {@link #DAY} (standard name
+	 * <code>week</code>).
+	 */
+	public static final Unit<Duration> WEEK = nonSI(DAY.times(7));
+
+	/**
+	 * A unit of duration equal to 365 {@link #DAY} (standard name
+	 * <code>year</code>).
+	 */
+	public static final Unit<Duration> YEAR_CALENDAR = nonSI(DAY.times(365));
+
+	/**
+	 * A unit of duration equal to one complete revolution of the earth about
+	 * the sun, relative to the fixed stars, or 365 days, 6 hours, 9 minutes,
+	 * 9.54 seconds (standard name <code>year_sidereal</code>).
+	 */
+	public static final Unit<Duration> YEAR_SIDEREAL = nonSI(SECOND
+			.times(31558149.54));
+
+	/**
+	 * The Julian year, as used in astronomy and other sciences, is a time unit
+	 * defined as exactly 365.25 days. This is the normal meaning of the unit
+	 * "year" (symbol "a" from the Latin annus, annata) used in various
+	 * scientific contexts.
+	 */
+	public static final Unit<Duration> YEAR_JULIEN = nonSI(SECOND
+			.times(31557600));
+
+	// ////////
+	// Mass //
+	// ////////
+	/**
+	 * A unit of mass equal to 1/12 the mass of the carbon-12 atom (standard
+	 * name <code>u</code>).
+	 */
+	public static final Unit<Mass> ATOMIC_MASS = nonSI(KILOGRAM
+			.times(1e-3 / AVOGADRO_CONSTANT));
+
+	/**
+	 * A unit of mass equal to the mass of the electron (standard name
+	 * <code>me</code>).
+	 */
+	public static final Unit<Mass> ELECTRON_MASS = nonSI(KILOGRAM
+			.times(9.10938188e-31));
+
+	/**
+	 * A unit of mass equal to <code>453.59237 grams</code> (avoirdupois pound,
+	 * standard name <code>lb</code>).
+	 */
+	public static final Unit<Mass> POUND = nonSI(KILOGRAM.times(
+			AVOIRDUPOIS_POUND_DIVIDEND).divide(AVOIRDUPOIS_POUND_DIVISOR));
+
+	/**
+	 * A unit of mass equal to <code>1 / 16 {@link #POUND}</code> (standard name <code>oz</code>).
+	 */
+	public static final Unit<Mass> OUNCE = nonSI(POUND.divide(16));
+
+	/**
+	 * A unit of mass equal to <code>2000 {@link #POUND}</code> (short ton, standard name
+	 * <code>ton_us</code>).
+	 */
+	public static final Unit<Mass> TON_US = nonSI(POUND.times(2000));
+
+	/**
+	 * A unit of mass equal to <code>2240 {@link #POUND}</code> (long ton, standard name
+	 * <code>ton_uk</code>).
+	 */
+	public static final Unit<Mass> TON_UK = nonSI(POUND.times(2240));
+
+	/**
+	 * A unit of mass equal to <code>1000 kg</code> (metric ton, standard name
+	 * <code>t</code>).
+	 */
+	public static final Unit<Mass> METRIC_TON = nonSI(KILOGRAM.times(1000));
+
+	// ///////////////////
+	// Electric charge //
+	// ///////////////////
+	/**
+	 * A unit of electric charge equal to the charge on one electron (standard
+	 * name <code>e</code>).
+	 */
+	public static final Unit<ElectricCharge> E = nonSI(COULOMB
+			.times(ELEMENTARY_CHARGE));
+
+	/**
+	 * A unit of electric charge equal to equal to the product of Avogadro's
+	 * number (see {@link SI#MOLE}) and the charge (1 e) on a single electron
+	 * (standard name <code>Fd</code>).
+	 */
+	public static final Unit<ElectricCharge> FARADAY = nonSI(COULOMB
+			.times(ELEMENTARY_CHARGE * AVOGADRO_CONSTANT)); // e/mol
+
+	/**
+	 * A unit of electric charge which exerts a force of one dyne on an equal
+	 * charge at a distance of one centimeter (standard name <code>Fr</code>).
+	 */
+	public static final Unit<ElectricCharge> FRANKLIN = nonSI(COULOMB
+			.times(3.3356e-10));
+
+	// ///////////////
+	// Temperature //
+	// ///////////////
+	/**
+	 * A unit of temperature equal to <code>5/9 °K</code> (standard name
+	 * <code>°R</code>).
+	 */
+	public static final Unit<Temperature> RANKINE = nonSI(KELVIN.times(5)
+			.divide(9));
+
+	/**
+	 * A unit of temperature equal to degree Rankine minus
+	 * <code>459.67 °R</code> (standard name <code>°F</code>).
+	 * 
+	 * @see #RANKINE
+	 */
+	public static final Unit<Temperature> FAHRENHEIT = nonSI(RANKINE
+			.plus(459.67));
+
+	// /////////
+	// Angle //
+	// /////////
+	/**
+	 * A unit of angle equal to a full circle or <code>2<i>π</i> 
+	 * {@link SI#RADIAN}</code> (standard name <code>rev</code>).
+	 */
+	public static final Unit<Angle> REVOLUTION = nonSI(RADIAN.times(2)
+			.times(PI).asType(Angle.class));
+
+	/**
+	 * A unit of angle equal to <code>1/360 {@link #REVOLUTION}</code> (standard name <code>°</code>).
+	 */
+	public static final Unit<Angle> DEGREE_ANGLE = nonSI(REVOLUTION.divide(360));
+
+	/**
+	 * A unit of angle equal to <code>1/60 {@link #DEGREE_ANGLE}</code> (standard name <code>′</code>).
+	 */
+	public static final Unit<Angle> MINUTE_ANGLE = nonSI(DEGREE_ANGLE
+			.divide(60));
+
+	/**
+	 * A unit of angle equal to <code>1/60 {@link #MINUTE_ANGLE}</code> (standard name <code>"</code>).
+	 */
+	public static final Unit<Angle> SECOND_ANGLE = nonSI(MINUTE_ANGLE
+			.divide(60));
+
+	/**
+	 * A unit of angle equal to <code>0.01 {@link SI#RADIAN}</code> (standard name
+	 * <code>centiradian</code>).
+	 */
+	public static final Unit<Angle> CENTIRADIAN = nonSI(RADIAN.divide(100));
+
+	/**
+	 * A unit of angle measure equal to <code>1/400 {@link #REVOLUTION}</code> (standard name <code>grade</code>
+	 * ).
+	 */
+	public static final Unit<Angle> GRADE = nonSI(REVOLUTION.divide(400));
+
+	// ////////////
+	// Velocity //
+	// ////////////
+	/**
+	 * A unit of velocity expressing the number of {@link NonSI#FOOT feet} per
+	 * {@link SI#SECOND second}.
+	 */
+	public static final Unit<Velocity> FOOT_PER_SECOND = nonSI(
+			NonSI.FOOT.divide(SI.SECOND)).asType(Velocity.class);
+
+	/**
+	 * A unit of velocity expressing the number of international {@link #MILE
+	 * miles} per {@link #HOUR hour} (abbreviation <code>mph</code>).
+	 */
+	public static final Unit<Velocity> MILES_PER_HOUR = nonSI(
+			NonSI.MILE.divide(NonSI.HOUR)).asType(Velocity.class);
+
+	/**
+	 * A unit of velocity expressing the number of {@link SI#KILOMETRE} per
+	 * {@link #HOUR hour}.
+	 */
+	public static final Unit<Velocity> KILOMETRES_PER_HOUR = nonSI(
+			SI.KILOMETRE.divide(NonSI.HOUR)).asType(Velocity.class);
+
+	/**
+	 * Equivalent to {@link #KILOMETRES_PER_HOUR}.
+	 */
+	public static final Unit<Velocity> KILOMETERS_PER_HOUR = KILOMETRES_PER_HOUR;
+
+	/**
+	 * A unit of velocity expressing the number of {@link #NAUTICAL_MILE
+	 * nautical miles} per {@link #HOUR hour} (abbreviation <code>kn</code>).
+	 */
+	public static final Unit<Velocity> KNOT = nonSI(
+			NonSI.NAUTICAL_MILE.divide(NonSI.HOUR)).asType(Velocity.class);
+
+	/**
+	 * A unit of velocity relative to the speed of light (standard name
+	 * <code>c</code>).
+	 */
+	public static final Unit<Velocity> C = nonSI(METRES_PER_SECOND
+			.times(299792458));
+
+	// ////////////////
+	// Acceleration //
+	// ////////////////
+	/**
+	 * A unit of acceleration equal to the gravity at the earth's surface
+	 * (standard name <code>grav</code>).
+	 */
+	public static final Unit<Acceleration> G = nonSI(METRES_PER_SQUARE_SECOND
+			.times(STANDARD_GRAVITY_DIVIDEND).divide(STANDARD_GRAVITY_DIVISOR));
+
+	// ////////
+	// Area //
+	// ////////
+	/**
+	 * A unit of area equal to <code>100 m²</code> (standard name <code>a</code>
+	 * ).
+	 */
+	public static final Unit<Area> ARE = nonSI(SQUARE_METRE.times(100));
+
+	/**
+	 * A unit of area equal to <code>100 {@link #ARE}</code> (standard name <code>ha</code>).
+	 */
+	public static final Unit<Area> HECTARE = nonSI(ARE.times(100)); // Exact.
+
+	// ///////////////
+	// Data Amount //
+	// ///////////////
+	/**
+	 * A unit of data amount equal to <code>8 {@link SI#BIT}</code> (BinarY TErm, standard name
+	 * <code>byte</code>).
+	 */
+	public static final Unit<DataAmount> BYTE = nonSI(BIT.times(8));
+
+	/**
+	 * Equivalent {@link #BYTE}
+	 */
+	public static final Unit<DataAmount> OCTET = BYTE;
+
+	// ////////////////////
+	// Electric current //
+	// ////////////////////
+	/**
+	 * A unit of electric charge equal to the centimeter-gram-second
+	 * electromagnetic unit of magnetomotive force, equal to <code>10/4
+	 * πampere-turn</code> (standard name <code>Gi</code>).
+	 */
+	public static final Unit<ElectricCurrent> GILBERT = nonSI(SI.AMPERE.times(
+			10).divide(4).times(PI).asType(ElectricCurrent.class));
+
+	// //////////
+	// Energy //
+	// //////////
+	/**
+	 * A unit of energy equal to <code>1E-7 J</code> (standard name
+	 * <code>erg</code>).
+	 */
+	public static final Unit<Energy> ERG = nonSI(JOULE.divide(10000000));
+
+	/**
+	 * A unit of energy equal to one electron-volt (standard name
+	 * <code>eV</code>, also recognized <code>keV, MeV, GeV</code>).
+	 */
+	public static final Unit<Energy> ELECTRON_VOLT = nonSI(JOULE
+			.times(ELEMENTARY_CHARGE));
+
+	// ///////////////
+	// Illuminance //
+	// ///////////////
+	/**
+	 * A unit of illuminance equal to <code>1E4 Lx</code> (standard name
+	 * <code>La</code>).
+	 */
+	public static final Unit<Illuminance> LAMBERT = nonSI(LUX.times(10000));
+
+	// /////////////////
+	// Magnetic Flux //
+	// /////////////////
+	/**
+	 * A unit of magnetic flux equal <code>1E-8 Wb</code> (standard name
+	 * <code>Mx</code>).
+	 */
+	public static final Unit<MagneticFlux> MAXWELL = nonSI(WEBER
+			.divide(100000000));
+
+	// /////////////////////////
+	// Magnetic Flux Density //
+	// /////////////////////////
+	/**
+	 * A unit of magnetic flux density equal <code>1000 A/m</code> (standard
+	 * name <code>G</code>).
+	 */
+	public static final Unit<MagneticFluxDensity> GAUSS = nonSI(TESLA
+			.divide(10000));
+
+	// /////////
+	// Force //
+	// /////////
+	/**
+	 * A unit of force equal to <code>1E-5 N</code> (standard name
+	 * <code>dyn</code>).
+	 */
+	public static final Unit<Force> DYNE = nonSI(NEWTON.divide(100000));
+
+	/**
+	 * A unit of force equal to <code>9.80665 N</code> (standard name
+	 * <code>kgf</code>).
+	 */
+	public static final Unit<Force> KILOGRAM_FORCE = nonSI(NEWTON.times(
+			STANDARD_GRAVITY_DIVIDEND).divide(STANDARD_GRAVITY_DIVISOR));
+
+	/**
+	 * A unit of force equal to <code>{@link #POUND}·{@link #G}</code> (standard name <code>lbf</code>).
+	 */
+	public static final Unit<Force> POUND_FORCE = nonSI(NEWTON.times(
+			1L * AVOIRDUPOIS_POUND_DIVIDEND * STANDARD_GRAVITY_DIVIDEND)
+			.divide(1L * AVOIRDUPOIS_POUND_DIVISOR * STANDARD_GRAVITY_DIVISOR));
+
+	// /////////
+	// Power //
+	// /////////
+	/**
+	 * A unit of power equal to the power required to raise a mass of 75
+	 * kilograms at a velocity of 1 meter per second (metric, standard name
+	 * <code>hp</code>).
+	 */
+	public static final Unit<Power> HORSEPOWER = nonSI(WATT.times(735.499));
+
+	// ////////////
+	// Pressure //
+	// ////////////
+	/**
+	 * A unit of pressure equal to the average pressure of the Earth's
+	 * atmosphere at sea level (standard name <code>atm</code>).
+	 */
+	public static final Unit<Pressure> ATMOSPHERE = nonSI(PASCAL.times(101325));
+
+	/**
+	 * A unit of pressure equal to <code>100 kPa</code> (standard name
+	 * <code>bar</code>).
+	 */
+	public static final Unit<Pressure> BAR = nonSI(PASCAL.times(100000));
+
+	/**
+	 * A unit of pressure equal to the pressure exerted at the Earth's surface
+	 * by a column of mercury 1 millimeter high (standard name <code>mmHg</code>
+	 * ).
+	 */
+	public static final Unit<Pressure> MILLIMETER_OF_MERCURY = nonSI(PASCAL
+			.times(133.322));
+
+	/**
+	 * A unit of pressure equal to the pressure exerted at the Earth's surface
+	 * by a column of mercury 1 inch high (standard name <code>inHg</code>).
+	 */
+	public static final Unit<Pressure> INCH_OF_MERCURY = nonSI(PASCAL
+			.times(3386.388));
+
+	// ///////////////////////////
+	// Radiation dose absorbed //
+	// ///////////////////////////
+	/**
+	 * A unit of radiation dose absorbed equal to a dose of 0.01 joule of energy
+	 * per kilogram of mass (J/kg) (standard name <code>rd</code>).
+	 */
+	public static final Unit<RadiationDoseAbsorbed> RAD = nonSI(GRAY
+			.divide(100));
+
+	/**
+	 * A unit of radiation dose effective equal to <code>0.01 Sv</code>
+	 * (standard name <code>rem</code>).
+	 */
+	public static final Unit<RadiationDoseEffective> REM = nonSI(SIEVERT
+			.divide(100));
+
+	// ////////////////////////
+	// Radioactive activity //
+	// ////////////////////////
+	/**
+	 * A unit of radioctive activity equal to the activity of a gram of radium
+	 * (standard name <code>Ci</code>).
+	 */
+	public static final Unit<RadioactiveActivity> CURIE = nonSI(BECQUEREL
+			.times(37000000000L));
+
+	/**
+	 * A unit of radioctive activity equal to 1 million radioactive
+	 * disintegrations per second (standard name <code>Rd</code>).
+	 */
+	public static final Unit<RadioactiveActivity> RUTHERFORD = nonSI(SI.BECQUEREL
+			.times(1000000));
+
+	// ///////////////
+	// Solid angle //
+	// ///////////////
+	/**
+	 * A unit of solid angle equal to <code>4 <i>π</i> steradians</code>
+	 * (standard name <code>sphere</code>).
+	 */
+	public static final Unit<SolidAngle> SPHERE = nonSI(STERADIAN.times(4)
+			.times(PI).asType(SolidAngle.class));
+
+	// //////////
+	// Volume //
+	// //////////
+	/**
+	 * A unit of volume equal to one cubic decimeter (default label
+	 * <code>L</code>, also recognized <code>µL, mL, cL, dL</code>).
+	 */
+	public static final Unit<Volume> LITRE = nonSI(CUBIC_METRE.divide(1000));
+
+	/**
+	 * Equivalent to {@link #LITRE} (American spelling).
+	 */
+	public static final Unit<Volume> LITER = LITRE;
+
+	/**
+	 * A unit of volume equal to one cubic inch (<code>in³</code>).
+	 */
+	public static final Unit<Volume> CUBIC_INCH = nonSI(INCH.pow(3).asType(
+			Volume.class));
+
+	/**
+	 * A unit of volume equal to one US gallon, Liquid Unit. The U.S. liquid
+	 * gallon is based on the Queen Anne or Wine gallon occupying 231 cubic
+	 * inches (standard name <code>gal</code>).
+	 */
+	public static final Unit<Volume> GALLON_LIQUID_US = nonSI(CUBIC_INCH
+			.times(231));
+
+	/**
+	 * A unit of volume equal to <code>1 / 128 {@link #GALLON_LIQUID_US}</code> (standard name
+	 * <code>oz_fl</code>).
+	 */
+	public static final Unit<Volume> OUNCE_LIQUID_US = nonSI(GALLON_LIQUID_US
+			.divide(128));
+
+	/**
+	 * A unit of volume equal to one US dry gallon. (standard name
+	 * <code>gallon_dry_us</code>).
+	 */
+	public static final Unit<Volume> GALLON_DRY_US = nonSI(CUBIC_INCH.times(
+			2688025).divide(10000));
+
+	/**
+	 * A unit of volume equal to <code>4.546 09 {@link #LITRE}</code> (standard name <code>gal_uk</code>).
+	 */
+	public static final Unit<Volume> GALLON_UK = nonSI(LITRE.times(454609)
+			.divide(100000));
+
+	/**
+	 * A unit of volume equal to <code>1 / 160 {@link #GALLON_UK}</code> (standard name
+	 * <code>oz_fl_uk</code>).
+	 */
+	public static final Unit<Volume> OUNCE_LIQUID_UK = nonSI(GALLON_UK
+			.divide(160));
+
+	// /////////////
+	// Viscosity //
+	// /////////////
+	/**
+	 * A unit of dynamic viscosity equal to <code>1 g/(cm·s)</code> (cgs unit).
+	 */
+	@SuppressWarnings("unchecked")
+	public static final Unit<DynamicViscosity> POISE = nonSI((Unit<DynamicViscosity>) GRAM
+			.divide(CENTI(METRE).times(SECOND)));
+
+	/**
+	 * A unit of kinematic viscosity equal to <code>1 cm²/s</code> (cgs unit).
+	 */
+	@SuppressWarnings("unchecked")
+	public static final Unit<KinematicViscosity> STOKE = nonSI((Unit<KinematicViscosity>) CENTI(
+			METRE).pow(2).divide(SECOND));
+
+	// //////////
+	// Others //
+	// //////////
+	/**
+	 * A unit used to measure the ionizing ability of radiation (standard name
+	 * <code>Roentgen</code>).
+	 */
+	public static final Unit<?> ROENTGEN = nonSI(COULOMB.divide(KILOGRAM)
+			.times(2.58e-4));
+
+	// ///////////////////
+	// Collection View //
+	// ///////////////////
+	/**
+	 * Returns a read only view over the units defined in this class.
+	 * 
+	 * @return the collection of NonSI units.
+	 */
+	public Set<Unit<?>> getUnits() {
+		return Collections.unmodifiableSet(UNITS);
+	}
+
+	/**
+	 * Adds a new unit to the collection.
+	 * 
+	 * @param unit the unit being added.
+	 * @return <code>unit</code>.
+	 */
+	private static <U extends Unit<?>> U nonSI(U unit) {
+		UNITS.add(unit);
+		return unit;
+	}
+
+	// ///////////////////
+	// NON-SI PREFIXES //
+	// ///////////////////
+
+	/**
+	 * Inner class holding binary prefixes.
+	 */
+	public static class BinaryPrefix {
+
+		private BinaryPrefix() {
+			// Utility class no visible constructor.
+		}
+
+		/**
+		 * Returns the specified unit multiplied by the factor
+		 * <code>2<sup>10</sup></code> (binary prefix).
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.times(1024)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> KIBI(Unit<Q> unit) {
+			return unit.times(1024);
+		}
+
+		/**
+		 * Returns the specified unit multiplied by the factor
+		 * <code>2<sup>20</sup></code> (binary prefix).
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.times(1048576)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> MEBI(Unit<Q> unit) {
+			return unit.times(1048576);
+		}
+
+		/**
+		 * Returns the specified unit multiplied by the factor
+		 * <code>2<sup>30</sup></code> (binary prefix).
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.times(1073741824)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> GIBI(Unit<Q> unit) {
+			return unit.times(1073741824);
+		}
+
+		/**
+		 * Returns the specified unit multiplied by the factor
+		 * <code>2<sup>40</sup></code> (binary prefix).
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.times(1099511627776L)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> TEBI(Unit<Q> unit) {
+			return unit.times(1099511627776L);
+		}
+
+		/**
+		 * Returns the specified unit multiplied by the factor
+		 * <code>2<sup>50</sup></code> (binary prefix).
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.times(1125899906842624L)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> PEBI(Unit<Q> unit) {
+			return unit.times(1125899906842624L);
+		}
+
+		/**
+		 * Returns the specified unit multiplied by the factor
+		 * <code>2<sup>60</sup></code> (binary prefix).
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.times(1152921504606846976L)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> EXBI(Unit<Q> unit) {
+			return unit.times(1152921504606846976L);
+		}
+
+	}
+
+	/**
+	 * Inner class holding prefixes used today in India, Pakistan, Bangladesh,
+	 * Nepal and Myanmar (Burma); based on grouping by two decimal places,
+	 * rather than the three decimal places common in most parts of the world.
+	 * [code] 
+	 *     import static javax.measure.unit.NonSI.IndianPrefix.*; // Static import.
+	 *     ... 
+	 *     Unit<Pressure> LAKH_PASCAL = LAKH(PASCAL); 
+	 *     Unit<Length> CRORE_METER = CRORE(METER);
+	 * [/code]
+	 * 
+	 * @author <a href="mailto:jsr275 at catmedia.us">Werner Keil</a>
+	 * @version 1.0
+	 * @see <a
+	 * href="http://en.wikipedia.org/wiki/Indian_numbering_system">Wikipedia:
+	 * Indian numbering system</a>
+	 */
+	public static class IndianPrefix {
+
+		private IndianPrefix() {
+			// Utility class no visible constructor.
+		}
+
+		/**
+		 * <p>
+		 * एक (Ek)
+		 * </p>
+		 * Returns the specified unit multiplied by the factor <code>1</code>
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.multiply(1)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> EK(Unit<Q> unit) {
+			return unit;
+		}
+
+		/**
+		 * <p>
+		 * दस (Das)
+		 * </p>
+		 * Returns the specified unit multiplied by the factor
+		 * <code>10<sup>1</sup></code>
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.multiply(10)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> DAS(Unit<Q> unit) {
+			return unit.transform(E1);
+		}
+
+		/**
+		 * <p>
+		 * सौ (Sau)
+		 * </p>
+		 * Returns the specified unit multiplied by the factor
+		 * <code>10<sup>2</sup></code>
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.multiply(100)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> SAU(Unit<Q> unit) {
+			return unit.transform(E2);
+		}
+
+		/**
+		 * <p>
+		 * सहस्र (Sahasr)
+		 * </p>
+		 * Returns the specified unit multiplied by the factor
+		 * <code>10<sup>3</sup></code>
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.multiply(1e3)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> SAHASR(Unit<Q> unit) {
+			return unit.transform(E3);
+		}
+
+		/**
+		 * <p>
+		 * हजार (Hazaar)
+		 * </p>
+		 * Equivalent to {@link #SAHASR}.
+		 */
+		public static <Q extends Quantity> Unit<Q> HAZAAR(Unit<Q> unit) {
+			return SAHASR(unit);
+		}
+
+		/**
+		 * <p>
+		 * लाख (Lakh)
+		 * </p>
+		 * Returns the specified unit multiplied by the factor
+		 * <code>10<sup>5</sup></code>
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.multiply(1e5)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> LAKH(Unit<Q> unit) {
+			return unit.transform(E5);
+		}
+
+		static final RationalConverter E5 = new RationalConverter(
+				BigInteger.TEN.pow(5), BigInteger.ONE);
+
+		/**
+		 * <p>
+		 * करोड़ (Crore)
+		 * </p>
+		 * Returns the specified unit multiplied by the factor
+		 * <code>10<sup>7</sup></code>
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.multiply(1e7)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> CRORE(Unit<Q> unit) {
+			return unit.transform(E7);
+		}
+
+		static final RationalConverter E7 = new RationalConverter(
+				BigInteger.TEN.pow(7), BigInteger.ONE);
+
+		/**
+		 * <p>
+		 * अरब (Arawb)
+		 * </p>
+		 * Returns the specified unit multiplied by the factor
+		 * <code>10<sup>9</sup></code>
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.multiply(1e9)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> ARAWB(Unit<Q> unit) {
+			return unit.transform(E9);
+		}
+
+		/**
+		 * <p>
+		 * खरब (Kharawb)
+		 * </p>
+		 * Returns the specified unit multiplied by the factor
+		 * <code>10<sup>11</sup></code>
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.multiply(1e11)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> KHARAWB(Unit<Q> unit) {
+			return unit.transform(E11);
+		}
+
+		static final RationalConverter E11 = new RationalConverter(
+				BigInteger.TEN.pow(11), BigInteger.ONE);
+
+		/**
+		 * <p>
+		 * नील (Neel)
+		 * </p>
+		 * Returns the specified unit multiplied by the factor
+		 * <code>10<sup>13</sup></code>
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.multiply(1e13)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> NEEL(Unit<Q> unit) {
+			return unit.transform(E13);
+		}
+
+		static final RationalConverter E13 = new RationalConverter(
+				BigInteger.TEN.pow(13), BigInteger.ONE);
+
+		/**
+		 * <p>
+		 * पद्म (Padma)
+		 * </p>
+		 * Returns the specified unit multiplied by the factor
+		 * <code>10<sup>15</sup></code>
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.multiply(1e15)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> PADMA(Unit<Q> unit) {
+			return unit.transform(E15);
+		}
+
+		/**
+		 * <p>
+		 * शंख (Shankh)
+		 * </p>
+		 * Returns the specified unit multiplied by the factor
+		 * <code>10<sup>17</sup></code>
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.multiply(1e17)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> SHANKH(Unit<Q> unit) {
+			return unit.transform(E17);
+		}
+
+		static final RationalConverter E17 = new RationalConverter(
+				BigInteger.TEN.pow(17), BigInteger.ONE);
+
+		/**
+		 * <p>
+		 * महाशंख (Mahashankh)
+		 * </p>
+		 * Returns the specified unit multiplied by the factor
+		 * <code>10<sup>19</sup></code>
+		 * 
+		 * @param unit any unit.
+		 * @return <code>unit.multiply(1e19)</code>.
+		 */
+		public static <Q extends Quantity> Unit<Q> MAHASHANKH(Unit<Q> unit) {
+			return unit.transform(E19);
+		}
+
+		static final RationalConverter E19 = new RationalConverter(
+				BigInteger.TEN.pow(19), BigInteger.ONE);
+
+	}
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/unit/ProductUnit.java b/src/main/java/javax/measure/unit/ProductUnit.java
new file mode 100644
index 0000000..8d87108
--- /dev/null
+++ b/src/main/java/javax/measure/unit/ProductUnit.java
@@ -0,0 +1,478 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import java.io.Serializable;
+
+import javax.measure.converter.ConversionException;
+import javax.measure.converter.LinearConverter;
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Quantity;
+
+/**
+ * <p>  This class represents units formed by the product of rational powers of
+ *      existing units.</p>
+ * 
+ * <p> This class maintains the canonical form of this product (simplest form 
+ *     after factorization). For example: <code>METRE.pow(2).divide(METRE)</code>
+ *     returns <code>METRE</code>.</p>
+ * 
+ * @author <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ * @see Unit#times(Unit)
+ * @see Unit#divide(Unit)
+ * @see Unit#pow(int)
+ * @see Unit#root(int)
+ */
+public final class ProductUnit<Q extends Quantity> extends DerivedUnit<Q> {
+
+    /**
+     * Holds the units composing this product unit.
+     */
+    private final Element[] _elements;
+
+    /**
+     * Holds the hashcode (optimization).
+     */
+    private int _hashCode;
+
+    /**
+     * Default constructor (used solely to create <code>ONE</code> instance).
+     */
+    ProductUnit() {
+        _elements = new Element[0];
+    }
+
+    /**
+     * Copy constructor (allows for parameterization of product units).
+     * 
+     * @param productUnit the product unit source.
+     * @throws ClassCastException if the specified unit is not a product unit.
+     */
+    public ProductUnit(Unit<?> productUnit) {
+        _elements = ((ProductUnit<?>) productUnit)._elements;
+    }
+
+    /**
+     * Product unit constructor.
+     * 
+     * @param elements the product elements.
+     */
+    private ProductUnit(Element[] elements) {
+        _elements = elements;
+    }
+
+    /**
+     * Returns the unit defined from the product of the specified elements.
+     * 
+     * @param leftElems left multiplicand elements.
+     * @param rightElems right multiplicand elements.
+     * @return the corresponding unit.
+     */
+    @SuppressWarnings("unchecked")
+    private static Unit<? extends Quantity> getInstance(Element[] leftElems,
+            Element[] rightElems) {
+
+        // Merges left elements with right elements.
+        Element[] result = new Element[leftElems.length + rightElems.length];
+        int resultIndex = 0;
+        for (int i = 0; i < leftElems.length; i++) {
+            Unit unit = leftElems[i]._unit;
+            int p1 = leftElems[i]._pow;
+            int r1 = leftElems[i]._root;
+            int p2 = 0;
+            int r2 = 1;
+            for (int j = 0; j < rightElems.length; j++) {
+                if (unit.equals(rightElems[j]._unit)) {
+                    p2 = rightElems[j]._pow;
+                    r2 = rightElems[j]._root;
+                    break; // No duplicate.
+                }
+            }
+            int pow = (p1 * r2) + (p2 * r1);
+            int root = r1 * r2;
+            if (pow != 0) {
+                int gcd = gcd(Math.abs(pow), root);
+                result[resultIndex++] = new Element(unit, pow / gcd, root / gcd);
+            }
+        }
+
+        // Appends remaining right elements not merged.
+        for (int i = 0; i < rightElems.length; i++) {
+            Unit unit = rightElems[i]._unit;
+            boolean hasBeenMerged = false;
+            for (int j = 0; j < leftElems.length; j++) {
+                if (unit.equals(leftElems[j]._unit)) {
+                    hasBeenMerged = true;
+                    break;
+                }
+            }
+            if (!hasBeenMerged)
+                result[resultIndex++] = rightElems[i];
+        }
+
+        // Returns or creates instance.
+        if (resultIndex == 0)
+            return ONE;
+        else if ((resultIndex == 1) && (result[0]._pow == result[0]._root))
+            return result[0]._unit;
+        else {
+            Element[] elems = new Element[resultIndex];
+            for (int i = 0; i < resultIndex; i++) {
+                elems[i] = result[i];
+            }
+            return new ProductUnit<Quantity>(elems);
+        }
+    }
+
+    /**
+     * Returns the product of the specified units.
+     * 
+     * @param left the left unit operand.
+     * @param right the right unit operand.
+     * @return <code>left * right</code>
+     */
+    static Unit<? extends Quantity> getProductInstance(Unit<?> left,
+            Unit<?> right) {
+        Element[] leftElems;
+        if (left instanceof ProductUnit)
+            leftElems = ((ProductUnit<?>) left)._elements;
+        else
+            leftElems = new Element[] { new Element(left, 1, 1) };
+        Element[] rightElems;
+        if (right instanceof ProductUnit)
+            rightElems = ((ProductUnit<?>) right)._elements;
+        else
+            rightElems = new Element[] { new Element(right, 1, 1) };
+        return getInstance(leftElems, rightElems);
+    }
+
+    /**
+     * Returns the quotient of the specified units.
+     * 
+     * @param left the dividend unit operand.
+     * @param right the divisor unit operand.
+     * @return <code>dividend / divisor</code>
+     */
+    static Unit<? extends Quantity> getQuotientInstance(Unit<?> left,
+            Unit<?> right) {
+        Element[] leftElems;
+        if (left instanceof ProductUnit)
+            leftElems = ((ProductUnit<?>) left)._elements;
+        else
+            leftElems = new Element[] { new Element(left, 1, 1) };
+        Element[] rightElems;
+        if (right instanceof ProductUnit) {
+            Element[] elems = ((ProductUnit<?>) right)._elements;
+            rightElems = new Element[elems.length];
+            for (int i = 0; i < elems.length; i++) {
+                rightElems[i] = new Element(elems[i]._unit, -elems[i]._pow,
+                        elems[i]._root);
+            }
+        } else
+            rightElems = new Element[] { new Element(right, -1, 1) };
+        return getInstance(leftElems, rightElems);
+    }
+
+    /**
+     * Returns the product unit corresponding to the specified root of the
+     * specified unit.
+     * 
+     * @param unit the unit.
+     * @param n the root's order (n > 0).
+     * @return <code>unit^(1/nn)</code>
+     * @throws ArithmeticException if <code>n == 0</code>.
+     */
+    static Unit<? extends Quantity> getRootInstance(Unit<?> unit, int n) {
+        Element[] unitElems;
+        if (unit instanceof ProductUnit) {
+            Element[] elems = ((ProductUnit<?>) unit)._elements;
+            unitElems = new Element[elems.length];
+            for (int i = 0; i < elems.length; i++) {
+                int gcd = gcd(Math.abs(elems[i]._pow), elems[i]._root * n);
+                unitElems[i] = new Element(elems[i]._unit, elems[i]._pow / gcd,
+                        elems[i]._root * n / gcd);
+            }
+        } else
+            unitElems = new Element[] { new Element(unit, 1, n) };
+        return getInstance(unitElems, new Element[0]);
+    }
+
+    /**
+     * Returns the product unit corresponding to this unit raised to the
+     * specified exponent.
+     * 
+     * @param unit the unit.
+     * @param nn the exponent (nn > 0).
+     * @return <code>unit^n</code>
+     */
+    static Unit<? extends Quantity> getPowInstance(Unit<?> unit, int n) {
+        Element[] unitElems;
+        if (unit instanceof ProductUnit) {
+            Element[] elems = ((ProductUnit<?>) unit)._elements;
+            unitElems = new Element[elems.length];
+            for (int i = 0; i < elems.length; i++) {
+                int gcd = gcd(Math.abs(elems[i]._pow * n), elems[i]._root);
+                unitElems[i] = new Element(elems[i]._unit, elems[i]._pow * n
+                        / gcd, elems[i]._root / gcd);
+            }
+        } else
+            unitElems = new Element[] { new Element(unit, n, 1) };
+        return getInstance(unitElems, new Element[0]);
+    }
+
+    /**
+     * Returns the number of units in this product.
+     * 
+     * @return the number of units being multiplied.
+     */
+    public int getUnitCount() {
+        return _elements.length;
+    }
+
+    /**
+     * Returns the unit at the specified position.
+     * 
+     * @param index the index of the unit to return.
+     * @return the unit at the specified position.
+     * @throws IndexOutOfBoundsException if index is out of range
+     *         <code>(index < 0 || index >= size())</code>.
+     */
+    public Unit<? extends Quantity> getUnit(int index) {
+        return _elements[index].getUnit();
+    }
+
+    /**
+     * Returns the power exponent of the unit at the specified position.
+     * 
+     * @param index the index of the unit to return.
+     * @return the unit power exponent at the specified position.
+     * @throws IndexOutOfBoundsException if index is out of range
+     *         <code>(index < 0 || index >= size())</code>.
+     */
+    public int getUnitPow(int index) {
+        return _elements[index].getPow();
+    }
+
+    /**
+     * Returns the root exponent of the unit at the specified position.
+     * 
+     * @param index the index of the unit to return.
+     * @return the unit root exponent at the specified position.
+     * @throws IndexOutOfBoundsException if index is out of range
+     *         <code>(index < 0 || index >= size())</code>.
+     */
+    public int getUnitRoot(int index) {
+        return _elements[index].getRoot();
+    }
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that)
+            return true;
+        if (!(that instanceof ProductUnit))
+            return false;
+        // Two products are equals if they have the same elements
+        // regardless of the elements' order.
+        Element[] elems = ((ProductUnit<?>) that)._elements;
+        if (_elements.length != elems.length)
+            return false;
+        for (int i = 0; i < _elements.length; i++) {
+            boolean unitFound = false;
+            Element e = _elements[i];
+            for (int j = 0; j < elems.length; j++) {
+                if (e._unit.equals(elems[j]._unit))
+                    if ((e._pow != elems[j]._pow)
+                            || (e._root != elems[j]._root))
+                        return false;
+                    else {
+                        unitFound = true;
+                        break;
+                    }
+            }
+            if (!unitFound)
+                return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        if (_hashCode != 0)
+            return _hashCode;
+        int code = 0;
+        for (int i = 0; i < _elements.length; i++) {
+            code += _elements[i]._unit.hashCode()
+                    * (_elements[i]._pow * 3 - _elements[i]._root * 2);
+        }
+        _hashCode = code;
+        return code;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Unit<Q> toSI() {
+        if (hasOnlyStandardUnit())
+            return this;
+        Unit<?> systemUnit = ONE;
+        for (int i = 0; i < _elements.length; i++) {
+            Unit<?> unit = _elements[i]._unit.toSI();
+            unit = unit.pow(_elements[i]._pow);
+            unit = unit.root(_elements[i]._root);
+            systemUnit = systemUnit.times(unit);
+        }
+        return (Unit<Q>) systemUnit;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public final UnitConverter getConverterTo(Unit<Q> unit) {
+        if (this.equals(unit))
+            return UnitConverter.IDENTITY;
+        if (!unit.equals(this.toSI()))
+            return super.getConverterTo(unit);
+        UnitConverter converter = UnitConverter.IDENTITY;
+        for (int i = 0; i < _elements.length; i++) {
+            Element e = _elements[i];
+            UnitConverter cvtr = e._unit.getConverterTo((Unit)e._unit.toSI());
+            if (!(cvtr instanceof LinearConverter))
+                throw new ConversionException(e._unit
+                        + " is non-linear, cannot convert");
+            if (e._root != 1)
+                throw new ConversionException(e._unit
+                        + " holds a base unit with fractional exponent");
+            int pow = e._pow;
+            if (pow < 0) { // Negative power.
+                pow = -pow;
+                cvtr = cvtr.inverse();
+            }
+            for (int j = 0; j < pow; j++) {
+                converter = converter.concatenate(cvtr);
+            }
+        }
+        return converter;
+    }
+
+    /**
+     * Indicates if this product unit is a standard unit.
+     * 
+     * @return <code>true</code> if all elements are standard units;
+     *         <code>false</code> otherwise.
+     */
+    private boolean hasOnlyStandardUnit() {
+        for (int i = 0; i < _elements.length; i++) {
+            Unit<?> u = _elements[i]._unit;
+            if (!u.isSI())
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns the greatest common divisor (Euclid's algorithm).
+     * 
+     * @param m the first number.
+     * @param nn the second number.
+     * @return the greatest common divisor.
+     */
+    private static int gcd(int m, int n) {
+        if (n == 0)
+            return m;
+        else
+            return gcd(n, m % n);
+    }
+
+    /**
+     * Inner product element represents a rational power of a single unit.
+     */
+    private final static class Element implements Serializable {
+
+        /**
+         * Holds the single unit.
+         */
+        private final Unit<?> _unit;
+
+        /**
+         * Holds the power exponent.
+         */
+        private final int _pow;
+
+        /**
+         * Holds the root exponent.
+         */
+        private final int _root;
+
+        /**
+         * Structural constructor.
+         * 
+         * @param unit the unit.
+         * @param pow the power exponent.
+         * @param root the root exponent.
+         */
+        private Element(Unit<?> unit, int pow, int root) {
+            _unit = unit;
+            _pow = pow;
+            _root = root;
+        }
+
+        /**
+         * Returns this element's unit.
+         * 
+         * @return the single unit.
+         */
+        public Unit<?> getUnit() {
+            return _unit;
+        }
+
+        /**
+         * Returns the power exponent. The power exponent can be negative but is
+         * always different from zero.
+         * 
+         * @return the power exponent of the single unit.
+         */
+        public int getPow() {
+            return _pow;
+        }
+
+        /**
+         * Returns the root exponent. The root exponent is always greater than
+         * zero.
+         * 
+         * @return the root exponent of the single unit.
+         */
+        public int getRoot() {
+            return _root;
+        }
+
+        private static final long serialVersionUID = 1L;
+
+    }
+
+    private static final long serialVersionUID = 1L;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/unit/SI.java b/src/main/java/javax/measure/unit/SI.java
new file mode 100644
index 0000000..6fffc53
--- /dev/null
+++ b/src/main/java/javax/measure/unit/SI.java
@@ -0,0 +1,744 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.measure.converter.RationalConverter;
+import javax.measure.quantity.*;
+
+/**
+ * <p> This class contains SI (Système International d'Unités) base units,
+ *     and derived units.</p>
+ *     
+ * <p> It also defines the 20 SI prefixes used to form decimal multiples and
+ *     submultiples of SI units. For example:[code]
+ *     import static org.jscience.physics.units.SI.*; // Static import.
+ *     ...
+ *     Unit<Pressure> HECTOPASCAL = HECTO(PASCAL);
+ *     Unit<Length> KILOMETRE = KILO(METRE);
+ *     [/code]</p>
+ *     
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ * @see <a href="http://en.wikipedia.org/wiki/International_System_of_Units">Wikipedia: International System of Units</a>
+ */
+public final class SI extends SystemOfUnits {
+
+    /**
+     * Holds collection of SI units.
+     */
+    private static HashSet<Unit<?>> UNITS = new HashSet<Unit<?>>();
+
+    /**
+     * Default constructor (prevents this class from being instantiated).
+     */
+    private SI() {
+    }
+
+    /**
+     * Returns the unique instance of this class.
+     *
+     * @return the SI instance.
+     */
+    public static SI getInstance() {
+        return INSTANCE;
+    }
+    private static final SI INSTANCE = new SI();
+    ////////////////
+    // BASE UNITS //
+    ////////////////
+
+    /**
+     * The base unit for electric current quantities (<code>A</code>).
+     * The Ampere is that constant current which, if maintained in two straight
+     * parallel conductors of infinite length, of negligible circular
+     * cross-section, and placed 1 meter apart in vacuum, would produce between
+     * these conductors a force equal to 2 × 10-7 newton per meter of length.
+     * It is named after the French physicist Andre Ampere (1775-1836).
+     */
+    public static final BaseUnit<ElectricCurrent> AMPERE = si(new BaseUnit<ElectricCurrent>(
+            "A"));
+
+    /**
+     * The base unit for luminous intensity quantities (<code>cd</code>).
+     * The candela is the luminous intensity, in a given direction,
+     * of a source that emits monochromatic radiation of frequency
+     * 540 × 1012 hertz and that has a radiant intensity in that
+     * direction of 1/683 watt per steradian
+     * @see <a href="http://en.wikipedia.org/wiki/Candela"> 
+     *      Wikipedia: Candela</a>
+     */
+    public static final BaseUnit<LuminousIntensity> CANDELA = si(new BaseUnit<LuminousIntensity>(
+            "cd"));
+
+    /**
+     * The base unit for thermodynamic temperature quantities (<code>K</code>).
+     * The kelvin is the 1/273.16th of the thermodynamic temperature of the
+     * triple point of water. It is named after the Scottish mathematician and
+     * physicist William Thomson 1st Lord Kelvin (1824-1907)
+     */
+    public static final BaseUnit<Temperature> KELVIN = si(new BaseUnit<Temperature>(
+            "K"));
+
+    /**
+     * The base unit for mass quantities (<code>kg</code>).
+     * It is the only SI unit with a prefix as part of its name and symbol.
+     * The kilogram is equal to the mass of an international prototype in the
+     * form of a platinum-iridium cylinder kept at Sevres in France.
+     * @see   #GRAM
+     */
+    public static final BaseUnit<Mass> KILOGRAM = si(new BaseUnit<Mass>("kg"));
+
+    /**
+     * The base unit for length quantities (<code>m</code>).
+     * One metre was redefined in 1983 as the distance traveled by light in
+     * a vacuum in 1/299,792,458 of a second.
+     */
+    public static final BaseUnit<Length> METRE = si(new BaseUnit<Length>("m"));
+
+    /**
+     * Equivalent to {@link #METRE} (American spelling).
+     */
+    public static final Unit<Length> METER = METRE;
+
+    /**
+     * The base unit for amount of substance quantities (<code>mol</code>).
+     * The mole is the amount of substance of a system which contains as many
+     * elementary entities as there are atoms in 0.012 kilogram of carbon 12.
+     */
+    public static final BaseUnit<AmountOfSubstance> MOLE = si(new BaseUnit<AmountOfSubstance>(
+            "mol"));
+
+    /**
+     * The base unit for duration quantities (<code>s</code>).
+     * It is defined as the duration of 9,192,631,770 cycles of radiation
+     * corresponding to the transition between two hyperfine levels of
+     * the ground state of cesium (1967 Standard).
+     */
+    public static final BaseUnit<Duration> SECOND = si(new BaseUnit<Duration>(
+            "s"));
+    ////////////////////////////////
+    // SI DERIVED ALTERNATE UNITS //
+    ////////////////////////////////
+
+    /**
+     * The derived unit for mass quantities (<code>g</code>).
+     * The base unit for mass quantity is {@link #KILOGRAM}.
+     */
+    public static final Unit<Mass> GRAM = KILOGRAM.divide(1000);
+
+    /**
+     * The unit for plane angle quantities (<code>rad</code>).
+     * One radian is the angle between two radii of a circle such that the
+     * length of the arc between them is equal to the radius.
+     */
+    public static final AlternateUnit<Angle> RADIAN = si(new AlternateUnit<Angle>(
+            "rad", Unit.ONE));
+
+    /**
+     * The unit for solid angle quantities (<code>sr</code>).
+     * One steradian is the solid angle subtended at the center of a sphere by
+     * an area on the surface of the sphere that is equal to the radius squared.
+     * The total solid angle of a sphere is 4*Pi steradians.
+     */
+    public static final AlternateUnit<SolidAngle> STERADIAN = si(new AlternateUnit<SolidAngle>(
+            "sr", Unit.ONE));
+
+    /**
+     * The unit for binary information (<code>bit</code>).
+     */
+    public static final AlternateUnit<DataAmount> BIT = si(new AlternateUnit<DataAmount>(
+            "bit", Unit.ONE));
+
+    /**
+     * The derived unit for frequency (<code>Hz</code>).
+     * A unit of frequency equal to one cycle per second.
+     * After Heinrich Rudolf Hertz (1857-1894), German physicist who was the
+     * first to produce radio waves artificially.
+     */
+    public static final AlternateUnit<Frequency> HERTZ = si(new AlternateUnit<Frequency>(
+            "Hz", Unit.ONE.divide(SECOND)));
+
+    /**
+     * The derived unit for force (<code>N</code>).
+     * One newton is the force required to give a mass of 1 kilogram an Force
+     * of 1 metre per second per second. It is named after the English
+     * mathematician and physicist Sir Isaac Newton (1642-1727).
+     */
+    public static final AlternateUnit<Force> NEWTON = si(new AlternateUnit<Force>(
+            "N", METRE.times(KILOGRAM).divide(SECOND.pow(2))));
+
+    /**
+     * The derived unit for pressure, stress (<code>Pa</code>).
+     * One pascal is equal to one newton per square meter. It is named after
+     * the French philosopher and mathematician Blaise Pascal (1623-1662).
+     */
+    public static final AlternateUnit<Pressure> PASCAL = si(new AlternateUnit<Pressure>(
+            "Pa", NEWTON.divide(METRE.pow(2))));
+
+    /**
+     * The derived unit for energy, work, quantity of heat (<code>J</code>).
+     * One joule is the amount of work done when an applied force of 1 newton
+     * moves through a distance of 1 metre in the direction of the force.
+     * It is named after the English physicist James Prescott Joule (1818-1889).
+     */
+    public static final AlternateUnit<Energy> JOULE = si(new AlternateUnit<Energy>(
+            "J", NEWTON.times(METRE)));
+
+    /**
+     * The derived unit for power, radiant, flux (<code>W</code>).
+     * One watt is equal to one joule per second. It is named after the British
+     * scientist James Watt (1736-1819).
+     */
+    public static final AlternateUnit<Power> WATT = si(new AlternateUnit<Power>(
+            "W", JOULE.divide(SECOND)));
+
+    /**
+     * The derived unit for electric charge, quantity of electricity
+     * (<code>C</code>).
+     * One Coulomb is equal to the quantity of charge transferred in one second
+     * by a steady current of one ampere. It is named after the French physicist
+     * Charles Augustin de Coulomb (1736-1806).
+     */
+    public static final AlternateUnit<ElectricCharge> COULOMB = si(new AlternateUnit<ElectricCharge>(
+            "C", SECOND.times(AMPERE)));
+
+    /**
+     * The derived unit for electric potential difference, electromotive force
+     * (<code>V</code>).
+     * One Volt is equal to the difference of electric potential between two
+     * points on a conducting wire carrying a constant current of one ampere
+     * when the power dissipated between the points is one watt. It is named
+     * after the Italian physicist Count Alessandro Volta (1745-1827).
+     */
+    public static final AlternateUnit<ElectricPotential> VOLT = si(new AlternateUnit<ElectricPotential>(
+            "V", WATT.divide(AMPERE)));
+
+    /**
+     * The derived unit for capacitance (<code>F</code>).
+     * One Farad is equal to the capacitance of a capacitor having an equal
+     * and opposite charge of 1 coulomb on each plate and a potential difference
+     * of 1 volt between the plates. It is named after the British physicist
+     * and chemist Michael Faraday (1791-1867).
+     */
+    public static final AlternateUnit<ElectricCapacitance> FARAD = si(new AlternateUnit<ElectricCapacitance>(
+            "F", COULOMB.divide(VOLT)));
+
+    /**
+     * The derived unit for electric resistance (<code>Ω</code> or 
+     * <code>Ohm</code>).
+     * One Ohm is equal to the resistance of a conductor in which a current of
+     * one ampere is produced by a potential of one volt across its terminals.
+     * It is named after the German physicist Georg Simon Ohm (1789-1854).
+     */
+    public static final AlternateUnit<ElectricResistance> OHM = si(new AlternateUnit<ElectricResistance>(
+            "Ω", VOLT.divide(AMPERE)));
+
+    /**
+     * The derived unit for electric conductance (<code>S</code>).
+     * One Siemens is equal to one ampere per volt. It is named after
+     * the German engineer Ernst Werner von Siemens (1816-1892).
+     */
+    public static final AlternateUnit<ElectricConductance> SIEMENS = si(new AlternateUnit<ElectricConductance>(
+            "S", AMPERE.divide(VOLT)));
+
+    /**
+     * The derived unit for magnetic flux (<code>Wb</code>).
+     * One Weber is equal to the magnetic flux that in linking a circuit of one
+     * turn produces in it an electromotive force of one volt as it is uniformly
+     * reduced to zero within one second. It is named after the German physicist
+     * Wilhelm Eduard Weber (1804-1891).
+     */
+    public static final AlternateUnit<MagneticFlux> WEBER = si(new AlternateUnit<MagneticFlux>(
+            "Wb", VOLT.times(SECOND)));
+
+    /**
+     * The derived unit for magnetic flux density (<code>T</code>).
+     * One Tesla is equal equal to one weber per square metre. It is named
+     * after the Serbian-born American electrical engineer and physicist
+     * Nikola Tesla (1856-1943).
+     */
+    public static final AlternateUnit<MagneticFluxDensity> TESLA = si(new AlternateUnit<MagneticFluxDensity>(
+            "T", WEBER.divide(METRE.pow(2))));
+
+    /**
+     * The derived unit for inductance (<code>H</code>).
+     * One Henry is equal to the inductance for which an induced electromotive
+     * force of one volt is produced when the current is varied at the rate of
+     * one ampere per second. It is named after the American physicist
+     * Joseph Henry (1791-1878).
+     */
+    public static final AlternateUnit<ElectricInductance> HENRY = si(new AlternateUnit<ElectricInductance>(
+            "H", WEBER.divide(AMPERE)));
+
+    /**
+     * The derived unit for Celsius temperature (<code>℃</code>).
+     * This is a unit of temperature such as the freezing point of water
+     * (at one atmosphere of pressure) is 0 ℃, while the boiling point is
+     * 100 ℃.
+     */
+    public static final Unit<Temperature> CELSIUS = si(KELVIN.plus(273.15));
+
+    /**
+     * The derived unit for luminous flux (<code>lm</code>).
+     * One Lumen is equal to the amount of light given out through a solid angle
+     * by a source of one candela intensity radiating equally in all directions.
+     */
+    public static final AlternateUnit<LuminousFlux> LUMEN = si(new AlternateUnit<LuminousFlux>(
+            "lm", CANDELA.times(STERADIAN)));
+
+    /**
+     * The derived unit for illuminance (<code>lx</code>).
+     * One Lux is equal to one lumen per square metre.
+     */
+    public static final AlternateUnit<Illuminance> LUX = si(new AlternateUnit<Illuminance>(
+            "lx", LUMEN.divide(METRE.pow(2))));
+
+    /**
+     * The derived unit for activity of a radionuclide (<code>Bq</code>).
+     * One becquerel is the radiation caused by one disintegration per second.
+     * It is named after the French physicist, Antoine-Henri Becquerel
+     * (1852-1908).
+     */
+    public static final AlternateUnit<RadioactiveActivity> BECQUEREL = si(new AlternateUnit<RadioactiveActivity>(
+            "Bq", Unit.ONE.divide(SECOND)));
+
+    /**
+     * The derived unit for absorbed dose, specific energy (imparted), kerma
+     * (<code>Gy</code>).
+     * One gray is equal to the dose of one joule of energy absorbed per one
+     * kilogram of matter. It is named after the British physician
+     * L. H. Gray (1905-1965).
+     */
+    public static final AlternateUnit<RadiationDoseAbsorbed> GRAY = si(new AlternateUnit<RadiationDoseAbsorbed>(
+            "Gy", JOULE.divide(KILOGRAM)));
+
+    /**
+     * The derived unit for dose equivalent (<code>Sv</code>).
+     * One Sievert is equal  is equal to the actual dose, in grays, multiplied
+     * by a "quality factor" which is larger for more dangerous forms of
+     * radiation. It is named after the Swedish physicist Rolf Sievert
+     * (1898-1966).
+     */
+    public static final AlternateUnit<RadiationDoseEffective> SIEVERT = si(new AlternateUnit<RadiationDoseEffective>(
+            "Sv", JOULE.divide(KILOGRAM)));
+
+    /**
+     * The derived unit for catalytic activity (<code>kat</code>).
+     */
+    public static final AlternateUnit<CatalyticActivity> KATAL = si(new AlternateUnit<CatalyticActivity>(
+            "kat", MOLE.divide(SECOND)));
+    //////////////////////////////
+    // SI DERIVED PRODUCT UNITS //
+    //////////////////////////////
+
+    /**
+     * The metric unit for velocity quantities (<code>m/s</code>).
+     */
+    public static final Unit<Velocity> METRES_PER_SECOND = si(new ProductUnit<Velocity>(
+            METRE.divide(SECOND)));
+
+    /**
+     * Equivalent to {@link #METRES_PER_SECOND}.
+     */
+    public static final Unit<Velocity> METERS_PER_SECOND = METRES_PER_SECOND;
+
+    /**
+     * The metric unit for acceleration quantities (<code>m/s²</code>).
+     */
+    public static final Unit<Acceleration> METRES_PER_SQUARE_SECOND = si(new ProductUnit<Acceleration>(
+            METRES_PER_SECOND.divide(SECOND)));
+
+    /**
+     * Equivalent to {@link #METRES_PER_SQUARE_SECOND}.
+     */
+    public static final Unit<Acceleration> METERS_PER_SQUARE_SECOND = METRES_PER_SQUARE_SECOND;
+
+    /**
+     * The metric unit for area quantities (<code>m²</code>).
+     */
+    public static final Unit<Area> SQUARE_METRE = si(new ProductUnit<Area>(
+            METRE.times(METRE)));
+
+    /**
+     * Equivalent to {@link #SQUARE_METRE}.
+     */
+    public static final Unit<Area> SQUARE_METER = SQUARE_METRE;
+
+    /**
+     * The metric unit for volume quantities (<code>m³</code>).
+     */
+    public static final Unit<Volume> CUBIC_METRE = si(new ProductUnit<Volume>(
+            SQUARE_METRE.times(METRE)));
+
+    /**
+     * Equivalent to {@link #CUBIC_METRE}.
+     */
+    public static final Unit<Volume> CUBIC_METER = CUBIC_METRE;
+
+    /**
+     * Equivalent to <code>KILO(METRE)</code>.
+     */
+    public static final Unit<Length> KILOMETRE = METER.times(1000);
+
+    /**
+     * Equivalent to {@link #KILOMETRE}.
+     */
+    public static final Unit<Length> KILOMETER = KILOMETRE;
+
+    /**
+     * Equivalent to <code>CENTI(METRE)</code>.
+     */
+    public static final Unit<Length> CENTIMETRE = METRE.divide(100);
+
+    /**
+     * Equivalent to {@link #CENTIMETRE}.
+     */
+    public static final Unit<Length> CENTIMETER = CENTIMETRE;
+
+    /**
+     * Equivalent to <code>MILLI(METRE)</code>.
+     */
+    public static final Unit<Length> MILLIMETRE = METRE.divide(1000);
+
+    /**
+     * Equivalent to {@link #MILLIMETRE}.
+     */
+    public static final Unit<Length> MILLIMETER = MILLIMETRE;
+
+    /////////////////
+    // SI PREFIXES //
+    /////////////////
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>24</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e24)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> YOTTA(Unit<Q> unit) {
+        return unit.transform(E24);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>21</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e21)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> ZETTA(Unit<Q> unit) {
+        return unit.transform(E21);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>18</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e18)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> EXA(Unit<Q> unit) {
+        return unit.transform(E18);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>15</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e15)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> PETA(Unit<Q> unit) {
+        return unit.transform(E15);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>12</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e12)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> TERA(Unit<Q> unit) {
+        return unit.transform(E12);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>9</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e9)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> GIGA(Unit<Q> unit) {
+        return unit.transform(E9);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>6</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e6)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> MEGA(Unit<Q> unit) {
+        return unit.transform(E6);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>3</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e3)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> KILO(Unit<Q> unit) {
+        return unit.transform(E3);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>2</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e2)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> HECTO(Unit<Q> unit) {
+        return unit.transform(E2);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>1</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e1)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> DEKA(Unit<Q> unit) {
+        return unit.transform(E1);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>-1</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e-1)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> DECI(Unit<Q> unit) {
+        return unit.transform(Em1);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>-2</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e-2)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> CENTI(Unit<Q> unit) {
+        return unit.transform(Em2);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>-3</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e-3)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> MILLI(Unit<Q> unit) {
+        return unit.transform(Em3);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>-6</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e-6)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> MICRO(Unit<Q> unit) {
+        return unit.transform(Em6);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>-9</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e-9)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> NANO(Unit<Q> unit) {
+        return unit.transform(Em9);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>-12</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e-12)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> PICO(Unit<Q> unit) {
+        return unit.transform(Em12);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>-15</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e-15)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> FEMTO(Unit<Q> unit) {
+        return unit.transform(Em15);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>-18</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e-18)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> ATTO(Unit<Q> unit) {
+        return unit.transform(Em18);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>-21</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e-21)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> ZEPTO(Unit<Q> unit) {
+        return unit.transform(Em21);
+    }
+
+    /**
+     * Returns the specified unit multiplied by the factor
+     * <code>10<sup>-24</sup></code>
+     *
+     * @param  unit any unit.
+     * @return <code>unit.times(1e-24)</code>.
+     */
+    public static <Q extends Quantity> Unit<Q> YOCTO(Unit<Q> unit) {
+        return unit.transform(Em24);
+    }
+
+    /////////////////////
+    // Collection View //
+    /////////////////////
+    /**
+     * Returns a read only view over theunits defined in this class.
+     *
+     * @return the collection of SI units.
+     */
+    public Set<Unit<?>> getUnits() {
+        return Collections.unmodifiableSet(UNITS);
+    }
+
+    /**
+     * Adds a new unit to the collection.
+     *
+     * @param  unit the unit being added.
+     * @return <code>unit</code>.
+     */
+    private static <U extends Unit<?>> U si(U unit) {
+        UNITS.add(unit);
+        return unit;
+    }
+    // Holds prefix converters (optimization).
+    static final RationalConverter E24 = new RationalConverter(
+            BigInteger.TEN.pow(24), BigInteger.ONE);
+
+    static final RationalConverter E21 = new RationalConverter(
+            BigInteger.TEN.pow(21), BigInteger.ONE);
+
+    static final RationalConverter E18 = new RationalConverter(
+            BigInteger.TEN.pow(18), BigInteger.ONE);
+
+    static final RationalConverter E15 = new RationalConverter(
+            BigInteger.TEN.pow(15), BigInteger.ONE);
+
+    static final RationalConverter E12 = new RationalConverter(
+            BigInteger.TEN.pow(12), BigInteger.ONE);
+
+    static final RationalConverter E9 = new RationalConverter(
+            BigInteger.TEN.pow(9), BigInteger.ONE);
+
+    static final RationalConverter E6 = new RationalConverter(
+            BigInteger.TEN.pow(6), BigInteger.ONE);
+
+    static final RationalConverter E3 = new RationalConverter(
+            BigInteger.TEN.pow(3), BigInteger.ONE);
+
+    static final RationalConverter E2 = new RationalConverter(
+            BigInteger.TEN.pow(2), BigInteger.ONE);
+
+    static final RationalConverter E1 = new RationalConverter(
+            BigInteger.TEN.pow(1), BigInteger.ONE);
+
+    static final RationalConverter Em1 = new RationalConverter(
+            BigInteger.ONE, BigInteger.TEN.pow(1));
+
+    static final RationalConverter Em2 = new RationalConverter(
+            BigInteger.ONE, BigInteger.TEN.pow(2));
+
+    static final RationalConverter Em3 = new RationalConverter(
+            BigInteger.ONE, BigInteger.TEN.pow(3));
+
+    static final RationalConverter Em6 = new RationalConverter(
+            BigInteger.ONE, BigInteger.TEN.pow(6));
+
+    static final RationalConverter Em9 = new RationalConverter(
+            BigInteger.ONE, BigInteger.TEN.pow(9));
+
+    static final RationalConverter Em12 = new RationalConverter(
+            BigInteger.ONE, BigInteger.TEN.pow(12));
+
+    static final RationalConverter Em15 = new RationalConverter(
+            BigInteger.ONE, BigInteger.TEN.pow(15));
+
+    static final RationalConverter Em18 = new RationalConverter(
+            BigInteger.ONE, BigInteger.TEN.pow(18));
+
+    static final RationalConverter Em21 = new RationalConverter(
+            BigInteger.ONE, BigInteger.TEN.pow(21));
+
+    static final RationalConverter Em24 = new RationalConverter(
+            BigInteger.ONE, BigInteger.TEN.pow(24));
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/unit/SystemOfUnits.java b/src/main/java/javax/measure/unit/SystemOfUnits.java
new file mode 100644
index 0000000..665bc1b
--- /dev/null
+++ b/src/main/java/javax/measure/unit/SystemOfUnits.java
@@ -0,0 +1,50 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import java.util.Set;
+
+/**
+ * <p> This class represents a system of units, it groups units together 
+ *     for historical or cultural reasons. Nothing prevents a unit from 
+ *     belonging to several system of units at the same time
+ *     (for example an imperial system would have many of the units 
+ *     held by {@link NonSI}).</p>
+ *
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public abstract class SystemOfUnits {
+
+    /**
+     * Returns a read only view over the units defined in this system.
+     *
+     * @return the collection of units.
+     */
+    public abstract Set<Unit<?>> getUnits();
+}
diff --git a/src/main/java/javax/measure/unit/TransformedUnit.java b/src/main/java/javax/measure/unit/TransformedUnit.java
new file mode 100644
index 0000000..2bc0756
--- /dev/null
+++ b/src/main/java/javax/measure/unit/TransformedUnit.java
@@ -0,0 +1,127 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Quantity;
+
+/**
+ * <p> This class represents the units derived from other units using
+ *     {@link UnitConverter converters}.</p>
+ *     
+ * <p> Examples of transformed units:[code]
+ *         CELSIUS = KELVIN.add(273.15);
+ *         FOOT = METRE.times(3048).divide(10000);
+ *         MILLISECOND = MILLI(SECOND); 
+ *     [/code]</p>
+ *     
+ * <p> Transformed units have no label. But like any other units,
+ *     they may have labels attached to them (see {@link javax.measure.unit.format.SymbolMap
+ *     SymbolMap}</p>
+ *
+ * <p> Instances of this class are created through the {@link Unit#transform} method.</p>
+ *     
+ * @author  <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @version 1.0, April 15, 2009
+ */
+public final class TransformedUnit<Q extends Quantity> extends DerivedUnit<Q> {
+
+    /**
+     * Holds the parent unit (not a transformed unit).
+     */
+    private final Unit<Q> _parentUnit;
+
+    /**
+     * Holds the converter to the parent unit.
+     */
+    private final UnitConverter _toParentUnit;
+
+    /**
+     * Creates a transformed unit from the specified parent unit.
+     *
+     * @param parentUnit the untransformed unit from which this unit is 
+     *        derived.
+     * @param  toParentUnit the converter to the parent units.
+     * @throws IllegalArgumentException if <code>toParentUnit == 
+     *         {@link UnitConverter#IDENTITY UnitConverter.IDENTITY}</code>
+     */
+    TransformedUnit(Unit<Q> parentUnit, UnitConverter toParentUnit) {
+        if (toParentUnit == UnitConverter.IDENTITY)
+            throw new IllegalArgumentException("Identity not allowed");
+        _parentUnit = parentUnit;
+        _toParentUnit = toParentUnit;
+    }
+
+    /**
+     * Returns the parent unit for this unit. The parent unit is the 
+     * untransformed unit from which this unit is derived.
+     *
+     * @return the untransformed unit from which this unit is derived.
+     */
+    public Unit<Q> getParentUnit() {
+        return _parentUnit;
+    }
+
+    /**
+     * Returns the converter to the parent unit.
+     *
+     * @return the converter to the parent unit.
+     */
+    public UnitConverter toParentUnit() {
+        return _toParentUnit;
+    }
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that)
+            return true;
+        if (!(that instanceof TransformedUnit))
+            return false;
+        TransformedUnit<?> thatUnit = (TransformedUnit<?>) that;
+        return this._parentUnit.equals(thatUnit._parentUnit) &&
+                this._toParentUnit.equals(thatUnit._toParentUnit);
+    }
+
+    @Override
+    public int hashCode() {
+        return _parentUnit.hashCode() + _toParentUnit.hashCode();
+    }
+
+    @Override
+    public Unit<Q> toSI() {
+        return _parentUnit.toSI();
+    }
+
+    @Override
+    public final UnitConverter getConverterTo(Unit<Q> unit) {
+        return _parentUnit.getConverterTo(unit).concatenate(_toParentUnit);
+    }
+
+    private static final long serialVersionUID = 1L;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/unit/Unit.java b/src/main/java/javax/measure/unit/Unit.java
new file mode 100644
index 0000000..b5a818f
--- /dev/null
+++ b/src/main/java/javax/measure/unit/Unit.java
@@ -0,0 +1,571 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences Copyright
+ * (c) 2005-2009, JScience (http://jscience.org/) All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.text.ParsePosition;
+import java.util.HashMap;
+
+import javax.measure.converter.AddConverter;
+import javax.measure.converter.ConversionException;
+import javax.measure.converter.LinearConverter;
+import javax.measure.converter.MultiplyConverter;
+import javax.measure.converter.RationalConverter;
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Dimensionless;
+import javax.measure.quantity.Quantity;
+
+/**
+ * <p> This class represents a determinate {@link javax.measure.quantity.Quantity
+ * quantity} (as of length, time, heat, or value) adopted as a standard of
+ * measurement.</p>
+ * 
+ * <p> It is helpful to think of instances of this class as recording the history by
+ * which they are created. Thus, for example, the string "g/kg" (which is a
+ * dimensionless unit) would result from invoking the method toString() on a
+ * unit that was created by dividing a gram unit by a kilogram unit. Yet, "kg"
+ * divided by "kg" returns {@link #ONE} and not "kg/kg" due to automatic unit
+ * factorization.</p>
+ * 
+ * <p> This class supports the multiplication of offsets units. The result is
+ * usually a unit not convertible to its {@link #toSI standard unit}. Such units
+ * may appear in derivative quantities. For example °C/m is an unit of gradient,
+ * which is common in atmospheric and oceanographic research.</p>
+ * 
+ * <p> Units raised at rational powers are also supported. For example the cubic
+ * root of liter is a unit compatible with meter.</p>
+ * 
+ * <p> Units specializations can only be defined by sub-classing either
+ * {@link BaseUnit}, {@link DerivedUnit} or {@link AnnotatedUnit} (the unit
+ * constructor is package private).For example:[code] 
+ *     public LengthUnit extends AnnotatedUnit<Length> { 
+ *         public static LengthUnit METER = new LengthUnit(SI.METER, "myOwnUnitClass"); // Equivalent to SI.METER
+ *         LengthUnit(Unit<Length> realUnit, String annotation) { super(realUnit, annotation); } 
+ *     }[/code]</p>
+ * 
+ * <p> Instances of this class and sub-classes are immutable.</p>
+ * 
+ * @author <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @author <a href="mailto:steve at unidata.ucar.edu">Steve Emmerson</a>
+ * @author Martin Desruisseaux
+ * @version 1.0, April 15, 2009
+ * @see <a href="http://en.wikipedia.org/wiki/Units_of_measurement"> Wikipedia:
+ * Units of measurement</a>
+ */
+public abstract class Unit<Q extends Quantity> implements Serializable {
+
+	/**
+	 * Holds the dimensionless unit <code>ONE</code>.
+	 */
+	public static final Unit<Dimensionless> ONE = new ProductUnit<Dimensionless>();
+
+	/**
+	 * Holds the unique symbols collection (base unit or alternate units).
+	 */
+	static final HashMap<String, Unit<?>> SYMBOL_TO_UNIT = new HashMap<String, Unit<?>>();
+
+	/**
+	 * Default constructor. Package private visibility. Subclasses should derive
+	 * from either BaseUnit, DerivedUnit or AnnotatedUnit.
+	 */
+	Unit() {
+	}
+
+	// ////////////////////////////////////////////////////
+	// Contract methods (for sub-classes to implement). //
+	// ////////////////////////////////////////////////////
+	/**
+	 * Returns the standard unit from which this unit is derived. The SI unit
+	 * identifies the "type" of {@link javax.measure.quantity.Quantity quantity}
+	 * for which this unit is employed. For example:[code]
+	 *     boolean isAngularVelocity(Unit<?> u) {
+	 *         return u.toSI().equals(RADIAN.divide(SECOND));
+	 *     }
+	 *     assert(REVOLUTION.divide(MINUTE).isAngularVelocity());
+	 * [/code] 
+	 * <p><i> Note: Having the same SI unit is not sufficient to ensure that a
+	 * converter exists between the two units (e.g. °C/m and K/m).</i></p>
+	 * 
+	 * @return the system unit this unit is derived from.
+	 */
+	public abstract Unit<Q> toSI();
+
+	/**
+	 * Returns the hash code for this unit.
+	 * 
+	 * @return this unit hashcode value.
+	 */
+	@Override
+	public abstract int hashCode();
+
+	/**
+	 * Indicates if the specified unit can be considered equals to the one
+	 * specified.
+	 * 
+	 * @param that the object to compare to.
+	 * @return <code>true</code> if this unit is considered equal to that unit;
+	 * <code>false</code> otherwise.
+	 */
+	@Override
+	public abstract boolean equals(Object that);
+
+	/**
+	 * Indicates if this unit is a standard unit (base units and alternate units
+	 * are standard units). The standard unit identifies the "type" of
+	 * {@link javax.measure.quantity.Quantity quantity} for which the unit is
+	 * employed.
+	 * 
+	 * @return <code>this.toSI().equals(this)</code>
+	 */
+	public boolean isSI() {
+		return toSI().equals(this);
+	}
+
+	/**
+	 * Indicates if this unit is compatible with the unit specified. Units don't
+	 * need to be equals to be compatible. For example:[code]
+	 *     RADIAN.equals(ONE) == false 
+	 *     RADIAN.isCompatible(ONE) == true
+	 * [/code]
+	 * 
+	 * @param that the other unit.
+	 * @return <code>this.getDimension().equals(that.getDimension())</code>
+	 * @see #getDimension()
+	 */
+	public final boolean isCompatible(Unit<?> that) {
+		return (this == that) || this.toSI().equals(that.toSI())
+				|| this.getDimension().equals(that.getDimension());
+	}
+
+	/**
+	 * Casts this unit to a parameterized unit of specified nature or throw a
+	 * <code>ClassCastException</code> if the dimension of the specified
+	 * quantity and this unit's dimension do not match. For example:[code]
+	 *      Unit<Length> LIGHT_YEAR = NonSI.C.times(NonSI.YEAR).asType(Length.class);
+	 * [/code]
+	 * 
+	 * @param type the quantity class identifying the nature of the unit.
+	 * @return this unit parameterized with the specified type.
+	 * @throws ClassCastException if the dimension of this unit is different
+	 * from the specified quantity dimension.
+	 * @throws UnsupportedOperationException if the specified quantity class
+	 * does not have a public static field named "UNIT" holding the SI unit for
+	 * the quantity.
+	 */
+	@SuppressWarnings("unchecked")
+	public final <T extends Quantity> Unit<T> asType(Class<T> type)
+			throws ClassCastException {
+		Dimension thisDimension = this.getDimension();
+		Unit<T> quantityUnit = null;
+		try {
+			quantityUnit = (Unit<T>) type.getField("UNIT").get(null);
+		} catch (Exception e) {
+			throw new UnsupportedOperationException(
+					"The quantity class "
+							+ type
+							+ " does not have a public static field UNIT holding the SI unit "
+							+ " for the quantity.");
+		}
+		Dimension quantityDimension = quantityUnit.getDimension();
+		if (!thisDimension.equals(quantityDimension))
+			throw new ClassCastException("Dimension of " + this + " is "
+					+ thisDimension
+					+ ", but the dimension of quantity of type "
+					+ type.getName() + " is " + quantityDimension);
+		return (Unit<T>) this;
+	}
+
+	/**
+	 * Returns the dimension of this unit (depends upon the current dimensional
+	 * {@link Dimension.Model model}).
+	 * 
+	 * @return the dimension of this unit for the current model.
+	 */
+	public final Dimension getDimension() {
+		Unit<?> systemUnit = this.toSI();
+		if (systemUnit instanceof BaseUnit)
+			return Dimension.getModel().getDimension((BaseUnit<?>) systemUnit);
+		if (systemUnit instanceof AlternateUnit)
+			return ((AlternateUnit<?>) systemUnit).getParent().getDimension();
+		// Product of units.
+		ProductUnit<?> productUnit = (ProductUnit<?>) systemUnit;
+		Dimension dimension = Dimension.NONE;
+		for (int i = 0; i < productUnit.getUnitCount(); i++) {
+			Unit<?> unit = productUnit.getUnit(i);
+			Dimension d = unit.getDimension().pow(productUnit.getUnitPow(i))
+					.root(productUnit.getUnitRoot(i));
+			dimension = dimension.times(d);
+		}
+		return dimension;
+	}
+
+	/**
+	 * Returns a converter of numeric values from this unit to another unit. As
+	 * a minimum unit sub-classes should be able to provide a unit converter to
+	 * their associated {@link #toSI() standard} unit.
+	 * 
+	 * @param that the unit to which to convert the numeric values.
+	 * @return the converter from this unit to <code>that</code> unit.
+	 * @throws ConversionException if the converter cannot be constructed (e.g.
+	 * <code>!this.isCompatible(that)</code>).
+	 */
+	public UnitConverter getConverterTo(Unit<Q> that)
+			throws ConversionException {
+		return ((this == that) || this.equals(that)) ? UnitConverter.IDENTITY
+				: searchConverterTo(that);
+	}
+
+	private UnitConverter searchConverterTo(Unit<Q> that)
+			throws ConversionException {
+		Unit<Q> thisSI = this.toSI();
+		Unit<Q> thatSI = that.toSI();
+		if (thisSI.equals(thatSI))
+			return that.getConverterTo(thatSI).inverse().concatenate(
+					this.getConverterTo(thisSI));
+		// Use dimensional transforms.
+		if (!thisSI.getDimension().equals(thatSI.getDimension()))
+			throw new ConversionException(this + " is not compatible with "
+					+ that);
+		// Transform between SystemUnit and BaseUnits is Identity.
+		UnitConverter thisTransform = this.getConverterTo(thisSI).concatenate(
+				transformOf(this.toBaseUnits()));
+		UnitConverter thatTransform = that.getConverterTo(thatSI).concatenate(
+				transformOf(that.toBaseUnits()));
+		return thatTransform.inverse().concatenate(thisTransform);
+	}
+
+	private Unit<?> toBaseUnits() {
+		Unit<?> systemUnit = this.toSI();
+		if (systemUnit instanceof BaseUnit)
+			return systemUnit;
+		if (systemUnit instanceof AlternateUnit)
+			return ((AlternateUnit<?>) systemUnit).getParent().toBaseUnits();
+		if (systemUnit instanceof ProductUnit) {
+			ProductUnit<?> productUnit = (ProductUnit<?>) systemUnit;
+			Unit<?> baseUnits = ONE;
+			for (int i = 0; i < productUnit.getUnitCount(); i++) {
+				Unit<?> unit = productUnit.getUnit(i).toBaseUnits();
+				unit = unit.pow(productUnit.getUnitPow(i));
+				unit = unit.root(productUnit.getUnitRoot(i));
+				baseUnits = baseUnits.times(unit);
+			}
+			return baseUnits;
+		} else
+			throw new InternalError("System Unit cannot be an instance of "
+					+ this.getClass());
+	}
+
+	private static UnitConverter transformOf(Unit<?> baseUnits) {
+		if (baseUnits instanceof BaseUnit)
+			return Dimension.getModel().getTransform((BaseUnit<?>) baseUnits);
+		// Product of units.
+		ProductUnit<?> productUnit = (ProductUnit<?>) baseUnits;
+		UnitConverter converter = UnitConverter.IDENTITY;
+		for (int i = 0; i < productUnit.getUnitCount(); i++) {
+			Unit<?> unit = productUnit.getUnit(i);
+			UnitConverter cvtr = transformOf(unit);
+			if (!(cvtr instanceof LinearConverter))
+				throw new ConversionException(baseUnits
+						+ " is non-linear, cannot convert");
+			if (productUnit.getUnitRoot(i) != 1)
+				throw new ConversionException(productUnit
+						+ " holds a base unit with fractional exponent");
+			int pow = productUnit.getUnitPow(i);
+			if (pow < 0) { // Negative power.
+				pow = -pow;
+				cvtr = cvtr.inverse();
+			}
+			for (int j = 0; j < pow; j++) {
+				converter = converter.concatenate(cvtr);
+			}
+		}
+		return converter;
+	}
+
+	/**
+	 * Returns a unit equivalent to this unit but used in expressions to
+	 * distinguish between quantities of a different nature but of the same
+	 * dimensions.
+	 * 
+	 * <p> Examples of alternate units:[code]
+	 *     Unit<Angle> RADIAN = ONE.alternate("rad"); 
+	 *     Unit<Force> NEWTON = METRE.times(KILOGRAM).divide(SECOND.pow(2)).alternate("N");
+	 *     Unit<Pressure> PASCAL = NEWTON.divide(METRE.pow(2)).alternate("Pa");
+	 * [/code]
+	 * </p>
+	 * 
+	 * @param symbol the new symbol for the alternate unit.
+	 * @return the alternate unit.
+	 * @throws UnsupportedOperationException if this unit is not a standard
+	 * unit.
+	 * @throws IllegalArgumentException if the specified symbol is already
+	 * associated to a different unit.
+	 */
+	public final <A extends Quantity> AlternateUnit<A> alternate(String symbol) {
+		return new AlternateUnit<A>(symbol, this);
+	}
+
+	/**
+	 * Returns the combination of this unit with the specified sub-unit.
+	 * Compound units are typically used for formatting purpose. Examples of
+	 * compound units:[code] 
+	 *     Unit<Length> FOOT_INCH = FOOT.compound(INCH);
+	 *     Unit<Duration> HOUR_MINUTE_SECOND = HOUR.compound(MINUTE).compound(SECOND);
+	 * [/code]
+	 * 
+	 * @param that the least significant unit to combine with this unit.
+	 * @return the corresponding compound unit.
+	 */
+	public final CompoundUnit<Q> compound(Unit<Q> that) {
+		return new CompoundUnit<Q>(this, that);
+	}
+
+	/**
+	 * Returns the unit derived from this unit using the specified converter.
+	 * The converter does not need to be linear. For example:[code]
+	 *     Unit<Dimensionless> DECIBEL = Unit.ONE.transform(
+	 *         new LogConverter(10).inverse().concatenate( 
+	 *             new RationalConverter(1, 10)));
+	 * [/code]
+	 * 
+	 * @param operation the converter from the transformed unit to this unit.
+	 * @return the unit after the specified transformation.
+	 */
+	public final Unit<Q> transform(UnitConverter operation) {
+		if (this instanceof TransformedUnit) {
+			TransformedUnit<Q> tf = (TransformedUnit<Q>) this;
+			Unit<Q> parent = tf.getParentUnit();
+			UnitConverter toParent = tf.toParentUnit().concatenate(operation);
+			if (toParent == UnitConverter.IDENTITY)
+				return parent;
+			return new TransformedUnit<Q>(parent, toParent);
+		}
+		if (operation == UnitConverter.IDENTITY)
+			return this;
+		return new TransformedUnit<Q>(this, operation);
+	}
+
+	/**
+	 * Returns the result of adding an offset to this unit. The returned unit is
+	 * convertible with all units that are convertible with this unit.
+	 * 
+	 * @param offset the offset added (expressed in this unit, e.g.
+	 * <code>CELSIUS = KELVIN.plus(273.15)</code>).
+	 * @return <code>this.transform(new AddConverter(offset))</code>
+	 */
+	public final Unit<Q> plus(double offset) {
+		if (offset == 0)
+			return this;
+		return transform(new AddConverter(offset));
+	}
+
+	/**
+	 * Returns the result of multiplying this unit by an exact factor.
+	 * 
+	 * @param factor the exact scale factor (e.g.
+	 * <code>KILOMETRE = METRE.times(1000)</code>).
+	 * @return <code>this.transform(new RationalConverter(factor, 1))</code>
+	 */
+	public final Unit<Q> times(long factor) {
+		if (factor == 1)
+			return this;
+		return transform(new RationalConverter(BigInteger.valueOf(factor),
+				BigInteger.ONE));
+	}
+
+	/**
+	 * Returns the result of multiplying this unit by a an approximate factor.
+	 * 
+	 * @param factor the approximate factor (e.g.
+	 * <code>ELECTRON_MASS = KILOGRAM.times(9.10938188e-31)</code>).
+	 * @return <code>this.transform(new MultiplyConverter(factor))</code>
+	 */
+	public final Unit<Q> times(double factor) {
+		if (factor == 1)
+			return this;
+		return transform(new MultiplyConverter(factor));
+	}
+
+	/**
+	 * Returns the product of this unit with the one specified.
+	 * 
+	 * @param that the unit multiplicand.
+	 * @return <code>this * that</code>
+	 */
+	@SuppressWarnings("unchecked")
+	public final Unit<?> times(Unit<?> that) {
+		if (this.equals(ONE))
+			return that;
+		if (that.equals(ONE))
+			return this;
+		if (this.isRationalFactor())
+			return that.transform(this.getConverterTo((Unit) ONE));
+		if (that.isRationalFactor())
+			return this.transform(that.getConverterTo((Unit) ONE));
+		return ProductUnit.getProductInstance(this, that);
+	}
+
+	private boolean isRationalFactor() {
+		if (!(this instanceof TransformedUnit))
+			return false;
+		TransformedUnit<Q> tu = (TransformedUnit<Q>) this;
+		return tu.getParentUnit().equals(ONE)
+				&& (tu.getConverterTo(tu.toSI()) instanceof RationalConverter);
+	}
+
+	/**
+	 * Returns the inverse of this unit.
+	 * 
+	 * @return <code>1 / this</code>
+	 */
+	@SuppressWarnings("unchecked")
+	public final Unit<?> inverse() {
+		if (this.equals(ONE))
+			return this;
+		if (this.isRationalFactor())
+			return this.transform(this.getConverterTo((Unit) ONE).inverse());
+		return ProductUnit.getQuotientInstance(ONE, this);
+	}
+
+	/**
+	 * Returns the result of dividing this unit by an exact divisor.
+	 * 
+	 * @param divisor the exact divisor. (e.g.
+	 * <code>QUART = GALLON_LIQUID_US.divide(4)</code>).
+	 * @return <code>this.transform(new RationalConverter(1 , divisor))</code>
+	 */
+	public final Unit<Q> divide(long divisor) {
+		if (divisor == 1)
+			return this;
+		return transform(new RationalConverter(BigInteger.ONE, BigInteger
+				.valueOf(divisor)));
+	}
+
+	/**
+	 * Returns the result of dividing this unit by an approximate divisor.
+	 * 
+	 * @param divisor the approximate divisor.
+	 * @return <code>this.transform(new MultiplyConverter(1.0 / divisor))</code>
+	 */
+	public final Unit<Q> divide(double divisor) {
+		if (divisor == 1)
+			return this;
+		return transform(new MultiplyConverter(1.0 / divisor));
+	}
+
+	/**
+	 * Returns the quotient of this unit with the one specified.
+	 * 
+	 * @param that the unit divisor.
+	 * @return <code>this / that</code>
+	 */
+	public final Unit<?> divide(Unit<?> that) {
+		return this.times(that.inverse());
+	}
+
+	/**
+	 * Returns a unit equals to the given root of this unit.
+	 * 
+	 * @param n the root's order.
+	 * @return the result of taking the given root of this unit.
+	 * @throws ArithmeticException if <code>n == 0</code>.
+	 */
+	public final Unit<?> root(int n) {
+		if (n > 0)
+			return ProductUnit.getRootInstance(this, n);
+		else if (n == 0)
+			throw new ArithmeticException("Root's order of zero");
+		else
+			// n < 0
+			return ONE.divide(this.root(-n));
+	}
+
+	/**
+	 * Returns a unit equals to this unit raised to an exponent.
+	 * 
+	 * @param n the exponent.
+	 * @return the result of raising this unit to the exponent.
+	 */
+	public final Unit<?> pow(int n) {
+		if (n > 0)
+			return this.times(this.pow(n - 1));
+		else if (n == 0)
+			return ONE;
+		else
+			// n < 0
+			return ONE.divide(this.pow(-n));
+	}
+
+	/**
+	 * Returns a unit instance that is defined from the specified character
+	 * sequence using the {@link UnitFormat#getStandard standard} unit format
+	 * (<a href="http://unitsofmeasure.org/">UCUM</a> based). This method is
+	 * capable of parsing any units representations produced by
+	 * {@link #toString()}. Locale-sensitive unit formatting and parsing are
+	 * handled by the {@link UnitFormat} class and its subclasses.
+	 * 
+	 * <p>
+	 * This method can be used to parse dimensionless units.[code]
+	 * Unit<Dimensionless> PERCENT = Unit.valueOf("100").inverse().asType(Dimensionless.class); [/code]
+	 * 
+	 * @param csq the character sequence to parse.
+	 * @return
+	 * <code>UnitFormat.getStandard().parse(csq, new ParsePosition(0))</code>
+	 * @throws IllegalArgumentException if the specified character sequence
+	 * cannot be correctly parsed (e.g. not UCUM compliant).
+	 */
+	public static Unit<?> valueOf(CharSequence csq) {
+		return UnitFormat.getStandard().parse(csq, new ParsePosition(0));
+	}
+
+	// ////////////////////
+	// GENERAL CONTRACT //
+	// ////////////////////
+	/**
+	 * Returns the international <code>String</code> representation of this unit
+	 * (<a href="http://unitsofmeasure.org/">UCUM</a> based). The string
+	 * produced for a given unit is always the same; it is not affected by the
+	 * locale. This means that it can be used as a canonical string
+	 * representation for exchanging units, or as a key for a Hashtable, etc.
+	 * Locale-sensitive unit formatting and parsing is handled by the
+	 * {@link UnitFormat} class and its subclasses.
+	 * 
+	 * <p>Custom units types should override this method as they will not be
+	 * recognized by the UCUM format.</p>
+	 * 
+	 * 
+	 * @return <code>UnitFormat.getStandard().format(this)</code>
+	 */
+	@Override
+	public String toString() {
+		return UnitFormat.getStandard().format(this);
+	}
+
+	private static final long serialVersionUID = 1L;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/unit/UnitFormat.java b/src/main/java/javax/measure/unit/UnitFormat.java
new file mode 100644
index 0000000..a2ccdcc
--- /dev/null
+++ b/src/main/java/javax/measure/unit/UnitFormat.java
@@ -0,0 +1,164 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit;
+
+import javax.measure.unit.format.*;
+import java.io.IOException;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+/**
+ * <p> This class provides the interface for formatting and parsing {@link 
+ *     Unit units}.</p>
+ *     
+ * <p> For all {@link SI} units, the 20 SI prefixes used to form decimal
+ *     multiples and sub-multiples of SI units are recognized.
+ *     {@link NonSI} units are directly recognized. For example:[code]
+ *        Unit.valueOf("m°C").equals(SI.MILLI(SI.CELSIUS))
+ *        Unit.valueOf("kW").equals(SI.KILO(SI.WATT))
+ *        Unit.valueOf("ft").equals(SI.METRE.multiply(3048).divide(10000))[/code]</p>
+ *
+ * @author <a href="mailto:jean-marie at dautelle.com">Jean-Marie Dautelle</a>
+ * @author Eric Russell
+ * @version 1.0, April 15, 2009
+ */
+public abstract class UnitFormat extends Format {
+
+    /**
+     * Returns the unit format for the default locale.
+     * 
+     * @return {@link LocalFormat#getInstance()}
+     */
+    public static UnitFormat getInstance() {
+        return LocalFormat.getInstance();
+    }
+
+    /**
+     * Returns the unit format for the specified locale.
+     *
+     * @param locale the locale for which the format is returned.
+     * @return {@link LocalFormat#getInstance(java.util.Locale)}
+     */
+    public static UnitFormat getInstance(Locale locale) {
+        return LocalFormat.getInstance(locale);
+    }
+
+    /**
+     * Returns the standard
+     * <a href="http://unitsofmeasure.org/">UCUM </a> unit format.
+     * This is the format used by {@link Unit#valueOf(CharSequence)
+     * Unit.valueOf(CharSequence)} and {@link Unit#toString() Unit.toString()}).
+     *
+     * <p> This format uses characters range <code>0000-007F</code> exclusively
+     * and <b>is not</b> locale-sensitive. For example: <code>kg.m/s2</code></p>
+     *
+     * <p>For a description of the UCUM format including BNF, see:
+     *     <a href="http://aurora.regenstrief.org/~ucum/ucum.html">
+     * The Unified Code for Units of Measure</a></p>
+     * 
+     * @return {@link UCUMFormat#getCaseSensitiveInstance()}
+     */
+    public static UnitFormat getStandard() {
+        return UCUMFormat.getCaseSensitiveInstance();
+    }
+
+    /**
+     * Base constructor.
+     */
+    protected UnitFormat() {
+    }
+
+    /**
+     * Formats the specified unit.
+     *
+     * @param unit the unit to format.
+     * @param appendable the appendable destination.
+     * @throws IOException if an error occurs.
+     */
+    public abstract Appendable format(Unit<?> unit, Appendable appendable)
+            throws IOException;
+
+    /**
+     * Parses a portion of the specified <code>CharSequence</code> from the
+     * specified position to produce a unit. If there is no unit to parse 
+     * {@link Unit#ONE} is returned.
+     *
+     * @param csq the <code>CharSequence</code> to parse.
+     * @param cursor the cursor holding the current parsing index.
+     * @return the unit parsed from the specified character sub-sequence.
+     * @throws IllegalArgumentException if any problem occurs while parsing the
+     *         specified character sequence (e.g. illegal syntax).
+     */
+    public abstract Unit<?> parse(CharSequence csq, ParsePosition cursor)
+            throws IllegalArgumentException;
+
+    @Override
+    public final StringBuffer format(Object obj, final StringBuffer toAppendTo,
+            FieldPosition pos) {
+        if (!(obj instanceof Unit))
+            throw new IllegalArgumentException("obj: Not an instance of Unit");
+        if ((toAppendTo == null) || (pos == null))
+            throw new NullPointerException(); // Format contract.
+        try {
+            return (StringBuffer) format((Unit<?>) obj, (Appendable) toAppendTo);
+        } catch (IOException ex) {
+            throw new Error(ex); // Cannot happen.
+        }
+    }
+
+    @Override
+    public final Unit<?> parseObject(String source, ParsePosition pos) {
+        try {
+            return parse(source, pos);
+        } catch (IllegalArgumentException e) {
+            return null; // Unfortunately the message why the parsing failed
+        }                // is lost; but we have to follow the Format spec.
+
+    }
+
+    /**
+     * Convenience method equivalent to {@link #format(Unit, Appendable)}
+     * except it does not raise an IOException.
+     *
+     * @param unit the unit to format.
+     * @param dest the appendable destination.
+     * @return the specified <code>StringBuilder</code>.
+     */
+    public final StringBuilder format(Unit<?> unit, StringBuilder dest) {
+        try {
+            return (StringBuilder) this.format(unit, (Appendable) dest);
+        } catch (IOException ex) {
+            throw new Error(ex); // Can never happen.
+        }
+    }
+    
+    private static final long serialVersionUID = 1L;
+
+}
\ No newline at end of file
diff --git a/src/main/java/javax/measure/unit/format/LocalFormat.java b/src/main/java/javax/measure/unit/format/LocalFormat.java
new file mode 100644
index 0000000..d43aedb
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/LocalFormat.java
@@ -0,0 +1,522 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit.format;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.math.BigInteger;
+import java.text.ParsePosition;
+import java.util.*;
+import java.util.ResourceBundle;
+import javax.measure.converter.*;
+import javax.measure.unit.*;
+
+/**
+ * <p> This class represents the local sensitive format.</p>
+ *
+ * <h3>Here is the grammar for Units in Extended Backus-Naur Form (EBNF)</h3>
+ * <p>
+ *   Note that the grammar has been left-factored to be suitable for use by a top-down 
+ *   parser generator such as <a href="https://javacc.dev.java.net/">JavaCC</a>
+ * </p>
+ * <table width="90%" align="center">
+ *   <tr>
+ *     <th colspan="3" align="left">Lexical Entities:</th>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><sign></td>
+ *     <td>:=</td>
+ *     <td>"+" | "-"</td>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><digit></td>
+ *     <td>:=</td>
+ *     <td>"0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"</td>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><superscript_digit></td>
+ *     <td>:=</td>
+ *     <td>"⁰" | "¹" | "²" | "³" | "⁴" | "⁵" | "⁶" | "⁷" | "⁸" | "⁹"</td>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><integer></td>
+ *     <td>:=</td>
+ *     <td>(<digit>)+</td>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><number></td>
+ *     <td>:=</td>
+ *     <td>(<sign>)? (<digit>)* (".")? (<digit>)+ (("e" | "E") (<sign>)? (<digit>)+)? </td>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><exponent></td>
+ *     <td>:=</td>
+ *     <td>( "^" ( <sign> )? <integer> ) <br>| ( "^(" (<sign>)? <integer> ( "/" (<sign>)? <integer> )? ")" ) <br>| ( <superscript_digit> )+</td>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><initial_char></td>
+ *     <td>:=</td>
+ *     <td>? Any Unicode character excluding the following: ASCII control & whitespace (\u0000 - \u0020), decimal digits '0'-'9', '(' (\u0028), ')' (\u0029), '*' (\u002A), '+' (\u002B), '-' (\u002D), '.' (\u002E), '/' (\u005C), ':' (\u003A), '^' (\u005E), '²' (\u00B2), '³' (\u00B3), '·' (\u00B7), '¹' (\u00B9), '⁰' (\u2070), '⁴' (\u2074), '⁵' (\u2075), '⁶' (\u2076), '⁷' (\u2077), '⁸' (\u2078), '⁹' (\u2 [...]
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><unit_identifier></td>
+ *     <td>:=</td>
+ *     <td><initial_char> ( <initial_char> | <digit> )*</td>
+ *   </tr>
+ *   <tr>
+ *     <th colspan="3" align="left">Non-Terminals:</th>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><unit_expr></td>
+ *     <td>:=</td>
+ *     <td><compound_expr></td>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><compound_expr></td>
+ *     <td>:=</td>
+ *     <td><add_expr> ( ":" <add_expr> )*</td>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><add_expr></td>
+ *     <td>:=</td>
+ *     <td>( <number> <sign> )? <mul_expr> ( <sign> <number> )?</td>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><mul_expr></td>
+ *     <td>:=</td>
+ *     <td><exponent_expr> ( ( ( "*" | "·" ) <exponent_expr> ) | ( "/" <exponent_expr> ) )*</td>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><exponent_expr></td>
+ *     <td>:=</td>
+ *     <td>( <atomic_expr> ( <exponent> )? ) <br>| (<integer> "^" <atomic_expr>) <br>| ( ( "log" ( <integer> )? ) | "ln" ) "(" <add_expr> ")" )</td>
+ *   </tr>
+ *   <tr valign="top">
+ *     <td><atomic_expr></td>
+ *     <td>:=</td>
+ *     <td><number> <br>| <unit_identifier> <br>| ( "(" <add_expr> ")" )</td>
+ *   </tr>
+ * </table>
+ * 
+ * @author <a href="mailto:eric-r at northwestern.edu">Eric Russell</a>
+ * @version 1.0
+ */
+public class LocalFormat extends UnitFormat {
+
+    //////////////////////////////////////////////////////
+    // Class variables                                  //
+    //////////////////////////////////////////////////////
+    /** Default locale instance. If the default locale is changed after the class is
+    initialized, this instance will no longer be used. */
+    private static LocalFormat DEFAULT_INSTANCE = new LocalFormat(new SymbolMap(ResourceBundle.getBundle("javax.measure.unit.format.LocalFormat")));
+    /** Multiplicand character */
+    private static final char MIDDLE_DOT = '\u00b7';
+    /** Operator precedence for the addition and subtraction operations */
+    private static final int ADDITION_PRECEDENCE = 0;
+    /** Operator precedence for the multiplication and division operations */
+    private static final int PRODUCT_PRECEDENCE = ADDITION_PRECEDENCE + 2;
+    /** Operator precedence for the exponentiation and logarithm operations */
+    private static final int EXPONENT_PRECEDENCE = PRODUCT_PRECEDENCE + 2;
+    /**
+     * Operator precedence for a unit identifier containing no mathematical
+     * operations (i.e., consisting exclusively of an identifier and possibly
+     * a prefix). Defined to be <code>Integer.MAX_VALUE</code> so that no
+     * operator can have a higher precedence.
+     */
+    private static final int NOOP_PRECEDENCE = Integer.MAX_VALUE;
+
+    ///////////////////
+    // Class methods //
+    ///////////////////
+    /** Returns the instance for the current default locale (non-ascii characters are allowed) */
+    public static LocalFormat getInstance() {
+        return DEFAULT_INSTANCE;
+    }
+
+    /** 
+     * Returns an instance for the given locale.
+     * @param locale
+     */
+    public static LocalFormat getInstance(Locale locale) {
+        return new LocalFormat(new SymbolMap(ResourceBundle.getBundle("javax.measure.unit.format.LocalFormat", locale)));
+    }
+
+    /** Returns an instance for the given symbol map. */
+    public static LocalFormat getInstance(SymbolMap symbols) {
+        return new LocalFormat(symbols);
+    }
+    ////////////////////////
+    // Instance variables //
+    ////////////////////////
+    /** 
+     * The symbol map used by this instance to map between 
+     * {@link javax.measure.unit.Unit Unit}s and <code>String</code>s, etc... 
+     */
+    private SymbolMap _symbolMap;
+
+    //////////////////
+    // Constructors //
+    //////////////////
+    /**
+     * Base constructor.
+     *
+     * @param symbols the symbol mapping.
+     */
+    private LocalFormat(SymbolMap symbols) {
+        _symbolMap = symbols;
+    }
+
+    ////////////////////////
+    // Instance methods //
+    ////////////////////////
+    /** 
+     * Get the symbol map used by this instance to map between 
+     * {@link javax.measure.unit.Unit Unit}s and <code>String</code>s, etc... 
+     * @return SymbolMap the current symbol map
+     */
+    public SymbolMap getSymbols() {
+        return _symbolMap;
+    }
+
+    ////////////////
+    // Formatting //
+    ////////////////
+    @Override
+    public Appendable format(Unit<?> unit, Appendable appendable) throws IOException {
+        formatInternal(unit, appendable);
+        return appendable;
+    }
+
+    @Override
+    public Unit<?> parse(CharSequence csq, ParsePosition cursor) throws IllegalArgumentException {
+        // Parsing reads the whole character sequence from the parse position.
+        int start = cursor.getIndex();
+        int end = csq.length();
+        if (end <= start) {
+            return Unit.ONE;
+        }
+        String source = csq.subSequence(start, end).toString().trim();
+        if (source.length() == 0) {
+            return Unit.ONE;
+        }
+        try {
+            UnitParser parser = new UnitParser(_symbolMap, new StringReader(source));
+            Unit<?> result = parser.parseUnit();
+            cursor.setIndex(end);
+            return result;
+        } catch (ParseException e) {
+            if (e.currentToken != null) {
+                cursor.setErrorIndex(start + e.currentToken.endColumn);
+            } else {
+                cursor.setErrorIndex(start);
+            }
+            throw new IllegalArgumentException(e.getMessage());
+        } catch (TokenMgrError e) {
+            cursor.setErrorIndex(start);
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+
+    /**
+     * Format the given unit to the given StringBuffer, then return the operator
+     * precedence of the outermost operator in the unit expression that was 
+     * formatted. See {@link ConverterFormat} for the constants that define the
+     * various precedence values.
+     * @param unit the unit to be formatted
+     * @param buffer the <code>StringBuffer</code> to be written to
+     * @return the operator precedence of the outermost operator in the unit 
+     *   expression that was output
+     */
+    private int formatInternal(Unit<?> unit, Appendable buffer) throws IOException {
+        if (unit instanceof AnnotatedUnit) {
+            unit = ((AnnotatedUnit<?>) unit).getRealUnit();
+        }
+        String symbol = _symbolMap.getSymbol(unit);
+        if (symbol != null) {
+            buffer.append(symbol);
+            return NOOP_PRECEDENCE;
+        } else if (unit instanceof ProductUnit) {
+            ProductUnit<?> productUnit = (ProductUnit<?>) unit;
+            int negativeExponentCount = 0;
+            // Write positive exponents first...
+            boolean start = true;
+            for (int i = 0; i < productUnit.getUnitCount(); i += 1) {
+                int pow = productUnit.getUnitPow(i);
+                if (pow >= 0) {
+                    formatExponent(productUnit.getUnit(i), pow, productUnit.getUnitRoot(i), !start, buffer);
+                    start = false;
+                } else {
+                    negativeExponentCount += 1;
+                }
+            }
+            // ..then write negative exponents.
+            if (negativeExponentCount > 0) {
+                if (start) {
+                    buffer.append('1');
+                }
+                buffer.append('/');
+                if (negativeExponentCount > 1) {
+                    buffer.append('(');
+                }
+                start = true;
+                for (int i = 0; i < productUnit.getUnitCount(); i += 1) {
+                    int pow = productUnit.getUnitPow(i);
+                    if (pow < 0) {
+                        formatExponent(productUnit.getUnit(i), -pow, productUnit.getUnitRoot(i), !start, buffer);
+                        start = false;
+                    }
+                }
+                if (negativeExponentCount > 1) {
+                    buffer.append(')');
+                }
+            }
+            return PRODUCT_PRECEDENCE;
+        } else if ((unit instanceof TransformedUnit) || unit.equals(SI.KILOGRAM)) {
+            UnitConverter converter = null;
+            boolean printSeparator = false;
+            StringBuffer temp = new StringBuffer();
+            int unitPrecedence = NOOP_PRECEDENCE;
+            if (unit.equals(SI.KILOGRAM)) {
+                // A special case because KILOGRAM is a BaseUnit instead of 
+                // a transformed unit, even though it has a prefix.
+                converter = Prefix.KILO.getConverter();
+                unitPrecedence = formatInternal(SI.GRAM, temp);
+                printSeparator = true;
+            } else {
+                TransformedUnit<?> transformedUnit = (TransformedUnit<?>) unit;
+                Unit<?> parentUnits = transformedUnit.getParentUnit();
+                converter = transformedUnit.toParentUnit();
+                if (parentUnits.equals(SI.KILOGRAM)) {
+                    // More special-case hackery to work around gram/kilogram 
+                    // incosistency
+                    parentUnits = SI.GRAM;
+                    converter = converter.concatenate(Prefix.KILO.getConverter());
+                }
+                unitPrecedence = formatInternal(parentUnits, temp);
+                printSeparator = !parentUnits.equals(Unit.ONE);
+            }
+            int result = formatConverter(converter, printSeparator, unitPrecedence, temp);
+            buffer.append(temp);
+            return result;
+        } else if (unit instanceof AlternateUnit) {
+            buffer.append(((AlternateUnit<?>) unit).getSymbol());
+            return NOOP_PRECEDENCE;
+        } else if (unit instanceof BaseUnit) {
+            buffer.append(((BaseUnit<?>) unit).getSymbol());
+            return NOOP_PRECEDENCE;
+        } else {
+            throw new IllegalArgumentException("Cannot format the given Object as a Unit (unsupported unit type " + unit.getClass().getName() + ")");
+        }
+    }
+
+    /**
+     * Format the given unit raised to the given fractional power to the
+     * given <code>StringBuffer</code>.
+     * @param unit Unit the unit to be formatted
+     * @param pow int the numerator of the fractional power
+     * @param root int the denominator of the fractional power
+     * @param continued boolean <code>true</code> if the converter expression 
+     *    should begin with an operator, otherwise <code>false</code>. This will 
+     *    always be true unless the unit being modified is equal to Unit.ONE.
+     * @param buffer StringBuffer the buffer to append to. No assumptions should
+     *    be made about its content.
+     */
+    private void formatExponent(Unit<?> unit, int pow, int root, boolean continued, Appendable buffer) throws IOException {
+        if (continued) {
+            buffer.append(MIDDLE_DOT);
+        }
+        StringBuffer temp = new StringBuffer();
+        int unitPrecedence = formatInternal(unit, temp);
+        if (unitPrecedence < PRODUCT_PRECEDENCE) {
+            temp.insert(0, '(');
+            temp.append(')');
+        }
+        buffer.append(temp);
+        if ((root == 1) && (pow == 1)) {
+            // do nothing
+        } else if ((root == 1) && (pow > 1)) {
+            String powStr = Integer.toString(pow);
+            for (int i = 0; i < powStr.length(); i += 1) {
+                char c = powStr.charAt(i);
+                switch (c) {
+                    case '0':
+                        buffer.append('\u2070');
+                        break;
+                    case '1':
+                        buffer.append('\u00b9');
+                        break;
+                    case '2':
+                        buffer.append('\u00b2');
+                        break;
+                    case '3':
+                        buffer.append('\u00b3');
+                        break;
+                    case '4':
+                        buffer.append('\u2074');
+                        break;
+                    case '5':
+                        buffer.append('\u2075');
+                        break;
+                    case '6':
+                        buffer.append('\u2076');
+                        break;
+                    case '7':
+                        buffer.append('\u2077');
+                        break;
+                    case '8':
+                        buffer.append('\u2078');
+                        break;
+                    case '9':
+                        buffer.append('\u2079');
+                        break;
+                }
+            }
+        } else if (root == 1) {
+            buffer.append("^");
+            buffer.append(String.valueOf(pow));
+        } else {
+            buffer.append("^(");
+            buffer.append(String.valueOf(pow));
+            buffer.append('/');
+            buffer.append(String.valueOf(root));
+            buffer.append(')');
+        }
+    }
+
+    /**
+     * Formats the given converter to the given StringBuffer and returns the
+     * operator precedence of the converter's mathematical operation. This is
+     * the default implementation, which supports all built-in UnitConverter
+     * implementations. Note that it recursively calls itself in the case of 
+     * a {@link javax.measure.converter.UnitConverter.Compound Compound} 
+     * converter.
+     * @param converter the converter to be formatted
+     * @param continued <code>true</code> if the converter expression should 
+     *    begin with an operator, otherwise <code>false</code>.
+     * @param unitPrecedence the operator precedence of the operation expressed
+     *    by the unit being modified by the given converter.
+     * @param buffer the <code>StringBuffer</code> to append to.
+     * @return the operator precedence of the given UnitConverter
+     */
+    private int formatConverter(UnitConverter converter,
+            boolean continued,
+            int unitPrecedence,
+            StringBuffer buffer) {
+        Prefix prefix = _symbolMap.getPrefix(converter);
+        if ((prefix != null) && (unitPrecedence == NOOP_PRECEDENCE)) {
+            buffer.insert(0, _symbolMap.getSymbol(prefix));
+            return NOOP_PRECEDENCE;
+        } else if (converter instanceof AddConverter) {
+            if (unitPrecedence < ADDITION_PRECEDENCE) {
+                buffer.insert(0, '(');
+                buffer.append(')');
+            }
+            double offset = ((AddConverter) converter).getOffset();
+            if (offset < 0) {
+                buffer.append("-");
+                offset = -offset;
+            } else if (continued) {
+                buffer.append("+");
+            }
+            long lOffset = (long) offset;
+            if (lOffset == offset) {
+                buffer.append(lOffset);
+            } else {
+                buffer.append(offset);
+            }
+            return ADDITION_PRECEDENCE;
+        } else if (converter instanceof LogConverter) {
+            double base = ((LogConverter) converter).getBase();
+            StringBuffer expr = new StringBuffer();
+            if (base == StrictMath.E) {
+                expr.append("ln");
+            } else {
+                expr.append("log");
+                if (base != 10) {
+                    expr.append((int) base);
+                }
+            }
+            expr.append("(");
+            buffer.insert(0, expr);
+            buffer.append(")");
+            return EXPONENT_PRECEDENCE;
+        } else if (converter instanceof ExpConverter) {
+            if (unitPrecedence < EXPONENT_PRECEDENCE) {
+                buffer.insert(0, '(');
+                buffer.append(')');
+            }
+            StringBuffer expr = new StringBuffer();
+            double base = ((ExpConverter) converter).getBase();
+            if (base == StrictMath.E) {
+                expr.append('e');
+            } else {
+                expr.append((int) base);
+            }
+            expr.append('^');
+            buffer.insert(0, expr);
+            return EXPONENT_PRECEDENCE;
+        } else if (converter instanceof MultiplyConverter) {
+            if (unitPrecedence < PRODUCT_PRECEDENCE) {
+                buffer.insert(0, '(');
+                buffer.append(')');
+            }
+            if (continued) {
+                buffer.append(MIDDLE_DOT);
+            }
+            double factor = ((MultiplyConverter) converter).getFactor();
+            long lFactor = (long) factor;
+            if (lFactor == factor) {
+                buffer.append(lFactor);
+            } else {
+                buffer.append(factor);
+            }
+            return PRODUCT_PRECEDENCE;
+        } else if (converter instanceof RationalConverter) {
+            if (unitPrecedence < PRODUCT_PRECEDENCE) {
+                buffer.insert(0, '(');
+                buffer.append(')');
+            }
+            RationalConverter rationalConverter = (RationalConverter) converter;
+            if (!rationalConverter.getDividend().equals(BigInteger.ONE)) {
+                if (continued) {
+                    buffer.append(MIDDLE_DOT);
+                }
+                buffer.append(rationalConverter.getDividend());
+            }
+            if (!rationalConverter.getDivisor().equals(BigInteger.ONE)) {
+                buffer.append('/');
+                buffer.append(rationalConverter.getDivisor());
+            }
+            return PRODUCT_PRECEDENCE;
+        } else {
+            throw new IllegalArgumentException("Unable to format the given UnitConverter: " + converter.getClass());
+        }
+    }
+    private static final long serialVersionUID = 1L;
+
+}
diff --git a/src/main/java/javax/measure/unit/format/LocalFormat.properties b/src/main/java/javax/measure/unit/format/LocalFormat.properties
new file mode 100644
index 0000000..cee0ac3
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/LocalFormat.properties
@@ -0,0 +1,139 @@
+# NOTE: as a Java properties file, this file must use the
+# ISO 8859-1 encoding, so all non-ASCII Unicode characters 
+# must be escaped using the \uXXXX syntax.
+# See http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html#encoding
+
+# SI Prefixes
+
+javax.measure.unit.format.Prefix.YOTTA=Y
+javax.measure.unit.format.Prefix.ZETTA=Z
+javax.measure.unit.format.Prefix.EXA=E
+javax.measure.unit.format.Prefix.PETA=P
+javax.measure.unit.format.Prefix.TERA=T
+javax.measure.unit.format.Prefix.GIGA=G
+javax.measure.unit.format.Prefix.MEGA=M
+javax.measure.unit.format.Prefix.KILO=k
+javax.measure.unit.format.Prefix.HECTO=h
+javax.measure.unit.format.Prefix.DEKA=da
+javax.measure.unit.format.Prefix.DECI=d
+javax.measure.unit.format.Prefix.CENTI=c
+javax.measure.unit.format.Prefix.MILLI=m
+javax.measure.unit.format.Prefix.MICRO=\u00B5
+javax.measure.unit.format.Prefix.NANO=n
+javax.measure.unit.format.Prefix.PICO=p
+javax.measure.unit.format.Prefix.FEMTO=f
+javax.measure.unit.format.Prefix.ATTO=a
+javax.measure.unit.format.Prefix.ZEPTO=z
+javax.measure.unit.format.Prefix.YOCTO=y
+
+# SI Units
+
+javax.measure.unit.SI.AMPERE=A
+javax.measure.unit.SI.BECQUEREL=Bq
+javax.measure.unit.SI.CANDELA=cd
+javax.measure.unit.SI.CELSIUS=\u00B0C
+javax.measure.unit.SI.CELSIUS.1=\u2103
+javax.measure.unit.SI.CELSIUS.2=Celsius
+javax.measure.unit.SI.COULOMB=C
+javax.measure.unit.SI.FARAD=F
+javax.measure.unit.SI.GRAM=g
+javax.measure.unit.SI.GRAY=Gy
+javax.measure.unit.SI.HENRY=H
+javax.measure.unit.SI.HERTZ=Hz
+javax.measure.unit.SI.JOULE=J
+javax.measure.unit.SI.KATAL=kat
+javax.measure.unit.SI.KELVIN=K
+javax.measure.unit.SI.LUMEN=lm
+javax.measure.unit.SI.LUX=lx
+javax.measure.unit.SI.METRE=m
+javax.measure.unit.SI.MOLE=mol
+javax.measure.unit.SI.NEWTON=N
+javax.measure.unit.SI.OHM=\u03A9
+javax.measure.unit.SI.PASCAL=Pa
+javax.measure.unit.SI.RADIAN=rad
+javax.measure.unit.SI.SECOND=s
+javax.measure.unit.SI.SIEMENS=S
+javax.measure.unit.SI.SIEVERT=Sv
+javax.measure.unit.SI.STERADIAN=sr
+javax.measure.unit.SI.TESLA=T
+javax.measure.unit.SI.VOLT=V
+javax.measure.unit.SI.WATT=W
+javax.measure.unit.SI.WEBER=Wb
+
+# Non-SI Units
+
+javax.measure.unit.NonSI.PERCENT=%
+javax.measure.unit.NonSI.DECIBEL=dB
+javax.measure.unit.NonSI.G=grav
+javax.measure.unit.NonSI.ATOM=atom
+javax.measure.unit.NonSI.REVOLUTION=rev
+javax.measure.unit.NonSI.DEGREE_ANGLE=\u00B0
+javax.measure.unit.NonSI.MINUTE_ANGLE='
+javax.measure.unit.NonSI.SECOND_ANGLE="
+javax.measure.unit.NonSI.CENTIRADIAN=centiradian
+javax.measure.unit.NonSI.GRADE=grade
+javax.measure.unit.NonSI.ARE=a
+javax.measure.unit.NonSI.HECTARE=ha
+javax.measure.unit.NonSI.BYTE=byte
+javax.measure.unit.NonSI.MINUTE=min
+javax.measure.unit.NonSI.HOUR=h
+javax.measure.unit.NonSI.DAY=day
+javax.measure.unit.NonSI.WEEK=week
+javax.measure.unit.NonSI.DAY_SIDEREAL=day_sidereal
+javax.measure.unit.NonSI.YEAR_SIDEREAL=year_sidereal
+javax.measure.unit.NonSI.YEAR_CALENDAR=year
+javax.measure.unit.NonSI.E=e
+javax.measure.unit.NonSI.FARADAY=Fd
+javax.measure.unit.NonSI.FRANKLIN=Fr
+javax.measure.unit.NonSI.GILBERT=Gi
+javax.measure.unit.NonSI.ERG=erg
+javax.measure.unit.NonSI.ELECTRON_VOLT=eV
+javax.measure.unit.NonSI.LAMBERT=La
+javax.measure.unit.NonSI.FOOT=ft
+javax.measure.unit.NonSI.FOOT_SURVEY_US=foot_survey_us
+javax.measure.unit.NonSI.YARD=yd
+javax.measure.unit.NonSI.INCH=in
+javax.measure.unit.NonSI.MILE=mi
+javax.measure.unit.NonSI.NAUTICAL_MILE=nmi
+javax.measure.unit.NonSI.MILES_PER_HOUR=mph
+javax.measure.unit.NonSI.ANGSTROM=\u00C5
+javax.measure.unit.NonSI.ASTRONOMICAL_UNIT=ua
+javax.measure.unit.NonSI.LIGHT_YEAR=ly
+javax.measure.unit.NonSI.PARSEC=pc
+javax.measure.unit.NonSI.POINT=pt
+javax.measure.unit.NonSI.PIXEL=pixel
+javax.measure.unit.NonSI.MAXWELL=Mx
+javax.measure.unit.NonSI.GAUSS=G
+javax.measure.unit.NonSI.ATOMIC_MASS=u
+javax.measure.unit.NonSI.ELECTRON_MASS=me
+javax.measure.unit.NonSI.POUND=lb
+javax.measure.unit.NonSI.OUNCE=oz
+javax.measure.unit.NonSI.TON_US=ton_us
+javax.measure.unit.NonSI.TON_UK=ton_uk
+javax.measure.unit.NonSI.METRIC_TON=t
+javax.measure.unit.NonSI.DYNE=dyn
+javax.measure.unit.NonSI.KILOGRAM_FORCE=kgf
+javax.measure.unit.NonSI.POUND_FORCE=lbf
+javax.measure.unit.NonSI.HORSEPOWER=hp
+javax.measure.unit.NonSI.ATMOSPHERE=atm
+javax.measure.unit.NonSI.BAR=bar
+javax.measure.unit.NonSI.MILLIMETER_OF_MERCURY=mmHg
+javax.measure.unit.NonSI.INCH_OF_MERCURY=inHg
+javax.measure.unit.NonSI.RAD=rd
+javax.measure.unit.NonSI.REM=rem
+javax.measure.unit.NonSI.CURIE=Ci
+javax.measure.unit.NonSI.RUTHERFORD=Rd
+javax.measure.unit.NonSI.SPHERE=sphere
+javax.measure.unit.NonSI.RANKINE=\u00B0R
+javax.measure.unit.NonSI.FAHRENHEIT=\u00B0F
+javax.measure.unit.NonSI.FAHRENHEIT.1=\u2109
+javax.measure.unit.NonSI.KNOT=kn
+javax.measure.unit.NonSI.C=c
+javax.measure.unit.NonSI.LITRE=L
+javax.measure.unit.NonSI.GALLON_LIQUID_US=gal
+javax.measure.unit.NonSI.OUNCE_LIQUID_US=oz
+javax.measure.unit.NonSI.GALLON_DRY_US=gallon_dry_us
+javax.measure.unit.NonSI.GALLON_UK=gallon_uk
+javax.measure.unit.NonSI.OUNCE_LIQUID_UK=oz_uk
+javax.measure.unit.NonSI.ROENTGEN=Roentgen
+javax.measure.unit.NonSI.PI=\u03C0
diff --git a/src/main/java/javax/measure/unit/format/LocalFormat_de.properties b/src/main/java/javax/measure/unit/format/LocalFormat_de.properties
new file mode 100644
index 0000000..925ced9
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/LocalFormat_de.properties
@@ -0,0 +1,21 @@
+#Generated by ResourceBundle Editor (http://eclipse-rbe.sourceforge.net)
+#$Id: LocalFormat_de.properties,v 1.1 2009/06/13 22:40:18 dautelle Exp $
+javax.measure.unit.NonSI.DAY              = tag
+javax.measure.unit.NonSI.DAY_SIDEREAL     = tag_sidereal
+javax.measure.unit.NonSI.FOOT_SURVEY_US   = fu\u00DF_survey_us
+javax.measure.unit.NonSI.GALLON_DRY_US    = gallone_trocken_us
+javax.measure.unit.NonSI.GALLON_UK        = gallone_uk
+javax.measure.unit.NonSI.GRADE            = grad
+javax.measure.unit.NonSI.HORSEPOWER       = ps
+javax.measure.unit.NonSI.LIGHT_YEAR       = lj
+javax.measure.unit.NonSI.MILES_PER_HOUR   = mps
+javax.measure.unit.NonSI.OUNCE            = uz
+javax.measure.unit.NonSI.OUNCE_LIQUID_UK  = uz_uk
+javax.measure.unit.NonSI.OUNCE_LIQUID_US  = uz
+javax.measure.unit.NonSI.POINT            = pkt
+javax.measure.unit.NonSI.ROENTGEN         = R\u00F6ntgen
+javax.measure.unit.NonSI.TON_UK           = tonne_uk
+javax.measure.unit.NonSI.TON_US           = tonne_us
+javax.measure.unit.NonSI.WEEK             = woche
+javax.measure.unit.NonSI.YEAR_CALENDAR    = jahr
+javax.measure.unit.NonSI.YEAR_SIDEREAL    = jahr_sidereal
diff --git a/src/main/java/javax/measure/unit/format/LocalFormat_en_GB.properties b/src/main/java/javax/measure/unit/format/LocalFormat_en_GB.properties
new file mode 100644
index 0000000..182fb3d
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/LocalFormat_en_GB.properties
@@ -0,0 +1,4 @@
+javax.measure.unit.NonSI.GALLON_UK=gal
+javax.measure.unit.NonSI.OUNCE_LIQUID_UK=oz
+javax.measure.unit.NonSI.GALLON_LIQUID_US=gal_us
+javax.measure.unit.NonSI.OUNCE_LIQUID_US=oz_us
diff --git a/src/main/java/javax/measure/unit/format/ParseException.java b/src/main/java/javax/measure/unit/format/ParseException.java
new file mode 100644
index 0000000..05e12b1
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/ParseException.java
@@ -0,0 +1,192 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
+package javax.measure.unit.format;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * You can modify this class to customize your error reporting
+ * mechanisms so long as you retain the public fields.
+ */
+class ParseException extends Exception {
+
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.  The boolean
+   * flag "specialConstructor" is also set to true to indicate that
+   * this constructor was used to create this object.
+   * This constructor calls its super class with the empty string
+   * to force the "toString" method of parent class "Throwable" to
+   * print the error message in the form:
+   *     ParseException: <result of getMessage>
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super("");
+    specialConstructor = true;
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
+
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
+
+  public ParseException() {
+    super();
+    specialConstructor = false;
+  }
+
+  public ParseException(String message) {
+    super(message);
+    specialConstructor = false;
+  }
+
+  /**
+   * This variable determines which constructor was used to create
+   * this object and thereby affects the semantics of the
+   * "getMessage" method (see below).
+   */
+  protected boolean specialConstructor;
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * followng this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * This method has the standard behavior when this object has been
+   * created using the standard constructors.  Otherwise, it uses
+   * "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser), then this method is called during the printing
+   * of the final stack trace, and hence the correct error message
+   * gets displayed.
+   */
+  public String getMessage() {
+    if (!specialConstructor) {
+      return super.getMessage();
+    }
+    StringBuffer expected = new StringBuffer();
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+        expected.append("...");
+      }
+      expected.append(eol).append("    ");
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) retval += " ";
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += add_escapes(tok.image);
+      tok = tok.next; 
+    }
+    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+    retval += "." + eol;
+    if (expectedTokenSequences.length == 1) {
+      retval += "Was expecting:" + eol + "    ";
+    } else {
+      retval += "Was expecting one of:" + eol + "    ";
+    }
+    retval += expected.toString();
+    return retval;
+  }
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected String eol = System.getProperty("line.separator", "\n");
+ 
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  protected String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+}
diff --git a/src/main/java/javax/measure/unit/format/Prefix.java b/src/main/java/javax/measure/unit/format/Prefix.java
new file mode 100644
index 0000000..99c39b2
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/Prefix.java
@@ -0,0 +1,81 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit.format;
+
+import java.math.BigInteger;
+import javax.measure.converter.UnitConverter;
+import javax.measure.converter.RationalConverter;
+
+/**
+ * This class represents the prefixes recognized when parsing/formatting.
+ *
+ * @version 1.0
+ */
+enum Prefix {
+
+    YOTTA(new RationalConverter(BigInteger.TEN.pow(24), BigInteger.ONE)),
+    ZETTA(new RationalConverter(BigInteger.TEN.pow(21), BigInteger.ONE)),
+    EXA(new RationalConverter(BigInteger.TEN.pow(18), BigInteger.ONE)),
+    PETA(new RationalConverter(BigInteger.TEN.pow(15), BigInteger.ONE)),
+    TERA(new RationalConverter(BigInteger.TEN.pow(12), BigInteger.ONE)),
+    GIGA(new RationalConverter(BigInteger.TEN.pow(9), BigInteger.ONE)),
+    MEGA(new RationalConverter(BigInteger.TEN.pow(6), BigInteger.ONE)),
+    KILO(new RationalConverter(BigInteger.TEN.pow(3), BigInteger.ONE)),
+    HECTO(new RationalConverter(BigInteger.TEN.pow(2), BigInteger.ONE)),
+    DEKA(new RationalConverter(BigInteger.TEN.pow(1), BigInteger.ONE)),
+    DECI(new RationalConverter( BigInteger.ONE, BigInteger.TEN.pow(1))),
+    CENTI(new RationalConverter( BigInteger.ONE, BigInteger.TEN.pow(2))),
+    MILLI(new RationalConverter( BigInteger.ONE, BigInteger.TEN.pow(3))),
+    MICRO(new RationalConverter( BigInteger.ONE, BigInteger.TEN.pow(6))),
+    NANO(new RationalConverter( BigInteger.ONE, BigInteger.TEN.pow(9))),
+    PICO(new RationalConverter( BigInteger.ONE, BigInteger.TEN.pow(12))),
+    FEMTO(new RationalConverter( BigInteger.ONE, BigInteger.TEN.pow(15))),
+    ATTO(new RationalConverter( BigInteger.ONE, BigInteger.TEN.pow(18))),
+    ZEPTO(new RationalConverter( BigInteger.ONE, BigInteger.TEN.pow(21))),
+    YOCTO(new RationalConverter( BigInteger.ONE, BigInteger.TEN.pow(24)));
+
+    private final UnitConverter _converter;
+
+    /**
+     * Creates a new prefix.
+     *
+     * @param converter the associated unit converter.
+     */
+    Prefix (UnitConverter converter) {
+        _converter = converter;
+    }
+
+    /**
+     * Returns the corresponding unit converter.
+     *
+     * @return the unit converter.
+     */
+    public UnitConverter getConverter() {
+        return _converter;
+    }
+}
diff --git a/src/main/java/javax/measure/unit/format/SimpleCharStream.java b/src/main/java/javax/measure/unit/format/SimpleCharStream.java
new file mode 100644
index 0000000..878d272
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/SimpleCharStream.java
@@ -0,0 +1,439 @@
+/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */
+package javax.measure.unit.format;
+
+/**
+ * An implementation of interface CharStream, where the stream is assumed to
+ * contain only ASCII characters (without unicode processing).
+ */
+
+class SimpleCharStream
+{
+  public static final boolean staticFlag = false;
+  int bufsize;
+  int available;
+  int tokenBegin;
+  public int bufpos = -1;
+  protected int bufline[];
+  protected int bufcolumn[];
+
+  protected int column = 0;
+  protected int line = 1;
+
+  protected boolean prevCharIsCR = false;
+  protected boolean prevCharIsLF = false;
+
+  protected java.io.Reader inputStream;
+
+  protected char[] buffer;
+  protected int maxNextCharInd = 0;
+  protected int inBuf = 0;
+  protected int tabSize = 8;
+
+  protected void setTabSize(int i) { tabSize = i; }
+  protected int getTabSize(int i) { return tabSize; }
+
+
+  protected void ExpandBuff(boolean wrapAround)
+  {
+     char[] newbuffer = new char[bufsize + 2048];
+     int newbufline[] = new int[bufsize + 2048];
+     int newbufcolumn[] = new int[bufsize + 2048];
+
+     try
+     {
+        if (wrapAround)
+        {
+           System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+           System.arraycopy(buffer, 0, newbuffer,
+                                             bufsize - tokenBegin, bufpos);
+           buffer = newbuffer;
+
+           System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+           System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+           bufline = newbufline;
+
+           System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+           System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+           bufcolumn = newbufcolumn;
+
+           maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+        }
+        else
+        {
+           System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+           buffer = newbuffer;
+
+           System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+           bufline = newbufline;
+
+           System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+           bufcolumn = newbufcolumn;
+
+           maxNextCharInd = (bufpos -= tokenBegin);
+        }
+     }
+     catch (Throwable t)
+     {
+        throw new Error(t.getMessage());
+     }
+
+
+     bufsize += 2048;
+     available = bufsize;
+     tokenBegin = 0;
+  }
+
+  protected void FillBuff() throws java.io.IOException
+  {
+     if (maxNextCharInd == available)
+     {
+        if (available == bufsize)
+        {
+           if (tokenBegin > 2048)
+           {
+              bufpos = maxNextCharInd = 0;
+              available = tokenBegin;
+           }
+           else if (tokenBegin < 0)
+              bufpos = maxNextCharInd = 0;
+           else
+              ExpandBuff(false);
+        }
+        else if (available > tokenBegin)
+           available = bufsize;
+        else if ((tokenBegin - available) < 2048)
+           ExpandBuff(true);
+        else
+           available = tokenBegin;
+     }
+
+     int i;
+     try {
+        if ((i = inputStream.read(buffer, maxNextCharInd,
+                                    available - maxNextCharInd)) == -1)
+        {
+           inputStream.close();
+           throw new java.io.IOException();
+        }
+        else
+           maxNextCharInd += i;
+        return;
+     }
+     catch(java.io.IOException e) {
+        --bufpos;
+        backup(0);
+        if (tokenBegin == -1)
+           tokenBegin = bufpos;
+        throw e;
+     }
+  }
+
+  public char BeginToken() throws java.io.IOException
+  {
+     tokenBegin = -1;
+     char c = readChar();
+     tokenBegin = bufpos;
+
+     return c;
+  }
+
+  protected void UpdateLineColumn(char c)
+  {
+     column++;
+
+     if (prevCharIsLF)
+     {
+        prevCharIsLF = false;
+        line += (column = 1);
+     }
+     else if (prevCharIsCR)
+     {
+        prevCharIsCR = false;
+        if (c == '\n')
+        {
+           prevCharIsLF = true;
+        }
+        else
+           line += (column = 1);
+     }
+
+     switch (c)
+     {
+        case '\r' :
+           prevCharIsCR = true;
+           break;
+        case '\n' :
+           prevCharIsLF = true;
+           break;
+        case '\t' :
+           column--;
+           column += (tabSize - (column % tabSize));
+           break;
+        default :
+           break;
+     }
+
+     bufline[bufpos] = line;
+     bufcolumn[bufpos] = column;
+  }
+
+  public char readChar() throws java.io.IOException
+  {
+     if (inBuf > 0)
+     {
+        --inBuf;
+
+        if (++bufpos == bufsize)
+           bufpos = 0;
+
+        return buffer[bufpos];
+     }
+
+     if (++bufpos >= maxNextCharInd)
+        FillBuff();
+
+     char c = buffer[bufpos];
+
+     UpdateLineColumn(c);
+     return (c);
+  }
+
+  /**
+   * @deprecated 
+   * @see #getEndColumn
+   */
+
+  public int getColumn() {
+     return bufcolumn[bufpos];
+  }
+
+  /**
+   * @deprecated 
+   * @see #getEndLine
+   */
+
+  public int getLine() {
+     return bufline[bufpos];
+  }
+
+  public int getEndColumn() {
+     return bufcolumn[bufpos];
+  }
+
+  public int getEndLine() {
+     return bufline[bufpos];
+  }
+
+  public int getBeginColumn() {
+     return bufcolumn[tokenBegin];
+  }
+
+  public int getBeginLine() {
+     return bufline[tokenBegin];
+  }
+
+  public void backup(int amount) {
+
+    inBuf += amount;
+    if ((bufpos -= amount) < 0)
+       bufpos += bufsize;
+  }
+
+  public SimpleCharStream(java.io.Reader dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    available = bufsize = buffersize;
+    buffer = new char[buffersize];
+    bufline = new int[buffersize];
+    bufcolumn = new int[buffersize];
+  }
+
+  public SimpleCharStream(java.io.Reader dstream, int startline,
+                          int startcolumn)
+  {
+     this(dstream, startline, startcolumn, 4096);
+  }
+
+  public SimpleCharStream(java.io.Reader dstream)
+  {
+     this(dstream, 1, 1, 4096);
+  }
+  public void ReInit(java.io.Reader dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    if (buffer == null || buffersize != buffer.length)
+    {
+      available = bufsize = buffersize;
+      buffer = new char[buffersize];
+      bufline = new int[buffersize];
+      bufcolumn = new int[buffersize];
+    }
+    prevCharIsLF = prevCharIsCR = false;
+    tokenBegin = inBuf = maxNextCharInd = 0;
+    bufpos = -1;
+  }
+
+  public void ReInit(java.io.Reader dstream, int startline,
+                     int startcolumn)
+  {
+     ReInit(dstream, startline, startcolumn, 4096);
+  }
+
+  public void ReInit(java.io.Reader dstream)
+  {
+     ReInit(dstream, 1, 1, 4096);
+  }
+  public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+  int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+  {
+     this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+  }
+
+  public SimpleCharStream(java.io.InputStream dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+     this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+  }
+
+  public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+                          int startcolumn) throws java.io.UnsupportedEncodingException
+  {
+     this(dstream, encoding, startline, startcolumn, 4096);
+  }
+
+  public SimpleCharStream(java.io.InputStream dstream, int startline,
+                          int startcolumn)
+  {
+     this(dstream, startline, startcolumn, 4096);
+  }
+
+  public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+  {
+     this(dstream, encoding, 1, 1, 4096);
+  }
+
+  public SimpleCharStream(java.io.InputStream dstream)
+  {
+     this(dstream, 1, 1, 4096);
+  }
+
+  public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+                          int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+  {
+     ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+  }
+
+  public void ReInit(java.io.InputStream dstream, int startline,
+                          int startcolumn, int buffersize)
+  {
+     ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+  }
+
+  public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+  {
+     ReInit(dstream, encoding, 1, 1, 4096);
+  }
+
+  public void ReInit(java.io.InputStream dstream)
+  {
+     ReInit(dstream, 1, 1, 4096);
+  }
+  public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+                     int startcolumn) throws java.io.UnsupportedEncodingException
+  {
+     ReInit(dstream, encoding, startline, startcolumn, 4096);
+  }
+  public void ReInit(java.io.InputStream dstream, int startline,
+                     int startcolumn)
+  {
+     ReInit(dstream, startline, startcolumn, 4096);
+  }
+  public String GetImage()
+  {
+     if (bufpos >= tokenBegin)
+        return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+     else
+        return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+                              new String(buffer, 0, bufpos + 1);
+  }
+
+  public char[] GetSuffix(int len)
+  {
+     char[] ret = new char[len];
+
+     if ((bufpos + 1) >= len)
+        System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+     else
+     {
+        System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+                                                          len - bufpos - 1);
+        System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+     }
+
+     return ret;
+  }
+
+  public void Done()
+  {
+     buffer = null;
+     bufline = null;
+     bufcolumn = null;
+  }
+
+  /**
+   * Method to adjust line and column numbers for the start of a token.
+   */
+  public void adjustBeginLineColumn(int newLine, int newCol)
+  {
+     int start = tokenBegin;
+     int len;
+
+     if (bufpos >= tokenBegin)
+     {
+        len = bufpos - tokenBegin + inBuf + 1;
+     }
+     else
+     {
+        len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+     }
+
+     int i = 0, j = 0, k = 0;
+     int nextColDiff = 0, columnDiff = 0;
+
+     while (i < len &&
+            bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+     {
+        bufline[j] = newLine;
+        nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+        bufcolumn[j] = newCol + columnDiff;
+        columnDiff = nextColDiff;
+        i++;
+     } 
+
+     if (i < len)
+     {
+        bufline[j] = newLine++;
+        bufcolumn[j] = newCol + columnDiff;
+
+        while (i++ < len)
+        {
+           if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+              bufline[j] = newLine++;
+           else
+              bufline[j] = newLine;
+        }
+     }
+
+     line = bufline[j];
+     column = bufcolumn[j];
+  }
+
+}
diff --git a/src/main/java/javax/measure/unit/format/SymbolMap.java b/src/main/java/javax/measure/unit/format/SymbolMap.java
new file mode 100644
index 0000000..818b32e
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/SymbolMap.java
@@ -0,0 +1,222 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit.format;
+
+import java.lang.reflect.Field;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.ResourceBundle;
+import javax.measure.converter.UnitConverter;
+import javax.measure.unit.Unit;
+
+/**
+ * <p> The SymbolMap class provides a set of mappings between
+ *     {@link javax.measure.unit.Unit Units} and symbols (both ways),
+ *     between {@link Prefix Prefix}es and symbols
+ *     (both ways), and from {@link javax.measure.converter.UnitConverter
+ *     UnitConverter}s to {@link Prefix Prefix}es (one way).
+ *     No attempt is made to verify the uniqueness of the mappings.</p>
+ *
+ * <p> Mappings are read from a <code>ResourceBundle</code>, the keys
+ *     of which should consist of a fully-qualified class name, followed
+ *     by a dot ('.'), and then the name of a static field belonging
+ *     to that class, followed optionally by another dot and a number.
+ *     If the trailing dot and number are not present, the value
+ *     associated with the key is treated as a
+ *     {@link SymbolMap#label(javax.measure.unit.Unit, String) label},
+ *     otherwise if the trailing dot and number are present, the value
+ *     is treated as an {@link SymbolMap#alias(javax.measure.unit.Unit,String) alias}.
+ *     Aliases map from String to Unit only, whereas labels map in both
+ *     directions. A given unit may have any number of aliases, but may
+ *     have only one label.</p>
+ * 
+ * @author <a href="mailto:eric-r at northwestern.edu">Eric Russell</a>
+ * @version 1.0
+ */
+public class SymbolMap {
+    
+    private Map<String, Unit<?>> _symbolToUnit;
+    private Map<Unit<?>, String> _unitToSymbol;
+    private Map<String, Object> _symbolToPrefix;
+    private Map<Object, String> _prefixToSymbol;
+    private Map<UnitConverter, Prefix> _converterToPrefix;
+    
+    /**
+     * Creates an empty mapping.
+     */
+    public SymbolMap () {
+        _symbolToUnit = new HashMap<String, Unit<?>>();
+        _unitToSymbol = new HashMap<Unit<?>, String>();
+        _symbolToPrefix = new HashMap<String, Object>();
+        _prefixToSymbol = new HashMap<Object, String>();
+        _converterToPrefix = new HashMap<UnitConverter, Prefix>();
+    }
+
+    /** 
+     * Creates a symbol map from the specified resource bundle,
+     *
+     * @param rb the resource bundle.
+     */
+    public SymbolMap (ResourceBundle rb) {
+        this();
+        for (Enumeration<String> i = rb.getKeys(); i.hasMoreElements();) {
+            String fqn = i.nextElement();
+            String symbol = rb.getString(fqn);
+            boolean isAlias = false;
+            int lastDot = fqn.lastIndexOf('.');
+            String className = fqn.substring(0, lastDot);
+            String fieldName = fqn.substring(lastDot+1, fqn.length());
+            if (Character.isDigit(fieldName.charAt(0))) {
+                isAlias = true;
+                fqn = className;
+                lastDot = fqn.lastIndexOf('.');
+                className = fqn.substring(0, lastDot);
+                fieldName = fqn.substring(lastDot+1, fqn.length());
+            }
+            try {
+                Class<?> c = Class.forName(className);
+                Field field = c.getField(fieldName);
+                Object value = field.get(null);
+                if (value instanceof Unit) {
+                    if (isAlias) {
+                        alias((Unit<?>)value, symbol);
+                    } else {
+                        label((Unit<?>)value, symbol);
+                    }
+                } else if (value instanceof Prefix) {
+                    label((Prefix)value, symbol);
+                } else {
+                    throw new ClassCastException("unable to cast "+value+" to Unit or Prefix");
+                }
+            } catch (Exception e) {
+                System.err.println("ERROR reading Unit names: " + e.toString());
+            }
+        }
+    }
+
+    /**
+     * Attaches a label to the specified unit. For example:[code]
+     *    symbolMap.label(DAY.multiply(365), "year");
+     *    symbolMap.label(NonSI.FOOT, "ft");
+     * [/code]
+     *
+     * @param unit the unit to label.
+     * @param symbol the new symbol for the unit.
+     */
+    public void label (Unit<?> unit, String symbol) {
+        _symbolToUnit.put(symbol, unit);
+        _unitToSymbol.put(unit, symbol);
+    }
+    
+    /**
+     * Attaches an alias to the specified unit. Multiple aliases may be
+     * attached to the same unit. Aliases are used during parsing to
+     * recognize different variants of the same unit.[code]
+     *     symbolMap.alias(NonSI.FOOT, "foot");
+     *     symbolMap.alias(NonSI.FOOT, "feet");
+     *     symbolMap.alias(SI.METER, "meter");
+     *     symbolMap.alias(SI.METER, "metre");
+     * [/code]
+     *
+     * @param unit the unit to label.
+     * @param symbol the new symbol for the unit.
+     */
+    public void alias (Unit<?> unit, String symbol) { 
+        _symbolToUnit.put(symbol, unit);
+    }
+    
+    /**
+     * Attaches a label to the specified prefix. For example:[code]
+     *    symbolMap.label(Prefix.GIGA, "G");
+     *    symbolMap.label(Prefix.MICRO, "µ");
+     * [/code]
+     */
+    public void label(Prefix prefix, String symbol) {
+        _symbolToPrefix.put(symbol, prefix);
+        _prefixToSymbol.put(prefix, symbol);
+        _converterToPrefix.put(prefix.getConverter(), prefix);
+    }
+    
+    /**
+     * Returns the unit for the specified symbol.
+     * 
+     * @param symbol the symbol.
+     * @return the corresponding unit or <code>null</code> if none.
+     */
+    public Unit<?> getUnit (String symbol) {
+        return _symbolToUnit.get(symbol);
+    }
+    
+    /**
+     * Returns the symbol (label) for the specified unit.
+     *
+     * @param unit the corresponding symbol.
+     * @return the corresponding symbol or <code>null</code> if none.
+     */
+    public String getSymbol (Unit<?> unit) {
+        return _unitToSymbol.get(unit);
+    }
+    
+    /**
+     * Returns the prefix (if any) for the specified symbol.
+     *
+     * @param symbol the unit symbol.
+     * @return the corresponding prefix or <code>null</code> if none.
+     */
+    public Prefix getPrefix (String symbol) {
+        for (Iterator<String> i = _symbolToPrefix.keySet().iterator(); i.hasNext(); ) {
+            String pfSymbol = i.next();
+            if (symbol.startsWith(pfSymbol)) {
+                return (Prefix)_symbolToPrefix.get(pfSymbol);
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * Returns the prefix for the specified converter.
+     *
+     * @param converter the unit converter.
+     * @return the corresponding prefix or <code>null</code> if none.
+     */
+    public Prefix getPrefix (UnitConverter converter) {
+        return (Prefix)_converterToPrefix.get(converter);
+    }
+    
+    /**
+     * Returns the symbol for the specified prefix.
+     *
+     * @param prefix the prefix.
+     * @return the corresponding symbol or <code>null</code> if none.
+     */
+    public String getSymbol (Prefix prefix) {
+        return _prefixToSymbol.get(prefix);
+    }
+}
diff --git a/src/main/java/javax/measure/unit/format/Token.java b/src/main/java/javax/measure/unit/format/Token.java
new file mode 100644
index 0000000..dbfd190
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/Token.java
@@ -0,0 +1,81 @@
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */
+package javax.measure.unit.format;
+
+/**
+ * Describes the input token stream.
+ */
+
+class Token {
+
+  /**
+   * An integer that describes the kind of this token.  This numbering
+   * system is determined by JavaCCParser, and a table of these numbers is
+   * stored in the file ...Constants.java.
+   */
+  public int kind;
+
+  /**
+   * beginLine and beginColumn describe the position of the first character
+   * of this token; endLine and endColumn describe the position of the
+   * last character of this token.
+   */
+  public int beginLine, beginColumn, endLine, endColumn;
+
+  /**
+   * The string image of the token.
+   */
+  public String image;
+
+  /**
+   * A reference to the next regular (non-special) token from the input
+   * stream.  If this is the last token from the input stream, or if the
+   * token manager has not read tokens beyond this one, this field is
+   * set to null.  This is true only if this token is also a regular
+   * token.  Otherwise, see below for a description of the contents of
+   * this field.
+   */
+  public Token next;
+
+  /**
+   * This field is used to access special tokens that occur prior to this
+   * token, but after the immediately preceding regular (non-special) token.
+   * If there are no such special tokens, this field is set to null.
+   * When there are more than one such special token, this field refers
+   * to the last of these special tokens, which in turn refers to the next
+   * previous special token through its specialToken field, and so on
+   * until the first special token (whose specialToken field is null).
+   * The next fields of special tokens refer to other special tokens that
+   * immediately follow it (without an intervening regular token).  If there
+   * is no such token, this field is null.
+   */
+  public Token specialToken;
+
+  /**
+   * Returns the image.
+   */
+  public String toString()
+  {
+     return image;
+  }
+
+  /**
+   * Returns a new Token object, by default. However, if you want, you
+   * can create and return subclass objects based on the value of ofKind.
+   * Simply add the cases to the switch for all those special cases.
+   * For example, if you have a subclass of Token called IDToken that
+   * you want to create if ofKind is ID, simlpy add something like :
+   *
+   *    case MyParserConstants.ID : return new IDToken();
+   *
+   * to the following switch statement. Then you can cast matchedToken
+   * variable to the appropriate type and use it in your lexical actions.
+   */
+  public static final Token newToken(int ofKind)
+  {
+     switch(ofKind)
+     {
+       default : return new Token();
+     }
+  }
+
+}
diff --git a/src/main/java/javax/measure/unit/format/TokenMgrError.java b/src/main/java/javax/measure/unit/format/TokenMgrError.java
new file mode 100644
index 0000000..8492b10
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/TokenMgrError.java
@@ -0,0 +1,133 @@
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */
+package javax.measure.unit.format;
+
+class TokenMgrError extends Error
+{
+   /*
+    * Ordinals for various reasons why an Error of this type can be thrown.
+    */
+
+   /**
+    * Lexical error occured.
+    */
+   static final int LEXICAL_ERROR = 0;
+
+   /**
+    * An attempt wass made to create a second instance of a static token manager.
+    */
+   static final int STATIC_LEXER_ERROR = 1;
+
+   /**
+    * Tried to change to an invalid lexical state.
+    */
+   static final int INVALID_LEXICAL_STATE = 2;
+
+   /**
+    * Detected (and bailed out of) an infinite loop in the token manager.
+    */
+   static final int LOOP_DETECTED = 3;
+
+   /**
+    * Indicates the reason why the exception is thrown. It will have
+    * one of the above 4 values.
+    */
+   int errorCode;
+
+   /**
+    * Replaces unprintable characters by their espaced (or unicode escaped)
+    * equivalents in the given string
+    */
+   protected static final String addEscapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+   /**
+    * Returns a detailed message for the Error when it is thrown by the
+    * token manager to indicate a lexical error.
+    * Parameters : 
+    *    EOFSeen     : indicates if EOF caused the lexicl error
+    *    curLexState : lexical state in which this error occured
+    *    errorLine   : line number when the error occured
+    *    errorColumn : column number when the error occured
+    *    errorAfter  : prefix that was seen before this error occured
+    *    curchar     : the offending character
+    * Note: You can customize the lexical error message by modifying this method.
+    */
+   protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
+      return("Lexical error at line " +
+           errorLine + ", column " +
+           errorColumn + ".  Encountered: " +
+           (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
+           "after : \"" + addEscapes(errorAfter) + "\"");
+   }
+
+   /**
+    * You can also modify the body of this method to customize your error messages.
+    * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+    * of end-users concern, so you can return something like : 
+    *
+    *     "Internal Error : Please file a bug report .... "
+    *
+    * from this method for such cases in the release version of your parser.
+    */
+   public String getMessage() {
+      return super.getMessage();
+   }
+
+   /*
+    * Constructors of various flavors follow.
+    */
+
+   public TokenMgrError() {
+   }
+
+   public TokenMgrError(String message, int reason) {
+      super(message);
+      errorCode = reason;
+   }
+
+   public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
+      this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+   }
+}
diff --git a/src/main/java/javax/measure/unit/format/UCUM.java b/src/main/java/javax/measure/unit/format/UCUM.java
new file mode 100644
index 0000000..1c24520
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UCUM.java
@@ -0,0 +1,630 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit.format;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import javax.measure.quantity.*;
+import javax.measure.unit.*;
+
+/**
+ * <p> This class contains the units ({@link SI} and {@link NonSI}) as defined
+ *     in the <a href="http://unitsofmeasure.org/">
+ *     Uniform Code for Units of Measure</a>.</p>
+ *
+ * <p> Compatability with existing {@link javax.measure.unit.SI SI}/
+ *     {@link javax.measure.unit.NonSI NonSI} units has been given
+ *     priority over strict adherence to the standard. We have attempted to note
+ *     every place where the definitions in this class deviate from the
+ *     UCUM standard, but such notes are likely to be incomplete.</p>
+ * 
+ * @author  <a href="mailto:eric-r at northwestern.edu">Eric Russell</a>
+ * @version 1.0 
+ * @see <a href="http://aurora.regenstrief.org/UCUM/ucum.html">UCUM</a>
+ */
+ at SuppressWarnings("unchecked")
+final class UCUM extends SystemOfUnits {
+
+    /** Holds collection of all UCUM units. */
+    private static HashSet<Unit<?>> UNITS = new HashSet<Unit<?>>();
+
+    /**
+     * Returns the unique instance of this class.
+     *
+     * @return the UCUM instance.
+     */
+    public static UCUM getInstance() {
+        return INSTANCE;
+    }
+    private static final UCUM INSTANCE = new UCUM();
+
+    /**
+     * Adds a new unit to the collection.
+     * @param  unit the unit being added.
+     * @return <code>unit</code>.
+     */
+    private static <U extends Unit<?>> U ucum(U unit) {
+        UNITS.add(unit);
+        return unit;
+    }
+
+    /**
+     * Default constructor (prevents this class from being instantiated).
+     */
+    private UCUM() {
+    }
+
+    /**
+     * Returns a read only view over the units defined in this class.
+     * @return the collection of SI units.
+     */
+    public Set<Unit<?>> getUnits() {
+        return Collections.unmodifiableSet(UNITS);
+    }
+    //////////////////////////////
+    // BASE UNITS: UCUM 4.2 §25 //
+    //////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final BaseUnit<Length> METER = ucum(SI.METRE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final BaseUnit<Duration> SECOND = ucum(SI.SECOND);
+    /**
+     * We deviate slightly from the standard here, to maintain compatability
+     * with the existing SI units. In UCUM, the gram is the base unit of mass,
+     * rather than the kilogram. This doesn't have much effect on the units
+     * themselves, but it does make formatting the units a challenge.
+     */
+    public static final Unit<Mass> GRAM = ucum(SI.GRAM);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final AlternateUnit<Angle> RADIAN = ucum(SI.RADIAN);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final BaseUnit<Temperature> KELVIN = ucum(SI.KELVIN);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final AlternateUnit<ElectricCharge> COULOMB = ucum(SI.COULOMB);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final BaseUnit<LuminousIntensity> CANDELA = ucum(SI.CANDELA);
+    ///////////////////////////////////////////////
+    // DIMENSIONLESS DERIVED UNITS: UCUM 4.3 §26 //
+    ///////////////////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> TRIILLIONS = ucum(Unit.ONE.times(1000000000000L));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> BILLIONS = ucum(Unit.ONE.times(1000000000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> MILLIONS = ucum(Unit.ONE.times(1000000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> THOUSANDS = ucum(Unit.ONE.times(1000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> HUNDREDS = ucum(Unit.ONE.times(100));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> PI = ucum(Unit.ONE.times(StrictMath.PI));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> PERCENT = ucum(Unit.ONE.divide(100));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> PER_THOUSAND = ucum(Unit.ONE.divide(1000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> PER_MILLION = ucum(Unit.ONE.divide(1000000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> PER_BILLION = ucum(Unit.ONE.divide(1000000000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> PER_TRILLION = ucum(Unit.ONE.divide(1000000000000L));
+    ////////////////////////////
+    // SI UNITS: UCUM 4.3 §27 //
+    ////////////////////////////
+    /**
+     * We deviate slightly from the standard here, to maintain compatability
+     * with the existing SI units. In UCUM, the mole is no longer a base unit,
+     * but is defined as <code>Unit.ONE.times(6.0221367E23)</code>.
+     */
+    public static final Unit<AmountOfSubstance> MOLE = ucum(SI.MOLE);
+    /**
+     * We deviate slightly from the standard here, to maintain compatability
+     * with the existing SI units. In UCUM, the steradian is defined as 
+     * <code>RADIAN.pow(2)</code>.
+     */
+    public static final Unit<SolidAngle> STERADIAN = ucum(SI.STERADIAN);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Frequency> HERTZ = (Unit<Frequency>) ucum(SI.HERTZ);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Force> NEWTON = ucum(SI.NEWTON);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Pressure> PASCAL = ucum(SI.PASCAL);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> JOULE = ucum(SI.JOULE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Power> WATT = ucum(SI.WATT);
+    /** 
+     * We deviate slightly from the standard here, to maintain compatability
+     * with the existing SI units. In UCUM, the ampere is defined as 
+     * <code>COULOMB.divide(SECOND)</code>.
+     */
+    public static final Unit<ElectricCurrent> AMPERE = ucum(SI.AMPERE);
+    /** 
+     * We deviate slightly from the standard here, to maintain compatability
+     * with the existing SI units. In UCUM, the volt is defined as 
+     * <code>JOULE.divide(COULOMB)</code>.
+     */
+    public static final Unit<ElectricPotential> VOLT = ucum(SI.VOLT);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<ElectricCapacitance> FARAD = ucum(SI.FARAD);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<ElectricResistance> OHM = ucum(SI.OHM);
+    /** 
+     * We deviate slightly from the standard here, to maintain compatability
+     * with the existing SI units. In UCUM, the volt is defined as 
+     * <code>Unit.ONE.divide(OHM)</code>.
+     */
+    public static final Unit<ElectricConductance> SIEMENS = ucum(SI.SIEMENS);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<MagneticFlux> WEBER = ucum(SI.WEBER);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Temperature> CELSIUS = ucum(SI.CELSIUS);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<MagneticFluxDensity> TESLA = ucum(SI.TESLA);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<ElectricInductance> HENRY = ucum(SI.HENRY);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<LuminousFlux> LUMEN = ucum(SI.LUMEN);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Illuminance> LUX = ucum(SI.LUX);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<RadioactiveActivity> BECQUEREL = ucum(SI.BECQUEREL);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<RadiationDoseAbsorbed> GRAY = ucum(SI.GRAY);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<RadiationDoseEffective> SIEVERT = ucum(SI.SIEVERT);
+    ///////////////////////////////////////////////////////////////////////
+    // OTHER UNITS FROM ISO 1000, ISO 2955, AND ANSI X3.50: UCUM 4.3 §28 //
+    ///////////////////////////////////////////////////////////////////////
+    // The order of GON and DEGREE has been inverted because GON is defined in terms of DEGREE
+    /** 
+     * We deviate slightly from the standard here, to maintain compatability
+     * with the existing NonSI units. In UCUM, the degree is defined as 
+     * <code>PI.times(RADIAN.divide(180))</code>.
+     */
+    public static final Unit<Angle> DEGREE = ucum(NonSI.DEGREE_ANGLE);
+    /** 
+     * We deviate slightly from the standard here, to maintain compatability
+     * with the existing NonSI units. In UCUM, the grade is defined as 
+     * <code>DEGREE.times(0.9)</code>.
+     */
+    public static final Unit<Angle> GRADE = ucum(NonSI.GRADE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Angle> GON = GRADE;
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Angle> MINUTE_ANGLE = ucum(NonSI.MINUTE_ANGLE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Angle> SECOND_ANGLE = ucum(NonSI.SECOND_ANGLE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> LITER = ucum(NonSI.LITRE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Area> ARE = ucum(NonSI.ARE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Duration> MINUTE = ucum(NonSI.MINUTE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Duration> HOUR = ucum(NonSI.HOUR);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Duration> DAY = ucum(NonSI.DAY);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Duration> YEAR_TROPICAL = ucum(DAY.times(365.24219));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Duration> YEAR_JULIAN = ucum(DAY.times(365.25));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Duration> YEAR_GREGORIAN = ucum(DAY.times(365.2425));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Duration> YEAR = ucum(DAY.times(365.25));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Duration> MONTH_SYNODAL = ucum(DAY.times(29.53059));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Duration> MONTH_JULIAN = ucum(YEAR_JULIAN.divide(12));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Duration> MONTH_GREGORIAN = ucum(YEAR_GREGORIAN.divide(12));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Duration> MONTH = ucum(YEAR_JULIAN.divide(12));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> TONNE = ucum(NonSI.METRIC_TON);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Pressure> BAR = ucum(NonSI.BAR);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> ATOMIC_MASS_UNIT = ucum(NonSI.ATOMIC_MASS);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> ELECTRON_VOLT = ucum(NonSI.ELECTRON_VOLT);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> ASTRONOMIC_UNIT = ucum(NonSI.ASTRONOMICAL_UNIT);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> PARSEC = ucum(NonSI.PARSEC);
+    /////////////////////////////////
+    // NATURAL UNITS: UCUM 4.3 §29 //
+    /////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Velocity> C = ucum(NonSI.C);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Action> PLANCK = (Unit<Action>) ucum(JOULE.times(SECOND).times(6.6260755E-24));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> BOLTZMAN = (Unit<Dimensionless>) ucum(JOULE.divide(KELVIN).times(1.380658E-23));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<ElectricPermittivity> PERMITTIVITY_OF_VACUUM = (Unit<ElectricPermittivity>) ucum(FARAD.divide(METER).times(8.854187817E-12));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<MagneticPermeability> PERMEABILITY_OF_VACUUM = (Unit<MagneticPermeability>) ucum(NEWTON.times(4E-7 * StrictMath.PI).divide(AMPERE.pow(2)));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<ElectricCharge> ELEMENTARY_CHARGE = ucum(NonSI.E);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> ELECTRON_MASS = ucum(NonSI.ELECTRON_MASS);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> PROTON_MASS = ucum(GRAM.times(1.6726231E-24));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> NEWTON_CONSTANT_OF_GRAVITY = (Unit<Dimensionless>) ucum(METER.pow(3).times(SI.KILOGRAM.pow(-1)).times(SECOND.pow(-2)).times(6.67259E-11));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Acceleration> ACCELLERATION_OF_FREEFALL = ucum(NonSI.G);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Pressure> ATMOSPHERE = ucum(NonSI.ATMOSPHERE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> LIGHT_YEAR = (Unit<Length>) ucum(NonSI.LIGHT_YEAR);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Force> GRAM_FORCE = (Unit<Force>) ucum(GRAM.times(ACCELLERATION_OF_FREEFALL));
+    // POUND_FORCE contains a forward reference to avoirdupois pound weight, so it has been moved after section §36 below
+    /////////////////////////////
+    // CGS UNITS: UCUM 4.3 §30 //
+    /////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Wavenumber> KAYSER = (Unit<Wavenumber>) ucum(Unit.ONE.divide(SI.CENTI(METER)));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Acceleration> GAL = (Unit<Acceleration>) ucum(SI.CENTI(METER).divide(SECOND.pow(2)));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Force> DYNE = ucum(NonSI.DYNE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> ERG = ucum(NonSI.ERG);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<DynamicViscosity> POISE = ucum(NonSI.POISE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<ElectricCurrent> BIOT = ucum(AMPERE.times(10));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<KinematicViscosity> STOKES = ucum(NonSI.STOKE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<MagneticFlux> MAXWELL = ucum(NonSI.MAXWELL);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<MagneticFluxDensity> GAUSS = ucum(NonSI.GAUSS);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<MagneticFieldStrength> OERSTED = (Unit<MagneticFieldStrength>) ucum(Unit.ONE.divide(PI).times(AMPERE).divide(METER).times(250));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<MagnetomotiveForce> GILBERT = (Unit<MagnetomotiveForce>) ucum(OERSTED.times(SI.CENTI(METER)));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Luminance> STILB = (Unit<Luminance>) ucum(CANDELA.divide(SI.CENTI(METER).pow(2)));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Illuminance> LAMBERT = ucum(NonSI.LAMBERT);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Illuminance> PHOT = ucum(LUX.divide(10000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<RadioactiveActivity> CURIE = ucum(NonSI.CURIE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<IonizingRadiation> ROENTGEN = (Unit<IonizingRadiation>) ucum(NonSI.ROENTGEN);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<RadiationDoseAbsorbed> RAD = ucum(NonSI.RAD);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<RadiationDoseEffective> REM = ucum(NonSI.REM);
+    /////////////////////////////////////////////////
+    // INTERNATIONAL CUSTOMARY UNITS: UCUM 4.4 §31 //
+    /////////////////////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> INCH_INTERNATIONAL = ucum(SI.CENTI(METER).times(254).divide(100));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> FOOT_INTERNATIONAL = ucum(INCH_INTERNATIONAL.times(12));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> YARD_INTERNATIONAL = ucum(FOOT_INTERNATIONAL.times(3));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> MILE_INTERNATIONAL = ucum(FOOT_INTERNATIONAL.times(5280));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> FATHOM_INTERNATIONAL = ucum(FOOT_INTERNATIONAL.times(6));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> NAUTICAL_MILE_INTERNATIONAL = ucum(METER.times(1852));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Velocity> KNOT_INTERNATIONAL = (Unit<Velocity>) ucum(NAUTICAL_MILE_INTERNATIONAL.divide(HOUR));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Area> SQUARE_INCH_INTERNATIONAL = (Unit<Area>) ucum(INCH_INTERNATIONAL.pow(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Area> SQUARE_FOOT_INTERNATIONAL = (Unit<Area>) ucum(FOOT_INTERNATIONAL.pow(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Area> SQUARE_YARD_INTERNATIONAL = (Unit<Area>) ucum(YARD_INTERNATIONAL.pow(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> CUBIC_INCH_INTERNATIONAL = (Unit<Volume>) ucum(INCH_INTERNATIONAL.pow(3));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> CUBIC_FOOT_INTERNATIONAL = (Unit<Volume>) ucum(FOOT_INTERNATIONAL.pow(3));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> CUBIC_YARD_INTERNATIONAL = (Unit<Volume>) ucum(YARD_INTERNATIONAL.pow(3));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> BOARD_FOOT_INTERNATIONAL = ucum(CUBIC_INCH_INTERNATIONAL.times(144));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> CORD_INTERNATIONAL = ucum(CUBIC_FOOT_INTERNATIONAL.times(128));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> MIL_INTERNATIONAL = ucum(INCH_INTERNATIONAL.divide(1000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Area> CIRCULAR_MIL_INTERNATIONAL = (Unit<Area>) ucum(MIL_INTERNATIONAL.times(PI).divide(4));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> HAND_INTERNATIONAL = ucum(INCH_INTERNATIONAL.times(4));
+    //////////////////////////////////////////
+    // US SURVEY LENGTH UNITS: UCUM 4.4 §32 //
+    //////////////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> FOOT_US_SURVEY = ucum(METER.times(1200).divide(3937));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> YARD_US_SURVEY = ucum(FOOT_US_SURVEY.times(3));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> INCH_US_SURVEY = ucum(FOOT_US_SURVEY.divide(12));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> ROD_US_SURVEY = ucum(FOOT_US_SURVEY.times(33).divide(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> CHAIN_US_SURVEY = ucum(ROD_US_SURVEY.times(4));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> LINK_US_SURVEY = ucum(CHAIN_US_SURVEY.divide(100));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> RAMDEN_CHAIN_US_SURVEY = ucum(FOOT_US_SURVEY.times(100));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> RAMDEN_LINK_US_SURVEY = ucum(CHAIN_US_SURVEY.divide(100));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> FATHOM_US_SURVEY = ucum(FOOT_US_SURVEY.times(6));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> FURLONG_US_SURVEY = ucum(ROD_US_SURVEY.times(40));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> MILE_US_SURVEY = ucum(FURLONG_US_SURVEY.times(8));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Area> ACRE_US_SURVEY = (Unit<Area>) ucum(ROD_US_SURVEY.pow(2).times(160));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Area> SQUARE_ROD_US_SURVEY = (Unit<Area>) ucum(ROD_US_SURVEY.pow(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Area> SQUARE_MILE_US_SURVEY = (Unit<Area>) ucum(MILE_US_SURVEY.pow(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Area> SECTION_US_SURVEY = (Unit<Area>) ucum(MILE_US_SURVEY.pow(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Area> TOWNSHP_US_SURVEY = (Unit<Area>) ucum(SECTION_US_SURVEY.times(36));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> MIL_US_SURVEY = ucum(INCH_US_SURVEY.divide(1000));
+    /////////////////////////////////////////////////
+    // BRITISH IMPERIAL LENGTH UNITS: UCUM 4.4 §33 //
+    /////////////////////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> INCH_BRITISH = ucum(SI.CENTI(METER).times(2539998).divide(1000000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> FOOT_BRITISH = ucum(INCH_BRITISH.times(12));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> ROD_BRITISH = ucum(FOOT_BRITISH.times(33).divide(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> CHAIN_BRITISH = ucum(ROD_BRITISH.times(4));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> LINK_BRITISH = ucum(CHAIN_BRITISH.divide(100));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> FATHOM_BRITISH = ucum(FOOT_BRITISH.times(6));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> PACE_BRITISH = ucum(FOOT_BRITISH.times(5).divide(20));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> YARD_BRITISH = ucum(FOOT_BRITISH.times(3));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> MILE_BRITISH = ucum(FOOT_BRITISH.times(5280));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> NAUTICAL_MILE_BRITISH = ucum(FOOT_BRITISH.times(6080));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> KNOT_BRITISH = (Unit<Length>) ucum(NAUTICAL_MILE_BRITISH.divide(HOUR));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Area> ACRE_BRITISH = (Unit<Area>) ucum(YARD_BRITISH.pow(2).times(4840));
+    ///////////////////////////////////
+    // US VOLUME UNITS: UCUM 4.4 §34 //
+    ///////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> GALLON_US = ucum(CUBIC_INCH_INTERNATIONAL.times(231));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> BARREL_US = ucum(GALLON_US.times(42));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> QUART_US = ucum(GALLON_US.divide(4));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> PINT_US = ucum(QUART_US.divide(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> GILL_US = ucum(PINT_US.divide(4));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> FLUID_OUNCE_US = ucum(GILL_US.divide(4));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> FLUID_DRAM_US = ucum(FLUID_OUNCE_US.divide(8));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> MINIM_US = ucum(FLUID_DRAM_US.divide(60));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> CORD_US = ucum(CUBIC_FOOT_INTERNATIONAL.times(128));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> BUSHEL_US = ucum(CUBIC_INCH_INTERNATIONAL.times(215042).divide(100));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> GALLON_WINCHESTER = ucum(BUSHEL_US.divide(8));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> PECK_US = ucum(BUSHEL_US.divide(4));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> DRY_QUART_US = ucum(PECK_US.divide(8));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> DRY_PINT_US = ucum(DRY_QUART_US.divide(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> TABLESPOON_US = ucum(FLUID_OUNCE_US.divide(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> TEASPOON_US = ucum(TABLESPOON_US.divide(3));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> CUP_US = ucum(TABLESPOON_US.times(16));
+    /////////////////////////////////////////////////
+    // BRITISH IMPERIAL VOLUME UNITS: UCUM 4.4 §35 //
+    /////////////////////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> GALLON_BRITISH = ucum(LITER.times(454609).divide(100000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> PECK_BRITISH = ucum(GALLON_BRITISH.times(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> BUSHEL_BRITISH = ucum(PECK_BRITISH.times(4));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> QUART_BRITISH = ucum(GALLON_BRITISH.divide(4));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> PINT_BRITISH = ucum(QUART_BRITISH.divide(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> GILL_BRITISH = ucum(PINT_BRITISH.divide(4));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> FLUID_OUNCE_BRITISH = ucum(GILL_BRITISH.divide(5));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> FLUID_DRAM_BRITISH = ucum(FLUID_OUNCE_BRITISH.divide(8));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> MINIM_BRITISH = ucum(FLUID_DRAM_BRITISH.divide(60));
+    ////////////////////////////////////////////
+    // AVOIRDUPOIS WIEGHT UNITS: UCUM 4.4 §36 //
+    ////////////////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> GRAIN = ucum(SI.MILLI(GRAM).times(6479891).divide(100000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> POUND = ucum(GRAM.times(7000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> OUNCE = ucum(POUND.divide(16));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> DRAM = ucum(OUNCE.divide(16));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> SHORT_HUNDREDWEIGHT = ucum(POUND.times(100));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> LONG_HUNDREDWEIGHT = ucum(POUND.times(112));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> SHORT_TON = ucum(SHORT_HUNDREDWEIGHT.times(20));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> LONG_TON = ucum(LONG_HUNDREDWEIGHT.times(20));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> STONE = ucum(POUND.times(14));
+    // CONTINUED FROM SECTION §29
+    // contains a forward reference to POUND, so we had to move it here, below section §36
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Force> POUND_FORCE = (Unit<Force>) ucum(POUND.times(ACCELLERATION_OF_FREEFALL));
+    /////////////////////////////////////
+    // TROY WIEGHT UNITS: UCUM 4.4 §37 //
+    /////////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> PENNYWEIGHT_TROY = ucum(GRAIN.times(24));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> OUNCE_TROY = ucum(PENNYWEIGHT_TROY.times(24));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> POUND_TROY = ucum(OUNCE_TROY.times(12));
+    /////////////////////////////////////////////
+    // APOTECARIES' WEIGHT UNITS: UCUM 4.4 §38 //
+    /////////////////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> SCRUPLE_APOTHECARY = ucum(GRAIN.times(20));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> DRAM_APOTHECARY = ucum(SCRUPLE_APOTHECARY.times(3));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> OUNCE_APOTHECARY = ucum(DRAM_APOTHECARY.times(8));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> POUND_APOTHECARY = ucum(OUNCE_APOTHECARY.times(12));
+    /////////////////////////////////////////////
+    // TYPESETTER'S LENGTH UNITS: UCUM 4.4 §39 //
+    /////////////////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> LINE = ucum(INCH_INTERNATIONAL.divide(12));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> POINT = ucum(LINE.divide(6));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> PICA = ucum(POINT.times(12));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> POINT_PRINTER = ucum(INCH_INTERNATIONAL.times(13837).divide(1000000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> PICA_PRINTER = ucum(POINT_PRINTER.times(12));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> PIED = ucum(SI.CENTI(METER).times(3248).divide(100));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> POUCE = ucum(PIED.divide(12));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> LINGE = ucum(POUCE.divide(12));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> DIDOT = ucum(LINGE.divide(6));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> CICERO = ucum(DIDOT.times(12));
+    //////////////////////////////////////
+    // OTHER LEGACY UNITS: UCUM 4.5 §40 //
+    //////////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Temperature> FAHRENHEIT = ucum(KELVIN.times(5).divide(9).plus(459.67));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> CALORIE_AT_15C = ucum(JOULE.times(41858).divide(10000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> CALORIE_AT_20C = ucum(JOULE.times(41819).divide(10000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> CALORIE_MEAN = ucum(JOULE.times(419002).divide(100000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> CALORIE_INTERNATIONAL_TABLE = ucum(JOULE.times(41868).divide(10000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> CALORIE_THERMOCHEMICAL = ucum(JOULE.times(4184).divide(1000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> CALORIE = ucum(CALORIE_THERMOCHEMICAL);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> CALORIE_FOOD = ucum(SI.KILO(CALORIE_THERMOCHEMICAL));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> BTU_AT_39F = ucum(SI.KILO(JOULE).times(105967).divide(100000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> BTU_AT_59F = ucum(SI.KILO(JOULE).times(105480).divide(100000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> BTU_AT_60F = ucum(SI.KILO(JOULE).times(105468).divide(100000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> BTU_MEAN = ucum(SI.KILO(JOULE).times(105587).divide(100000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> BTU_INTERNATIONAL_TABLE = ucum(SI.KILO(JOULE).times(105505585262L).divide(100000000000L));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> BTU_THERMOCHEMICAL = ucum(SI.KILO(JOULE).times(105735).divide(100000));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Energy> BTU = ucum(BTU_THERMOCHEMICAL);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Power> HORSEPOWER = (Unit<Power>) ucum(FOOT_INTERNATIONAL.times(POUND_FORCE).divide(SECOND));
+    /////////////////////////////////////////////////////////
+    // SECTIONS §41-§43 skipped; implement later if needed //
+    /////////////////////////////////////////////////////////
+    ///////////////////////////////////////
+    // MISCELLANEOUS UNITS: UCUM 4.5 §44 //
+    ///////////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Volume> STERE = (Unit<Volume>) ucum(METER.pow(3));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Length> ANGSTROM = ucum(SI.NANO(METER).divide(10));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Area> BARN = (Unit<Area>) ucum(SI.FEMTO(METER).pow(2).times(100));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Pressure> ATMOSPHERE_TECHNICAL = (Unit<Pressure>) ucum(SI.KILO(GRAM_FORCE).divide(SI.CENTI(METER).pow(2)));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<ElectricConductance> MHO = ucum(SIEMENS.alternate("mho").asType(ElectricConductance.class));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Pressure> POUND_PER_SQUARE_INCH = (Unit<Pressure>) ucum(POUND_FORCE.divide(INCH_INTERNATIONAL.pow(2)));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Pressure> CIRCLE = (Unit<Pressure>) ucum(PI.times(RADIAN).times(2));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Pressure> SPHERE = (Unit<Pressure>) ucum(PI.times(STERADIAN).times(4));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Mass> CARAT_METRIC = ucum(GRAM.divide(5));
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<Dimensionless> CARAT_GOLD = ucum(Unit.ONE.divide(24));
+    ////////////////////////////////////////////////
+    // INFORMATION TECHNOLOGY UNITS: UCUM 4.6 §45 //
+    ////////////////////////////////////////////////
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<DataAmount> BIT = ucum(SI.BIT);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<DataAmount> BYTE = ucum(NonSI.BYTE);
+    /** As per <a href="http://unitsofmeasure.org/">UCUM</a> standard. */
+    public static final Unit<DataRate> BAUD = (Unit<DataRate>) ucum(Unit.ONE.divide(SECOND));
+}
diff --git a/src/main/java/javax/measure/unit/format/UCUMFormat.java b/src/main/java/javax/measure/unit/format/UCUMFormat.java
new file mode 100644
index 0000000..64cd8f7
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UCUMFormat.java
@@ -0,0 +1,405 @@
+/*
+ * JScience - Java Tools and Libraries for the Advancement of Sciences
+ * Copyright (c) 2005-2009, JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package javax.measure.unit.format;
+
+import javax.measure.unit.UnitFormat;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.text.*;
+import java.util.ResourceBundle;
+import javax.measure.converter.MultiplyConverter;
+import javax.measure.converter.RationalConverter;
+import javax.measure.converter.UnitConverter;
+import javax.measure.unit.*;
+import javax.measure.quantity.Quantity;
+
+/**
+ * <p>
+ * This class provides the interface for formatting and parsing
+ * {@link javax.measure.unit.Unit units} according to the <a
+ * href="http://unitsofmeasure.org/">Uniform Code for Units of Measure</a>
+ * (UCUM).
+ * </p>
+ * 
+ * <p>
+ * For a technical/historical overview of this format please read <a
+ * href="http://www.pubmedcentral.nih.gov/articlerender.fcgi?artid=61354"> Units
+ * of Measure in Clinical Information Systems</a>.
+ * </p>
+ * 
+ * <p>
+ * As of revision 1.16, the BNF in the UCUM standard contains an <a
+ * href="http://unitsofmeasure.org/ticket/4">error</a>. I've attempted to work
+ * around the problem by modifying the BNF productions for <Term>. Once
+ * the error in the standard is corrected, it may be necessary to modify the
+ * productions in the UCUMParser.jj file to conform to the standard.
+ * </p>
+ * 
+ * @author <a href="mailto:eric-r at northwestern.edu">Eric Russell</a>
+ * @version 1.0
+ */
+public abstract class UCUMFormat extends UnitFormat {
+
+	// /////////////////
+	// Class methods //
+	// /////////////////
+	/** Returns the instance for formatting using "print" symbols */
+	public static UCUMFormat getPrintInstance() {
+		return Print.DEFAULT;
+	}
+
+	/** Returns the instance for formatting using user defined symbols */
+	public static UCUMFormat getPrintInstance(SymbolMap symbolMap) {
+		return new Print(symbolMap);
+	}
+
+	/**
+	 * Returns the instance for formatting and parsing using case sensitive
+	 * symbols
+	 */
+	public static UCUMFormat getCaseSensitiveInstance() {
+		return Parsing.DEFAULT_CS;
+	}
+
+	/**
+	 * Returns a case sensitive instance for formatting and parsing using user
+	 * defined symbols
+	 */
+	public static UCUMFormat getCaseSensitiveInstance(SymbolMap symbolMap) {
+		return new Parsing(symbolMap, true);
+	}
+
+	/**
+	 * Returns the instance for formatting and parsing using case insensitive
+	 * symbols
+	 */
+	public static UCUMFormat getCaseInsensitiveInstance() {
+		return Parsing.DEFAULT_CI;
+	}
+
+	/**
+	 * Returns a case insensitive instance for formatting and parsing using user
+	 * defined symbols
+	 */
+	public static UCUMFormat getCaseInsensitiveInstance(SymbolMap symbolMap) {
+		return new Parsing(symbolMap, false);
+	}
+
+	/**
+	 * The symbol map used by this instance to map between
+	 * {@link javax.measure.unit.Unit Unit}s and <code>String</code>s.
+	 */
+	final SymbolMap _symbolMap;
+
+	// ////////////////
+	// Constructors //
+	// ////////////////
+	/**
+	 * Base constructor.
+	 */
+	UCUMFormat(SymbolMap symbolMap) {
+		_symbolMap = symbolMap;
+	}
+
+	// //////////////
+	// Formatting //
+	// //////////////
+	public Appendable format(Unit<?> unit, Appendable appendable)
+			throws IOException {
+		CharSequence symbol;
+		CharSequence annotation = null;
+		if (unit instanceof AnnotatedUnit) {
+			unit = ((AnnotatedUnit<?>) unit).getRealUnit();
+			annotation = ((AnnotatedUnit<?>) unit).getAnnotation();
+		}
+		String mapSymbol = _symbolMap.getSymbol(unit);
+		if (mapSymbol != null) {
+			symbol = mapSymbol;
+		} else if (unit instanceof ProductUnit) {
+			ProductUnit<?> productUnit = (ProductUnit<?>) unit;
+			StringBuffer app = new StringBuffer();
+			for (int i = 0; i < productUnit.getUnitCount(); i++) {
+				if (productUnit.getUnitRoot(i) != 1) {
+					throw new IllegalArgumentException(
+							"Unable to format units in UCUM (fractional powers not supported)");
+				}
+				StringBuffer temp = new StringBuffer();
+				temp = (StringBuffer) format(productUnit.getUnit(i), temp);
+				if ((temp.indexOf(".") >= 0) || (temp.indexOf("/") >= 0)) {
+					temp.insert(0, '(');
+					temp.append(')');
+				}
+				int pow = productUnit.getUnitPow(i);
+				if (i > 0) {
+					if (pow >= 0) {
+						app.append('.');
+					} else if (i < (productUnit.getUnitCount() - 1)) {
+						app.append('.');
+					} else {
+						app.append('/');
+						pow = -pow;
+					}
+				} else if (pow < 0) {
+					app.append('/');
+					pow = -pow;
+				}
+				app.append(temp);
+				if (pow != 1) {
+					app.append(Integer.toString(pow));
+				}
+			}
+			symbol = app;
+		} else if ((unit instanceof TransformedUnit)
+				|| unit.equals(SI.KILOGRAM)) {
+			StringBuffer temp = new StringBuffer();
+			UnitConverter converter;
+			boolean printSeparator;
+			if (unit.equals(SI.KILOGRAM)) {
+				// A special case because KILOGRAM is a BaseUnit instead of
+				// a transformed unit, for compatability with existing SI
+				// unit system.
+				temp = format(UCUM.GRAM, temp, new FieldPosition(0));
+				converter = Prefix.KILO.getConverter();
+				printSeparator = true;
+			} else {
+				TransformedUnit<?> transformedUnit = (TransformedUnit<?>) unit;
+				Unit<?> parentUnits = transformedUnit.getParentUnit();
+				converter = transformedUnit.toParentUnit();
+				if (parentUnits.equals(SI.KILOGRAM)) {
+					// More special-case hackery to work around gram/kilogram
+					// incosistency
+					parentUnits = UCUM.GRAM;
+					converter = converter.concatenate(Prefix.KILO
+							.getConverter());
+				}
+				temp = format(parentUnits, temp, new FieldPosition(0));
+				printSeparator = !parentUnits.equals(Unit.ONE);
+			}
+			formatConverter(converter, printSeparator, temp);
+			symbol = temp;
+		} else if (unit instanceof BaseUnit) {
+			symbol = ((BaseUnit<?>) unit).getSymbol();
+		} else if (unit instanceof AlternateUnit) {
+			symbol = ((AlternateUnit<?>) unit).getSymbol();
+		} else {
+			throw new IllegalArgumentException(
+					"Cannot format the given Object as UCUM units (unsupported unit "
+							+ unit.getClass().getName()
+							+ "). "
+							+ "Custom units types should override the toString() method as the default implementation uses the UCUM format.");
+		}
+
+		appendable.append(symbol);
+		if (annotation != null && annotation.length() > 0) {
+			appendAnnotation(unit, symbol, annotation, appendable);
+		}
+
+		return appendable;
+	}
+
+	void appendAnnotation(Unit<?> unit, CharSequence symbol,
+			CharSequence annotation, Appendable appendable) throws IOException {
+		appendable.append('{');
+		appendable.append(annotation);
+		appendable.append('}');
+	}
+
+	/**
+	 * Formats the given converter to the given StringBuffer. This is similar to
+	 * what {@link ConverterFormat} does, but there's no need to worry about
+	 * operator precedence here, since UCUM only supports multiplication,
+	 * division, and exponentiation and expressions are always evaluated left-
+	 * to-right.
+	 * 
+	 * @param converter
+	 *            the converter to be formatted
+	 * @param continued
+	 *            <code>true</code> if the converter expression should begin
+	 *            with an operator, otherwise <code>false</code>. This will
+	 *            always be true unless the unit being modified is equal to
+	 *            Unit.ONE.
+	 * @param buffer
+	 *            the <code>StringBuffer</code> to append to. Contains the
+	 *            already-formatted unit being modified by the given converter.
+	 */
+	void formatConverter(UnitConverter converter, boolean continued,
+			StringBuffer buffer) {
+		boolean unitIsExpression = ((buffer.indexOf(".") >= 0) || (buffer
+				.indexOf("/") >= 0));
+		Prefix prefix = _symbolMap.getPrefix(converter);
+		if ((prefix != null) && (!unitIsExpression)) {
+			buffer.insert(0, _symbolMap.getSymbol(prefix));
+		} else if (converter == UnitConverter.IDENTITY) {
+			// do nothing
+		} else if (converter instanceof MultiplyConverter) {
+			if (unitIsExpression) {
+				buffer.insert(0, '(');
+				buffer.append(')');
+			}
+			MultiplyConverter multiplyConverter = (MultiplyConverter) converter;
+			double factor = multiplyConverter.getFactor();
+			long lFactor = (long) factor;
+			if ((lFactor != factor) || (lFactor < -9007199254740992L)
+					|| (lFactor > 9007199254740992L)) {
+				throw new IllegalArgumentException(
+						"Only integer factors are supported in UCUM");
+			}
+			if (continued) {
+				buffer.append('.');
+			}
+			buffer.append(lFactor);
+		} else if (converter instanceof RationalConverter) {
+			if (unitIsExpression) {
+				buffer.insert(0, '(');
+				buffer.append(')');
+			}
+			RationalConverter rationalConverter = (RationalConverter) converter;
+			if (!rationalConverter.getDividend().equals(BigInteger.ONE)) {
+				if (continued) {
+					buffer.append('.');
+				}
+				buffer.append(rationalConverter.getDividend());
+			}
+			if (!rationalConverter.getDivisor().equals(BigInteger.ONE)) {
+				buffer.append('/');
+				buffer.append(rationalConverter.getDivisor());
+			}
+		} else {
+			throw new IllegalArgumentException(
+					"Unable to format units in UCUM (unsupported UnitConverter "
+							+ converter + ")");
+		}
+	}
+
+	// /////////////////
+	// Inner classes //
+	// /////////////////
+	/**
+	 * The Print format is used to output units according to the "print" column
+	 * in the UCUM standard. Because "print" symbols in UCUM are not unique,
+	 * this class of UCUMFormat may not be used for parsing, only for
+	 * formatting.
+	 */
+	private static class Print extends UCUMFormat {
+
+		private static final SymbolMap PRINT_SYMBOLS = new SymbolMap(
+				ResourceBundle
+						.getBundle("javax.measure.unit.format.UCUM_Print"));
+		private static final Print DEFAULT = new Print(PRINT_SYMBOLS);
+
+		public Print(SymbolMap symbols) {
+			super(symbols);
+		}
+
+		@Override
+		public Unit<? extends Quantity> parse(CharSequence csq,
+				ParsePosition pos) throws IllegalArgumentException {
+			throw new UnsupportedOperationException(
+					"The print format is for pretty-printing of units only. Parsing is not supported.");
+		}
+
+		@Override
+		void appendAnnotation(Unit<?> unit, CharSequence symbol,
+				CharSequence annotation, Appendable appendable)
+				throws IOException {
+			if (symbol != null && symbol.length() > 0) {
+				appendable.append('(');
+				appendable.append(annotation);
+				appendable.append(')');
+			} else {
+				appendable.append(annotation);
+			}
+		}
+
+		private static final long serialVersionUID = 1L;
+
+	}
+
+	/**
+	 * The Parsing format outputs formats and parses units according to the
+	 * "c/s" or "c/i" column in the UCUM standard, depending on which SymbolMap
+	 * is passed to its constructor.
+	 */
+	private static class Parsing extends UCUMFormat {
+
+		private static final SymbolMap CASE_SENSITIVE_SYMBOLS = new SymbolMap(
+				ResourceBundle.getBundle("javax.measure.unit.format.UCUM_CS"));
+		private static final SymbolMap CASE_INSENSITIVE_SYMBOLS = new SymbolMap(
+				ResourceBundle.getBundle("javax.measure.unit.format.UCUM_CI"));
+		private static final Parsing DEFAULT_CS = new Parsing(
+				CASE_SENSITIVE_SYMBOLS, true);
+		private static final Parsing DEFAULT_CI = new Parsing(
+				CASE_INSENSITIVE_SYMBOLS, false);
+		private final boolean _caseSensitive;
+
+		public Parsing(SymbolMap symbols, boolean caseSensitive) {
+			super(symbols);
+			_caseSensitive = caseSensitive;
+		}
+
+		@Override
+		public Unit<? extends Quantity> parse(CharSequence csq,
+				ParsePosition cursor) throws IllegalArgumentException {
+			// Parsing reads the whole character sequence from the parse
+			// position.
+			int start = cursor.getIndex();
+			int end = csq.length();
+			if (end <= start)
+				return Unit.ONE;
+			String source = csq.subSequence(start, end).toString().trim();
+			if (source.length() == 0)
+				return Unit.ONE;
+			if (!_caseSensitive) {
+				source = source.toUpperCase();
+			}
+			UCUMParser parser = new UCUMParser(_symbolMap,
+					new ByteArrayInputStream(source.getBytes()));
+			try {
+				Unit<?> result = parser.parseUnit();
+				cursor.setIndex(end);
+				return result;
+			} catch (javax.measure.unit.format.ParseException e) {
+				if (e.currentToken != null) {
+					cursor.setErrorIndex(start + e.currentToken.endColumn);
+				} else {
+					cursor.setErrorIndex(start);
+				}
+				throw new IllegalArgumentException(e.getMessage());
+			} catch (TokenMgrError e) {
+				cursor.setErrorIndex(start);
+				throw new IllegalArgumentException(e.getMessage());
+			}
+		}
+
+		private static final long serialVersionUID = 1L;
+
+	}
+
+	private static final long serialVersionUID = 1L;
+}
diff --git a/src/main/java/javax/measure/unit/format/UCUMParser.java b/src/main/java/javax/measure/unit/format/UCUMParser.java
new file mode 100644
index 0000000..ef506a3
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UCUMParser.java
@@ -0,0 +1,496 @@
+/* Generated By:JavaCC: Do not edit this line. UCUMParser.java */
+package javax.measure.unit.format;
+
+import javax.measure.unit.AnnotatedUnit;
+
+/**
+ * <p> 
+ * Parser definition for parsing {@link javax.measure.unit.Unit Unit}s 
+ * according to the <a href="http://aurora.regenstrief.org/UCUM/ucum.html">
+ * Uniform Code for Units of Measure</a>.
+ * 
+ * @author <a href="mailto:eric-r at northwestern.edu">Eric Russell</a>
+ * @version 1.0
+ * @see <a href="http://aurora.regenstrief.org/UCUM/ucum.html">UCUM</a>
+ */
+class UCUMParser implements UCUMParserConstants {
+
+    private SymbolMap _symbols;
+
+    public UCUMParser (SymbolMap symbols, java.io.InputStream in) {
+        this(in);
+        _symbols = symbols;
+    }
+
+//
+// Parser productions
+//
+  final public javax.measure.unit.Unit parseUnit() throws ParseException {
+        javax.measure.unit.Unit u;
+    u = Term();
+    jj_consume_token(0);
+      {if (true) return u;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public javax.measure.unit.Unit Term() throws ParseException {
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        javax.measure.unit.Unit temp = javax.measure.unit.Unit.ONE;
+    result = Component();
+    label_1:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case DOT:
+      case SOLIDUS:
+        ;
+        break;
+      default:
+        jj_la1[0] = jj_gen;
+        break label_1;
+      }
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case DOT:
+        jj_consume_token(DOT);
+        temp = Component();
+                                result = result.times(temp);
+        break;
+      case SOLIDUS:
+        jj_consume_token(SOLIDUS);
+        temp = Component();
+                                    result = result.divide(temp);
+        break;
+      default:
+        jj_la1[1] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+        {if (true) return result;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public javax.measure.unit.Unit Component() throws ParseException {
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        Token token = null;
+    if (jj_2_1(2147483647)) {
+      result = Annotatable();
+      token = jj_consume_token(ANNOTATION);
+        {if (true) return new AnnotatedUnit(result, token.image.substring(1, token.image.length()-1));}
+    } else {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case ATOM:
+        result = Annotatable();
+        {if (true) return result;}
+        break;
+      case ANNOTATION:
+        token = jj_consume_token(ANNOTATION);
+        {if (true) return new AnnotatedUnit(result, token.image.substring(1, token.image.length()-1));}
+        break;
+      case FACTOR:
+        token = jj_consume_token(FACTOR);
+        long factor = Long.parseLong(token.image);
+        {if (true) return result.times(factor);}
+        break;
+      case SOLIDUS:
+        jj_consume_token(SOLIDUS);
+        result = Component();
+        {if (true) return javax.measure.unit.Unit.ONE.divide(result);}
+        break;
+      case 14:
+        jj_consume_token(14);
+        result = Term();
+        jj_consume_token(15);
+        {if (true) return result;}
+        break;
+      default:
+        jj_la1[2] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public javax.measure.unit.Unit Annotatable() throws ParseException {
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        Token token1 = null;
+        Token token2 = null;
+    if (jj_2_2(2147483647)) {
+      result = SimpleUnit();
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case SIGN:
+        token1 = jj_consume_token(SIGN);
+        break;
+      default:
+        jj_la1[3] = jj_gen;
+        ;
+      }
+      token2 = jj_consume_token(FACTOR);
+        int exponent = Integer.parseInt(token2.image);
+        if ((token1 != null) && token1.image.equals("-")) {
+            {if (true) return result.pow(-exponent);}
+        } else {
+            {if (true) return result.pow(exponent);}
+        }
+    } else {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case ATOM:
+        result = SimpleUnit();
+        {if (true) return result;}
+        break;
+      default:
+        jj_la1[4] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public javax.measure.unit.Unit SimpleUnit() throws ParseException {
+        Token token = null;
+    token = jj_consume_token(ATOM);
+        javax.measure.unit.Unit unit = _symbols.getUnit(token.image);
+        if (unit == null) {
+            Prefix prefix = _symbols.getPrefix(token.image);
+            if (prefix != null) {
+                String prefixSymbol = _symbols.getSymbol(prefix);
+                unit = _symbols.getUnit(token.image.substring(prefixSymbol.length()));
+                if (unit != null) {
+                    {if (true) return unit.transform(prefix.getConverter());}
+                }
+            }
+            {if (true) throw new ParseException();}
+        } else {
+            {if (true) return unit;}
+        }
+    throw new Error("Missing return statement in function");
+  }
+
+  final private boolean jj_2_1(int xla) {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_1(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(0, xla); }
+  }
+
+  final private boolean jj_2_2(int xla) {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_2(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(1, xla); }
+  }
+
+  final private boolean jj_3R_3() {
+    if (jj_scan_token(ATOM)) return true;
+    return false;
+  }
+
+  final private boolean jj_3_1() {
+    if (jj_3R_2()) return true;
+    if (jj_scan_token(ANNOTATION)) return true;
+    return false;
+  }
+
+  final private boolean jj_3R_2() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_4()) {
+    jj_scanpos = xsp;
+    if (jj_3R_5()) return true;
+    }
+    return false;
+  }
+
+  final private boolean jj_3R_5() {
+    if (jj_3R_3()) return true;
+    return false;
+  }
+
+  final private boolean jj_3R_4() {
+    if (jj_3R_3()) return true;
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(10)) jj_scanpos = xsp;
+    if (jj_scan_token(FACTOR)) return true;
+    return false;
+  }
+
+  final private boolean jj_3_2() {
+    if (jj_3R_3()) return true;
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(10)) jj_scanpos = xsp;
+    if (jj_scan_token(FACTOR)) return true;
+    return false;
+  }
+
+  public UCUMParserTokenManager token_source;
+  SimpleCharStream jj_input_stream;
+  public Token token, jj_nt;
+  private int jj_ntk;
+  private Token jj_scanpos, jj_lastpos;
+  private int jj_la;
+  public boolean lookingAhead = false;
+  private boolean jj_semLA;
+  private int jj_gen;
+  final private int[] jj_la1 = new int[5];
+  static private int[] jj_la1_0;
+  static {
+      jj_la1_0();
+   }
+   private static void jj_la1_0() {
+      jj_la1_0 = new int[] {0x1800,0x1800,0x7300,0x400,0x2000,};
+   }
+  final private JJCalls[] jj_2_rtns = new JJCalls[2];
+  private boolean jj_rescan = false;
+  private int jj_gc = 0;
+
+  public UCUMParser(java.io.InputStream stream) {
+     this(stream, null);
+  }
+  public UCUMParser(java.io.InputStream stream, String encoding) {
+    try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+    token_source = new UCUMParserTokenManager(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 5; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public void ReInit(java.io.InputStream stream) {
+     ReInit(stream, null);
+  }
+  public void ReInit(java.io.InputStream stream, String encoding) {
+    try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+    token_source.ReInit(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 5; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public UCUMParser(java.io.Reader stream) {
+    jj_input_stream = new SimpleCharStream(stream, 1, 1);
+    token_source = new UCUMParserTokenManager(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 5; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public void ReInit(java.io.Reader stream) {
+    jj_input_stream.ReInit(stream, 1, 1);
+    token_source.ReInit(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 5; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public UCUMParser(UCUMParserTokenManager tm) {
+    token_source = tm;
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 5; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public void ReInit(UCUMParserTokenManager tm) {
+    token_source = tm;
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 5; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  final private Token jj_consume_token(int kind) throws ParseException {
+    Token oldToken;
+    if ((oldToken = token).next != null) token = token.next;
+    else token = token.next = token_source.getNextToken();
+    jj_ntk = -1;
+    if (token.kind == kind) {
+      jj_gen++;
+      if (++jj_gc > 100) {
+        jj_gc = 0;
+        for (int i = 0; i < jj_2_rtns.length; i++) {
+          JJCalls c = jj_2_rtns[i];
+          while (c != null) {
+            if (c.gen < jj_gen) c.first = null;
+            c = c.next;
+          }
+        }
+      }
+      return token;
+    }
+    token = oldToken;
+    jj_kind = kind;
+    throw generateParseException();
+  }
+
+  static private final class LookaheadSuccess extends java.lang.Error { }
+  final private LookaheadSuccess jj_ls = new LookaheadSuccess();
+  final private boolean jj_scan_token(int kind) {
+    if (jj_scanpos == jj_lastpos) {
+      jj_la--;
+      if (jj_scanpos.next == null) {
+        jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken();
+      } else {
+        jj_lastpos = jj_scanpos = jj_scanpos.next;
+      }
+    } else {
+      jj_scanpos = jj_scanpos.next;
+    }
+    if (jj_rescan) {
+      int i = 0; Token tok = token;
+      while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; }
+      if (tok != null) jj_add_error_token(kind, i);
+    }
+    if (jj_scanpos.kind != kind) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls;
+    return false;
+  }
+
+  final public Token getNextToken() {
+    if (token.next != null) token = token.next;
+    else token = token.next = token_source.getNextToken();
+    jj_ntk = -1;
+    jj_gen++;
+    return token;
+  }
+
+  final public Token getToken(int index) {
+    Token t = lookingAhead ? jj_scanpos : token;
+    for (int i = 0; i < index; i++) {
+      if (t.next != null) t = t.next;
+      else t = t.next = token_source.getNextToken();
+    }
+    return t;
+  }
+
+  final private int jj_ntk() {
+    if ((jj_nt=token.next) == null)
+      return (jj_ntk = (token.next=token_source.getNextToken()).kind);
+    else
+      return (jj_ntk = jj_nt.kind);
+  }
+
+  private java.util.Vector jj_expentries = new java.util.Vector();
+  private int[] jj_expentry;
+  private int jj_kind = -1;
+  private int[] jj_lasttokens = new int[100];
+  private int jj_endpos;
+
+  private void jj_add_error_token(int kind, int pos) {
+    if (pos >= 100) return;
+    if (pos == jj_endpos + 1) {
+      jj_lasttokens[jj_endpos++] = kind;
+    } else if (jj_endpos != 0) {
+      jj_expentry = new int[jj_endpos];
+      for (int i = 0; i < jj_endpos; i++) {
+        jj_expentry[i] = jj_lasttokens[i];
+      }
+      boolean exists = false;
+      for (java.util.Enumeration e = jj_expentries.elements(); e.hasMoreElements();) {
+        int[] oldentry = (int[])(e.nextElement());
+        if (oldentry.length == jj_expentry.length) {
+          exists = true;
+          for (int i = 0; i < jj_expentry.length; i++) {
+            if (oldentry[i] != jj_expentry[i]) {
+              exists = false;
+              break;
+            }
+          }
+          if (exists) break;
+        }
+      }
+      if (!exists) jj_expentries.addElement(jj_expentry);
+      if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind;
+    }
+  }
+
+  public ParseException generateParseException() {
+    jj_expentries.removeAllElements();
+    boolean[] la1tokens = new boolean[16];
+    for (int i = 0; i < 16; i++) {
+      la1tokens[i] = false;
+    }
+    if (jj_kind >= 0) {
+      la1tokens[jj_kind] = true;
+      jj_kind = -1;
+    }
+    for (int i = 0; i < 5; i++) {
+      if (jj_la1[i] == jj_gen) {
+        for (int j = 0; j < 32; j++) {
+          if ((jj_la1_0[i] & (1<<j)) != 0) {
+            la1tokens[j] = true;
+          }
+        }
+      }
+    }
+    for (int i = 0; i < 16; i++) {
+      if (la1tokens[i]) {
+        jj_expentry = new int[1];
+        jj_expentry[0] = i;
+        jj_expentries.addElement(jj_expentry);
+      }
+    }
+    jj_endpos = 0;
+    jj_rescan_token();
+    jj_add_error_token(0, 0);
+    int[][] exptokseq = new int[jj_expentries.size()][];
+    for (int i = 0; i < jj_expentries.size(); i++) {
+      exptokseq[i] = (int[])jj_expentries.elementAt(i);
+    }
+    return new ParseException(token, exptokseq, tokenImage);
+  }
+
+  final public void enable_tracing() {
+  }
+
+  final public void disable_tracing() {
+  }
+
+  final private void jj_rescan_token() {
+    jj_rescan = true;
+    for (int i = 0; i < 2; i++) {
+    try {
+      JJCalls p = jj_2_rtns[i];
+      do {
+        if (p.gen > jj_gen) {
+          jj_la = p.arg; jj_lastpos = jj_scanpos = p.first;
+          switch (i) {
+            case 0: jj_3_1(); break;
+            case 1: jj_3_2(); break;
+          }
+        }
+        p = p.next;
+      } while (p != null);
+      } catch(LookaheadSuccess ls) { }
+    }
+    jj_rescan = false;
+  }
+
+  final private void jj_save(int index, int xla) {
+    JJCalls p = jj_2_rtns[index];
+    while (p.gen > jj_gen) {
+      if (p.next == null) { p = p.next = new JJCalls(); break; }
+      p = p.next;
+    }
+    p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla;
+  }
+
+  static final class JJCalls {
+    int gen;
+    Token first;
+    int arg;
+    JJCalls next;
+  }
+
+}
diff --git a/src/main/java/javax/measure/unit/format/UCUMParser.jj b/src/main/java/javax/measure/unit/format/UCUMParser.jj
new file mode 100644
index 0000000..4b8c137
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UCUMParser.jj
@@ -0,0 +1,189 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2008 - JScience
+ * All rights reserved.
+ * 
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+
+options {
+  STATIC = false;
+  DEBUG_PARSER = false;
+  DEBUG_LOOKAHEAD = false;
+  DEBUG_TOKEN_MANAGER = false;
+}
+
+PARSER_BEGIN(UCUMParser)
+
+package javax.measure.unit.ucum;
+
+/**
+ * <p> 
+ * Parser definition for parsing {@link javax.measure.unit.Unit Unit}s 
+ * according to the <a href="http://aurora.regenstrief.org/UCUM/ucum.html">
+ * Uniform Code for Units of Measure</a>.
+ * 
+ * @author <a href="mailto:eric-r at northwestern.edu">Eric Russell</a>
+ * @version 1.0
+ * @see <a href="http://aurora.regenstrief.org/UCUM/ucum.html">UCUM</a>
+ */
+class UCUMParser {
+    
+    private SymbolMap _symbols;
+
+    public UCUMParser (SymbolMap symbols, java.io.InputStream in) {
+        this(in);
+        _symbols = symbols;
+    }
+}
+
+PARSER_END(UCUMParser)
+
+//
+// Lexical entities
+//
+
+TOKEN: { <#ATOM_CHAR: ["!","#"-"'","*",",","0"-"Z","\\","^"-"z","|","~"] >
+       | <#ESCAPED_ATOM_CHAR: ["!"-"Z","\\","^"-"~"] >
+       | <#TERMINAL_ATOM_CHAR: ["!","#"-"'","*",",",":"-"Z","\\","^"-"z","|","~"] >
+       | <#LCBRACKET: "{" >
+       | <#RCBRACKET: "}" >
+       | <#LSBRACKET: "[" >
+       | <#RSBRACKET: "]" > }
+TOKEN: { <ANNOTATION: <LCBRACKET> (["!"-"z","|","~" ])* <RCBRACKET> > }
+TOKEN: { <FACTOR: (["0"-"9"])+ > }
+TOKEN: { <SIGN: ["+","-"] > }
+TOKEN: { <DOT: "."> }
+TOKEN: { <SOLIDUS: "/"> }
+TOKEN: { <ATOM: (((<ATOM_CHAR>)*
+                  (<TERMINAL_ATOM_CHAR>)+) |
+                 ((<ATOM_CHAR>)*
+                  (<LSBRACKET> (<ESCAPED_ATOM_CHAR>)+ <RSBRACKET>)
+                  ((<ATOM_CHAR>)*
+                   (<TERMINAL_ATOM_CHAR>)+)?)) > }
+
+//
+// Parser productions
+//
+
+javax.measure.unit.Unit parseUnit () :
+    {
+        javax.measure.unit.Unit u;
+    }
+{
+    u=Term() <EOF>
+    { return u; }
+}
+
+javax.measure.unit.Unit Term () :
+    { 
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        javax.measure.unit.Unit temp = javax.measure.unit.Unit.ONE; 
+    }
+{
+(
+    result=Component() 
+    ( 
+      (<DOT> temp=Component() { result = result.times(temp); })
+      | 
+      (<SOLIDUS> temp=Component() { result = result.divide(temp); })
+    )*
+    {
+        return result;
+    }
+)
+}
+
+javax.measure.unit.Unit Component () :
+    {
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        Token token = null;
+    }
+{
+(
+    LOOKAHEAD(Annotatable() <ANNOTATION>)
+    result=Annotatable() token=<ANNOTATION>
+    { 
+        return new AnnotatedUnit(result, token.image.substring(1, token.image.length()-1));
+    }
+|
+    result=Annotatable()
+    {
+        return result; 
+    }
+|
+    token=<ANNOTATION>
+    {   
+        return new AnnotatedUnit(result, token.image.substring(1, token.image.length()-1));
+    }
+|
+    token=<FACTOR>
+    { 
+        long factor = Long.parseLong(token.image);
+        return result.times(factor); 
+    }
+|
+    <SOLIDUS> result=Component()
+    {
+        return javax.measure.unit.Unit.ONE.divide(result);
+    }
+|
+    "(" result=Term() ")"
+    {
+        return result; 
+    }
+)
+}
+
+javax.measure.unit.Unit Annotatable () :
+    {
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        Token token1 = null;
+        Token token2 = null;
+    }
+{
+(
+    LOOKAHEAD(SimpleUnit() (<SIGN>)? <FACTOR>)
+    result=SimpleUnit() (token1=<SIGN>)? token2=<FACTOR>
+    {
+        int exponent = Integer.parseInt(token2.image);
+        if ((token1 != null) && token1.image.equals("-")) {
+            return result.pow(-exponent);
+        } else {
+            return result.pow(exponent);
+        }
+    }
+|
+    result=SimpleUnit()
+    { 
+        return result; 
+    }
+)
+}
+
+javax.measure.unit.Unit SimpleUnit () :
+    {
+        Token token = null;
+    }
+{
+(
+    token=<ATOM>
+    {
+        javax.measure.unit.Unit unit = _symbols.getUnit(token.image);
+        if (unit == null) {
+            Prefix prefix = _symbols.getPrefix(token.image);
+            if (prefix != null) {
+                String prefixSymbol = _symbols.getSymbol(prefix);
+                unit = _symbols.getUnit(token.image.substring(prefixSymbol.length()));
+                if (unit != null) {
+                    return unit.transform(prefix.getConverter());
+                } 
+            }
+            throw new ParseException();
+        } else {
+            return unit;
+        }
+    }
+)
+}
diff --git a/src/main/java/javax/measure/unit/format/UCUMParserConstants.java b/src/main/java/javax/measure/unit/format/UCUMParserConstants.java
new file mode 100644
index 0000000..f2f39c9
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UCUMParserConstants.java
@@ -0,0 +1,42 @@
+/* Generated By:JavaCC: Do not edit this line. UCUMParserConstants.java */
+package javax.measure.unit.format;
+
+interface UCUMParserConstants {
+
+  int EOF = 0;
+  int ATOM_CHAR = 1;
+  int ESCAPED_ATOM_CHAR = 2;
+  int TERMINAL_ATOM_CHAR = 3;
+  int LCBRACKET = 4;
+  int RCBRACKET = 5;
+  int LSBRACKET = 6;
+  int RSBRACKET = 7;
+  int ANNOTATION = 8;
+  int FACTOR = 9;
+  int SIGN = 10;
+  int DOT = 11;
+  int SOLIDUS = 12;
+  int ATOM = 13;
+
+  int DEFAULT = 0;
+
+  String[] tokenImage = {
+    "<EOF>",
+    "<ATOM_CHAR>",
+    "<ESCAPED_ATOM_CHAR>",
+    "<TERMINAL_ATOM_CHAR>",
+    "\"{\"",
+    "\"}\"",
+    "\"[\"",
+    "\"]\"",
+    "<ANNOTATION>",
+    "<FACTOR>",
+    "<SIGN>",
+    "\".\"",
+    "\"/\"",
+    "<ATOM>",
+    "\"(\"",
+    "\")\"",
+  };
+
+}
diff --git a/src/main/java/javax/measure/unit/format/UCUMParserTokenManager.java b/src/main/java/javax/measure/unit/format/UCUMParserTokenManager.java
new file mode 100644
index 0000000..8b705be
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UCUMParserTokenManager.java
@@ -0,0 +1,399 @@
+/* Generated By:JavaCC: Do not edit this line. UCUMParserTokenManager.java */
+package javax.measure.unit.format;
+
+class UCUMParserTokenManager implements UCUMParserConstants
+{
+  public  java.io.PrintStream debugStream = System.out;
+  public  void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
+private final int jjStopStringLiteralDfa_0(int pos, long active0)
+{
+   switch (pos)
+   {
+      default :
+         return -1;
+   }
+}
+private final int jjStartNfa_0(int pos, long active0)
+{
+   return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
+}
+private final int jjStopAtPos(int pos, int kind)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   return pos + 1;
+}
+private final int jjStartNfaWithStates_0(int pos, int kind, int state)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) { return pos + 1; }
+   return jjMoveNfa_0(state, pos + 1);
+}
+private final int jjMoveStringLiteralDfa0_0()
+{
+   switch(curChar)
+   {
+      case 40:
+         return jjStopAtPos(0, 14);
+      case 41:
+         return jjStopAtPos(0, 15);
+      case 46:
+         return jjStopAtPos(0, 11);
+      case 47:
+         return jjStopAtPos(0, 12);
+      default :
+         return jjMoveNfa_0(0, 0);
+   }
+}
+private final void jjCheckNAdd(int state)
+{
+   if (jjrounds[state] != jjround)
+   {
+      jjstateSet[jjnewStateCnt++] = state;
+      jjrounds[state] = jjround;
+   }
+}
+private final void jjAddStates(int start, int end)
+{
+   do {
+      jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+   } while (start++ != end);
+}
+private final void jjCheckNAddTwoStates(int state1, int state2)
+{
+   jjCheckNAdd(state1);
+   jjCheckNAdd(state2);
+}
+private final void jjCheckNAddStates(int start, int end)
+{
+   do {
+      jjCheckNAdd(jjnextStates[start]);
+   } while (start++ != end);
+}
+private final void jjCheckNAddStates(int start)
+{
+   jjCheckNAdd(jjnextStates[start]);
+   jjCheckNAdd(jjnextStates[start + 1]);
+}
+private final int jjMoveNfa_0(int startState, int curPos)
+{
+   int[] nextStates;
+   int startsAt = 0;
+   jjnewStateCnt = 14;
+   int i = 1;
+   jjstateSet[0] = startState;
+   int j, kind = 0x7fffffff;
+   for (;;)
+   {
+      if (++jjround == 0x7fffffff)
+         ReInitRounds();
+      if (curChar < 64)
+      {
+         long l = 1L << curChar;
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+                  if ((0xffff14fa00000000L & l) != 0L)
+                     jjCheckNAddStates(0, 3);
+                  else if ((0x280000000000L & l) != 0L)
+                  {
+                     if (kind > 10)
+                        kind = 10;
+                  }
+                  if ((0xfc0014fa00000000L & l) != 0L)
+                  {
+                     if (kind > 13)
+                        kind = 13;
+                     jjCheckNAdd(5);
+                  }
+                  else if ((0x3ff000000000000L & l) != 0L)
+                  {
+                     if (kind > 9)
+                        kind = 9;
+                     jjCheckNAdd(3);
+                  }
+                  break;
+               case 1:
+                  if ((0xfffffffe00000000L & l) != 0L)
+                     jjAddStates(4, 5);
+                  break;
+               case 3:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 9)
+                     kind = 9;
+                  jjCheckNAdd(3);
+                  break;
+               case 4:
+                  if ((0x280000000000L & l) != 0L && kind > 10)
+                     kind = 10;
+                  break;
+               case 5:
+                  if ((0xfc0014fa00000000L & l) == 0L)
+                     break;
+                  if (kind > 13)
+                     kind = 13;
+                  jjCheckNAdd(5);
+                  break;
+               case 7:
+                  if ((0xfffffffe00000000L & l) != 0L)
+                     jjAddStates(6, 7);
+                  break;
+               case 9:
+                  if ((0xffff14fa00000000L & l) != 0L)
+                     jjCheckNAddTwoStates(9, 10);
+                  break;
+               case 10:
+                  if ((0xfc0014fa00000000L & l) == 0L)
+                     break;
+                  if (kind > 13)
+                     kind = 13;
+                  jjCheckNAdd(10);
+                  break;
+               case 11:
+                  if ((0xffff14fa00000000L & l) != 0L)
+                     jjCheckNAddStates(0, 3);
+                  break;
+               case 12:
+                  if ((0xffff14fa00000000L & l) != 0L)
+                     jjCheckNAddTwoStates(12, 5);
+                  break;
+               case 13:
+                  if ((0xffff14fa00000000L & l) != 0L)
+                     jjCheckNAddTwoStates(13, 6);
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else if (curChar < 128)
+      {
+         long l = 1L << (curChar & 077);
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+                  if ((0x57ffffffd7ffffffL & l) != 0L)
+                     jjCheckNAddStates(0, 3);
+                  else if (curChar == 91)
+                     jjCheckNAdd(7);
+                  else if (curChar == 123)
+                     jjCheckNAddTwoStates(1, 2);
+                  if ((0x57ffffffd7ffffffL & l) != 0L)
+                  {
+                     if (kind > 13)
+                        kind = 13;
+                     jjCheckNAdd(5);
+                  }
+                  break;
+               case 1:
+                  if ((0x57ffffffffffffffL & l) != 0L)
+                     jjCheckNAddTwoStates(1, 2);
+                  break;
+               case 2:
+                  if (curChar == 125 && kind > 8)
+                     kind = 8;
+                  break;
+               case 5:
+                  if ((0x57ffffffd7ffffffL & l) == 0L)
+                     break;
+                  if (kind > 13)
+                     kind = 13;
+                  jjCheckNAdd(5);
+                  break;
+               case 6:
+                  if (curChar == 91)
+                     jjCheckNAdd(7);
+                  break;
+               case 7:
+                  if ((0x7fffffffd7ffffffL & l) != 0L)
+                     jjCheckNAddTwoStates(7, 8);
+                  break;
+               case 8:
+                  if (curChar != 93)
+                     break;
+                  if (kind > 13)
+                     kind = 13;
+                  jjCheckNAddTwoStates(9, 10);
+                  break;
+               case 9:
+                  if ((0x57ffffffd7ffffffL & l) != 0L)
+                     jjCheckNAddTwoStates(9, 10);
+                  break;
+               case 10:
+                  if ((0x57ffffffd7ffffffL & l) == 0L)
+                     break;
+                  if (kind > 13)
+                     kind = 13;
+                  jjCheckNAdd(10);
+                  break;
+               case 11:
+                  if ((0x57ffffffd7ffffffL & l) != 0L)
+                     jjCheckNAddStates(0, 3);
+                  break;
+               case 12:
+                  if ((0x57ffffffd7ffffffL & l) != 0L)
+                     jjCheckNAddTwoStates(12, 5);
+                  break;
+               case 13:
+                  if ((0x57ffffffd7ffffffL & l) != 0L)
+                     jjCheckNAddTwoStates(13, 6);
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else
+      {
+         int i2 = (curChar & 0xff) >> 6;
+         long l2 = 1L << (curChar & 077);
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      if (kind != 0x7fffffff)
+      {
+         jjmatchedKind = kind;
+         jjmatchedPos = curPos;
+         kind = 0x7fffffff;
+      }
+      ++curPos;
+      if ((i = jjnewStateCnt) == (startsAt = 14 - (jjnewStateCnt = startsAt)))
+         return curPos;
+      try { curChar = input_stream.readChar(); }
+      catch(java.io.IOException e) { return curPos; }
+   }
+}
+static final int[] jjnextStates = {
+   12, 5, 13, 6, 1, 2, 7, 8, 
+};
+public static final String[] jjstrLiteralImages = {
+"", null, null, null, null, null, null, null, null, null, null, "\56", "\57", 
+null, "\50", "\51", };
+public static final String[] lexStateNames = {
+   "DEFAULT", 
+};
+protected SimpleCharStream input_stream;
+private final int[] jjrounds = new int[14];
+private final int[] jjstateSet = new int[28];
+protected char curChar;
+public UCUMParserTokenManager(SimpleCharStream stream){
+   if (SimpleCharStream.staticFlag)
+      throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
+   input_stream = stream;
+}
+public UCUMParserTokenManager(SimpleCharStream stream, int lexState){
+   this(stream);
+   SwitchTo(lexState);
+}
+public void ReInit(SimpleCharStream stream)
+{
+   jjmatchedPos = jjnewStateCnt = 0;
+   curLexState = defaultLexState;
+   input_stream = stream;
+   ReInitRounds();
+}
+private final void ReInitRounds()
+{
+   int i;
+   jjround = 0x80000001;
+   for (i = 14; i-- > 0;)
+      jjrounds[i] = 0x80000000;
+}
+public void ReInit(SimpleCharStream stream, int lexState)
+{
+   ReInit(stream);
+   SwitchTo(lexState);
+}
+public void SwitchTo(int lexState)
+{
+   if (lexState >= 1 || lexState < 0)
+      throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
+   else
+      curLexState = lexState;
+}
+
+protected Token jjFillToken()
+{
+   Token t = Token.newToken(jjmatchedKind);
+   t.kind = jjmatchedKind;
+   String im = jjstrLiteralImages[jjmatchedKind];
+   t.image = (im == null) ? input_stream.GetImage() : im;
+   t.beginLine = input_stream.getBeginLine();
+   t.beginColumn = input_stream.getBeginColumn();
+   t.endLine = input_stream.getEndLine();
+   t.endColumn = input_stream.getEndColumn();
+   return t;
+}
+
+int curLexState = 0;
+int defaultLexState = 0;
+int jjnewStateCnt;
+int jjround;
+int jjmatchedPos;
+int jjmatchedKind;
+
+public Token getNextToken() 
+{
+  int kind;
+  Token specialToken = null;
+  Token matchedToken;
+  int curPos = 0;
+
+  EOFLoop :
+  for (;;)
+  {   
+   try   
+   {     
+      curChar = input_stream.BeginToken();
+   }     
+   catch(java.io.IOException e)
+   {        
+      jjmatchedKind = 0;
+      matchedToken = jjFillToken();
+      return matchedToken;
+   }
+
+   jjmatchedKind = 0x7fffffff;
+   jjmatchedPos = 0;
+   curPos = jjMoveStringLiteralDfa0_0();
+   if (jjmatchedKind != 0x7fffffff)
+   {
+      if (jjmatchedPos + 1 < curPos)
+         input_stream.backup(curPos - jjmatchedPos - 1);
+         matchedToken = jjFillToken();
+         return matchedToken;
+   }
+   int error_line = input_stream.getEndLine();
+   int error_column = input_stream.getEndColumn();
+   String error_after = null;
+   boolean EOFSeen = false;
+   try { input_stream.readChar(); input_stream.backup(1); }
+   catch (java.io.IOException e1) {
+      EOFSeen = true;
+      error_after = curPos <= 1 ? "" : input_stream.GetImage();
+      if (curChar == '\n' || curChar == '\r') {
+         error_line++;
+         error_column = 0;
+      }
+      else
+         error_column++;
+   }
+   if (!EOFSeen) {
+      input_stream.backup(1);
+      error_after = curPos <= 1 ? "" : input_stream.GetImage();
+   }
+   throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
+  }
+}
+
+}
diff --git a/src/main/java/javax/measure/unit/format/UCUM_CI.properties b/src/main/java/javax/measure/unit/format/UCUM_CI.properties
new file mode 100644
index 0000000..6d04469
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UCUM_CI.properties
@@ -0,0 +1,248 @@
+
+# Prefixes
+
+javax.measure.unit.format.Prefix.YOTTA=YA
+javax.measure.unit.format.Prefix.ZETTA=ZA
+javax.measure.unit.format.Prefix.EXA=EX
+javax.measure.unit.format.Prefix.PETA=PT
+javax.measure.unit.format.Prefix.TERA=TR
+javax.measure.unit.format.Prefix.GIGA=GA
+javax.measure.unit.format.Prefix.MEGA=MA
+javax.measure.unit.format.Prefix.KILO=K
+javax.measure.unit.format.Prefix.HECTO=H
+javax.measure.unit.format.Prefix.DEKA=DA
+javax.measure.unit.format.Prefix.DECI=D
+javax.measure.unit.format.Prefix.CENTI=C
+javax.measure.unit.format.Prefix.MILLI=M
+javax.measure.unit.format.Prefix.MICRO=U
+javax.measure.unit.format.Prefix.NANO=N
+javax.measure.unit.format.Prefix.PICO=P
+javax.measure.unit.format.Prefix.FEMTO=F
+javax.measure.unit.format.Prefix.ATTO=A
+javax.measure.unit.format.Prefix.ZEPTO=ZO
+javax.measure.unit.format.Prefix.YOCTO=YO
+
+# Units
+
+javax.measure.unit.format.UCUM.METER=M
+javax.measure.unit.format.UCUM.SECOND=S
+javax.measure.unit.format.UCUM.GRAM=G
+javax.measure.unit.format.UCUM.RADIAN=RAD
+javax.measure.unit.format.UCUM.KELVIN=K
+javax.measure.unit.format.UCUM.COULOMB=C
+javax.measure.unit.format.UCUM.CANDELA=CD
+javax.measure.unit.format.UCUM.TRIILLIONS=10^12
+javax.measure.unit.format.UCUM.BILLIONS=10^9
+javax.measure.unit.format.UCUM.MILLIONS=10^6
+javax.measure.unit.format.UCUM.THOUSANDS=10^3
+javax.measure.unit.format.UCUM.HUNDREDS=10^2
+javax.measure.unit.format.UCUM.PI=[PI]
+javax.measure.unit.format.UCUM.PERCENT=%
+javax.measure.unit.format.UCUM.PER_THOUSAND=[PPTH]
+javax.measure.unit.format.UCUM.PER_MILLION=[PPM]
+javax.measure.unit.format.UCUM.PER_BILLION=[PPB]
+javax.measure.unit.format.UCUM.PER_TRILLION=[PPTR]
+javax.measure.unit.format.UCUM.MOLE=MOL
+javax.measure.unit.format.UCUM.STERADIAN=SR
+javax.measure.unit.format.UCUM.HERTZ=HZ
+javax.measure.unit.format.UCUM.NEWTON=N
+javax.measure.unit.format.UCUM.PASCAL=PAL
+javax.measure.unit.format.UCUM.JOULE=J
+javax.measure.unit.format.UCUM.WATT=W
+javax.measure.unit.format.UCUM.AMPERE=A
+javax.measure.unit.format.UCUM.VOLT=V
+javax.measure.unit.format.UCUM.FARAD=F
+javax.measure.unit.format.UCUM.OHM=OHM
+javax.measure.unit.format.UCUM.SIEMENS=SIE
+javax.measure.unit.format.UCUM.WEBER=WB
+javax.measure.unit.format.UCUM.CELSIUS=CEL
+javax.measure.unit.format.UCUM.TESLA=T
+javax.measure.unit.format.UCUM.HENRY=H
+javax.measure.unit.format.UCUM.LUMEN=LM
+javax.measure.unit.format.UCUM.LUX=LX
+javax.measure.unit.format.UCUM.BECQUEREL=BQ
+javax.measure.unit.format.UCUM.GRAY=GY
+javax.measure.unit.format.UCUM.SIEVERT=SV
+javax.measure.unit.format.UCUM.DEGREE=DEG
+javax.measure.unit.format.UCUM.GRADE=GON
+javax.measure.unit.format.UCUM.MINUTE_ANGLE='
+javax.measure.unit.format.UCUM.SECOND_ANGLE=''
+javax.measure.unit.format.UCUM.LITER=L
+javax.measure.unit.format.UCUM.ARE=AR
+javax.measure.unit.format.UCUM.MINUTE=MIN
+javax.measure.unit.format.UCUM.HOUR=HR
+javax.measure.unit.format.UCUM.DAY=D
+javax.measure.unit.format.UCUM.YEAR_TROPICAL=ANN_T
+javax.measure.unit.format.UCUM.YEAR_JULIAN=ANN_J
+javax.measure.unit.format.UCUM.YEAR_GREGORIAN=ANN_G
+javax.measure.unit.format.UCUM.YEAR=ANN
+javax.measure.unit.format.UCUM.MONTH_SYNODAL=MO_S
+javax.measure.unit.format.UCUM.MONTH_JULIAN=MO_J
+javax.measure.unit.format.UCUM.MONTH_GREGORIAN=MO_G
+javax.measure.unit.format.UCUM.MONTH=MO
+javax.measure.unit.format.UCUM.TONNE=TNE
+javax.measure.unit.format.UCUM.BAR=BAR
+javax.measure.unit.format.UCUM.ATOMIC_MASS_UNIT=AMU
+javax.measure.unit.format.UCUM.ELECTRON_VOLT=EV
+javax.measure.unit.format.UCUM.ASTRONOMIC_UNIT=ASU
+javax.measure.unit.format.UCUM.PARSEC=PRS
+javax.measure.unit.format.UCUM.C=[C]
+javax.measure.unit.format.UCUM.PLANCK=[H]
+javax.measure.unit.format.UCUM.BOLTZMAN=[K]
+javax.measure.unit.format.UCUM.PERMITTIVITY_OF_VACUUM=[EPS_0]
+javax.measure.unit.format.UCUM.PERMEABILITY_OF_VACUUM=[MU_0]
+javax.measure.unit.format.UCUM.ELEMENTARY_CHARGE=[E]
+javax.measure.unit.format.UCUM.ELECTRON_MASS=[M_E]
+javax.measure.unit.format.UCUM.PROTON_MASS=[M_P]
+javax.measure.unit.format.UCUM.NEWTON_CONSTANT_OF_GRAVITY=[GC]
+javax.measure.unit.format.UCUM.ACCELLERATION_OF_FREEFALL=[G]
+javax.measure.unit.format.UCUM.ATMOSPHERE=ATM
+javax.measure.unit.format.UCUM.LIGHT_YEAR=[LY]
+javax.measure.unit.format.UCUM.GRAM_FORCE=GF
+javax.measure.unit.format.UCUM.KAYSER=KY
+javax.measure.unit.format.UCUM.GAL=GL
+javax.measure.unit.format.UCUM.DYNE=DYN
+javax.measure.unit.format.UCUM.ERG=ERG
+javax.measure.unit.format.UCUM.POISE=P
+javax.measure.unit.format.UCUM.BIOT=BI
+javax.measure.unit.format.UCUM.STOKES=ST
+javax.measure.unit.format.UCUM.MAXWELL=MX
+javax.measure.unit.format.UCUM.GAUSS=GS
+javax.measure.unit.format.UCUM.OERSTED=OE
+javax.measure.unit.format.UCUM.GILBERT=GB
+javax.measure.unit.format.UCUM.STILB=SB
+javax.measure.unit.format.UCUM.LAMBERT=LMB
+javax.measure.unit.format.UCUM.PHOT=PHT
+javax.measure.unit.format.UCUM.CURIE=CI
+javax.measure.unit.format.UCUM.ROENTGEN=ROE
+javax.measure.unit.format.UCUM.RAD=[RAD]
+javax.measure.unit.format.UCUM.REM=[REM]
+javax.measure.unit.format.UCUM.INCH_INTERNATIONAL=[IN_I]
+javax.measure.unit.format.UCUM.FOOT_INTERNATIONAL=[FT_I]
+javax.measure.unit.format.UCUM.YARD_INTERNATIONAL=[YD_I]
+javax.measure.unit.format.UCUM.MILE_INTERNATIONAL=[MI_I]
+javax.measure.unit.format.UCUM.FATHOM_INTERNATIONAL=[FTH_I]
+javax.measure.unit.format.UCUM.NAUTICAL_MILE_INTERNATIONAL=[NMI_I]
+javax.measure.unit.format.UCUM.KNOT_INTERNATIONAL=[KN_I]
+javax.measure.unit.format.UCUM.SQUARE_INCH_INTERNATIONAL=[SIN_I]
+javax.measure.unit.format.UCUM.SQUARE_FOOT_INTERNATIONAL=[SFT_I]
+javax.measure.unit.format.UCUM.SQUARE_YARD_INTERNATIONAL=[SYD_I]
+javax.measure.unit.format.UCUM.CUBIC_INCH_INTERNATIONAL=[CIN_I]
+javax.measure.unit.format.UCUM.CUBIC_FOOT_INTERNATIONAL=[CFT_I]
+javax.measure.unit.format.UCUM.CUBIC_YARD_INTERNATIONAL=[CYD_I]
+javax.measure.unit.format.UCUM.BOARD_FOOT_INTERNATIONAL=[BF_I]
+javax.measure.unit.format.UCUM.CORD_INTERNATIONAL=[CR_I]
+javax.measure.unit.format.UCUM.MIL_INTERNATIONAL=[MIL_I]
+javax.measure.unit.format.UCUM.CIRCULAR_MIL_INTERNATIONAL=[CML_I]
+javax.measure.unit.format.UCUM.HAND_INTERNATIONAL=[HD_I]
+javax.measure.unit.format.UCUM.FOOT_US_SURVEY=[FT_US]
+javax.measure.unit.format.UCUM.YARD_US_SURVEY=[YD_US]
+javax.measure.unit.format.UCUM.INCH_US_SURVEY=[IN_US]
+javax.measure.unit.format.UCUM.ROD_US_SURVEY=[RD_US]
+javax.measure.unit.format.UCUM.CHAIN_US_SURVEY=[CH_US]
+javax.measure.unit.format.UCUM.LINK_US_SURVEY=[LK_US]
+javax.measure.unit.format.UCUM.RAMDEN_CHAIN_US_SURVEY=[RCH_US]
+javax.measure.unit.format.UCUM.RAMDEN_LINK_US_SURVEY=[RLK_US]
+javax.measure.unit.format.UCUM.FATHOM_US_SURVEY=[FTH_US]
+javax.measure.unit.format.UCUM.FURLONG_US_SURVEY=[FUR_US]
+javax.measure.unit.format.UCUM.MILE_US_SURVEY=[MI_US]
+javax.measure.unit.format.UCUM.ACRE_US_SURVEY=[ACR_US]
+javax.measure.unit.format.UCUM.SQUARE_ROD_US_SURVEY=[SRD_US]
+javax.measure.unit.format.UCUM.SQUARE_MILE_US_SURVEY=[SMI_US]
+javax.measure.unit.format.UCUM.SECTION_US_SURVEY=[SCT]
+javax.measure.unit.format.UCUM.TOWNSHP_US_SURVEY=[TWP]
+javax.measure.unit.format.UCUM.MIL_US_SURVEY=[MIL_US]
+javax.measure.unit.format.UCUM.INCH_BRITISH=[IN_BR]
+javax.measure.unit.format.UCUM.FOOT_BRITISH=[FT_BR]
+javax.measure.unit.format.UCUM.ROD_BRITISH=[RD_BR]
+javax.measure.unit.format.UCUM.CHAIN_BRITISH=[CH_BR]
+javax.measure.unit.format.UCUM.LINK_BRITISH=[LK_BR]
+javax.measure.unit.format.UCUM.FATHOM_BRITISH=[FTH_BR]
+javax.measure.unit.format.UCUM.PACE_BRITISH=[PC_BR]
+javax.measure.unit.format.UCUM.YARD_BRITISH=[YD_BR]
+javax.measure.unit.format.UCUM.MILE_BRITISH=[MI_BR]
+javax.measure.unit.format.UCUM.NAUTICAL_MILE_BRITISH=[NMI_BR]
+javax.measure.unit.format.UCUM.KNOT_BRITISH=[KN_BR]
+javax.measure.unit.format.UCUM.ACRE_BRITISH=[ACR_BR]
+javax.measure.unit.format.UCUM.GALLON_US=[GAL_US]
+javax.measure.unit.format.UCUM.BARREL_US=[BBL_US]
+javax.measure.unit.format.UCUM.QUART_US=[QT_US]
+javax.measure.unit.format.UCUM.PINT_US=[PT_US]
+javax.measure.unit.format.UCUM.GILL_US=[GIL_US]
+javax.measure.unit.format.UCUM.FLUID_OUNCE_US=[FOZ_US]
+javax.measure.unit.format.UCUM.FLUID_DRAM_US=[FDR_US]
+javax.measure.unit.format.UCUM.MINIM_US=[MIN_US]
+javax.measure.unit.format.UCUM.CORD_US=[CRD_US]
+javax.measure.unit.format.UCUM.BUSHEL_US=[BU_US]
+javax.measure.unit.format.UCUM.GALLON_WINCHESTER=[GAL_WI]
+javax.measure.unit.format.UCUM.PECK_US=[PK_US]
+javax.measure.unit.format.UCUM.DRY_QUART_US=[DQT_US]
+javax.measure.unit.format.UCUM.DRY_PINT_US=[DPT_US]
+javax.measure.unit.format.UCUM.TABLESPOON_US=[TBS_US]
+javax.measure.unit.format.UCUM.TEASPOON_US=[TSP_US]
+javax.measure.unit.format.UCUM.CUP_US=[CUP_US]
+javax.measure.unit.format.UCUM.GALLON_BRITISH=[GAL_BR]
+javax.measure.unit.format.UCUM.PECK_BRITISH=[PK_BR]
+javax.measure.unit.format.UCUM.BUSHEL_BRITISH=[BU_BR]
+javax.measure.unit.format.UCUM.QUART_BRITISH=[QT_BR]
+javax.measure.unit.format.UCUM.PINT_BRITISH=[PT_BR]
+javax.measure.unit.format.UCUM.GILL_BRITISH=[GIL_BR]
+javax.measure.unit.format.UCUM.FLUID_OUNCE_BRITISH=[FOZ_BR]
+javax.measure.unit.format.UCUM.FLUID_DRAM_BRITISH=[FDR_BR]
+javax.measure.unit.format.UCUM.MINIM_BRITISH=[MIN_BR]
+javax.measure.unit.format.UCUM.GRAIN=[GR]
+javax.measure.unit.format.UCUM.POUND=[LB_AV]
+javax.measure.unit.format.UCUM.OUNCE=[OZ_AV]
+javax.measure.unit.format.UCUM.DRAM=[DR_AV]
+javax.measure.unit.format.UCUM.SHORT_HUNDREDWEIGHT=[SCWT_AV]
+javax.measure.unit.format.UCUM.LONG_HUNDREDWEIGHT=[LCWT_AV]
+javax.measure.unit.format.UCUM.SHORT_TON=[STON_AV]
+javax.measure.unit.format.UCUM.LONG_TON=[LTON_AV]
+javax.measure.unit.format.UCUM.STONE=[STONE_AV]
+javax.measure.unit.format.UCUM.POUND_FORCE=[LBF_AV]
+javax.measure.unit.format.UCUM.PENNYWEIGHT_TROY=[PWT_TR]
+javax.measure.unit.format.UCUM.OUNCE_TROY=[OZ_TR]
+javax.measure.unit.format.UCUM.POUND_TROY=[LB_TR]
+javax.measure.unit.format.UCUM.SCRUPLE_APOTHECARY=[SC_AP]
+javax.measure.unit.format.UCUM.DRAM_APOTHECARY=[DR_AP]
+javax.measure.unit.format.UCUM.OUNCE_APOTHECARY=[OZ_AP]
+javax.measure.unit.format.UCUM.POUND_APOTHECARY=[LB_AP]
+javax.measure.unit.format.UCUM.LINE=[LNE]
+javax.measure.unit.format.UCUM.POINT=[PNT]
+javax.measure.unit.format.UCUM.PICA=[PCA]
+javax.measure.unit.format.UCUM.POINT_PRINTER=[PNT_PR]
+javax.measure.unit.format.UCUM.PICA_PRINTER=[PCA_PR]
+javax.measure.unit.format.UCUM.PIED=[PIED]
+javax.measure.unit.format.UCUM.POUCE=[POUCE]
+javax.measure.unit.format.UCUM.LINGE=[LIGNE]
+javax.measure.unit.format.UCUM.DIDOT=[DIDOT]
+javax.measure.unit.format.UCUM.CICERO=[CICERO]
+javax.measure.unit.format.UCUM.FAHRENHEIT=[DEGF]
+javax.measure.unit.format.UCUM.CALORIE_AT_15C=CAL_[15]
+javax.measure.unit.format.UCUM.CALORIE_AT_20C=CAL_[20]
+javax.measure.unit.format.UCUM.CALORIE_MEAN=CAL_M
+javax.measure.unit.format.UCUM.CALORIE_INTERNATIONAL_TABLE=CAL_IT
+javax.measure.unit.format.UCUM.CALORIE_THERMOCHEMICAL=CAL_TH
+javax.measure.unit.format.UCUM.CALORIE=CAL
+javax.measure.unit.format.UCUM.CALORIE_FOOD=[CAL]
+javax.measure.unit.format.UCUM.BTU_AT_39F=[BTU_39]
+javax.measure.unit.format.UCUM.BTU_AT_59F=[BTU_59]
+javax.measure.unit.format.UCUM.BTU_AT_60F=[BTU_60]
+javax.measure.unit.format.UCUM.BTU_MEAN=[BTU_M]
+javax.measure.unit.format.UCUM.BTU_INTERNATIONAL_TABLE=[BTU_IT]
+javax.measure.unit.format.UCUM.BTU_THERMOCHEMICAL=[BTU_TH]
+javax.measure.unit.format.UCUM.BTU=[BTU]
+javax.measure.unit.format.UCUM.HORSEPOWER=[HP]
+javax.measure.unit.format.UCUM.STERE=STR
+javax.measure.unit.format.UCUM.ANGSTROM=AO
+javax.measure.unit.format.UCUM.BARN=BRN
+javax.measure.unit.format.UCUM.ATMOSPHERE_TECHNICAL=ATT
+javax.measure.unit.format.UCUM.MHO=MHO
+javax.measure.unit.format.UCUM.POUND_PER_SQUARE_INCH=[PSI]
+javax.measure.unit.format.UCUM.CIRCLE=CIRC
+javax.measure.unit.format.UCUM.SPHERE=SPH
+javax.measure.unit.format.UCUM.CARAT_METRIC=[CAR_M]
+javax.measure.unit.format.UCUM.CARAT_GOLD=[CAR_AU]
+javax.measure.unit.format.UCUM.BIT=BIT
+javax.measure.unit.format.UCUM.BYTE=BY
+javax.measure.unit.format.UCUM.BAUD=Bd
diff --git a/src/main/java/javax/measure/unit/format/UCUM_CS.properties b/src/main/java/javax/measure/unit/format/UCUM_CS.properties
new file mode 100644
index 0000000..0b9b331
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UCUM_CS.properties
@@ -0,0 +1,250 @@
+
+# Prefixes
+
+javax.measure.unit.format.Prefix.YOTTA=Y
+javax.measure.unit.format.Prefix.ZETTA=Z
+javax.measure.unit.format.Prefix.EXA=E
+javax.measure.unit.format.Prefix.PETA=P
+javax.measure.unit.format.Prefix.TERA=T
+javax.measure.unit.format.Prefix.GIGA=G
+javax.measure.unit.format.Prefix.MEGA=M
+javax.measure.unit.format.Prefix.KILO=k
+javax.measure.unit.format.Prefix.HECTO=h
+javax.measure.unit.format.Prefix.DEKA=da
+javax.measure.unit.format.Prefix.DECI=d
+javax.measure.unit.format.Prefix.CENTI=c
+javax.measure.unit.format.Prefix.MILLI=m
+javax.measure.unit.format.Prefix.MICRO=u
+javax.measure.unit.format.Prefix.NANO=n
+javax.measure.unit.format.Prefix.PICO=p
+javax.measure.unit.format.Prefix.FEMTO=f
+javax.measure.unit.format.Prefix.ATTO=a
+javax.measure.unit.format.Prefix.ZEPTO=z
+javax.measure.unit.format.Prefix.YOCTO=y
+
+# Units
+
+javax.measure.unit.format.UCUM.METER=m
+javax.measure.unit.format.UCUM.SECOND=s
+javax.measure.unit.format.UCUM.GRAM=g
+javax.measure.unit.format.UCUM.RADIAN=rad
+javax.measure.unit.format.UCUM.KELVIN=K
+javax.measure.unit.format.UCUM.COULOMB=C
+javax.measure.unit.format.UCUM.CANDELA=cd
+javax.measure.unit.format.UCUM.TRIILLIONS=10^12
+javax.measure.unit.format.UCUM.BILLIONS=10^9
+javax.measure.unit.format.UCUM.MILLIONS=10^6
+javax.measure.unit.format.UCUM.THOUSANDS=10^3
+javax.measure.unit.format.UCUM.HUNDREDS=10^2
+javax.measure.unit.format.UCUM.PI=[pi]
+javax.measure.unit.format.UCUM.PERCENT=%
+javax.measure.unit.format.UCUM.PER_THOUSAND=[ppth]
+javax.measure.unit.format.UCUM.PER_MILLION=[ppm]
+javax.measure.unit.format.UCUM.PER_BILLION=[ppb]
+javax.measure.unit.format.UCUM.PER_TRILLION=[pptr]
+javax.measure.unit.format.UCUM.MOLE=mol
+javax.measure.unit.format.UCUM.STERADIAN=sr
+javax.measure.unit.format.UCUM.HERTZ=Hz
+javax.measure.unit.format.UCUM.NEWTON=N
+javax.measure.unit.format.UCUM.PASCAL=Pa
+javax.measure.unit.format.UCUM.JOULE=J
+javax.measure.unit.format.UCUM.WATT=W
+javax.measure.unit.format.UCUM.AMPERE=A
+javax.measure.unit.format.UCUM.VOLT=V
+javax.measure.unit.format.UCUM.FARAD=F
+javax.measure.unit.format.UCUM.OHM=Ohm
+javax.measure.unit.format.UCUM.SIEMENS=S
+javax.measure.unit.format.UCUM.WEBER=Wb
+javax.measure.unit.format.UCUM.CELSIUS=Cel
+javax.measure.unit.format.UCUM.TESLA=T
+javax.measure.unit.format.UCUM.HENRY=H
+javax.measure.unit.format.UCUM.LUMEN=lm
+javax.measure.unit.format.UCUM.LUX=lx
+javax.measure.unit.format.UCUM.BECQUEREL=Bq
+javax.measure.unit.format.UCUM.GRAY=Gy
+javax.measure.unit.format.UCUM.SIEVERT=Sv
+javax.measure.unit.format.UCUM.DEGREE=deg
+javax.measure.unit.format.UCUM.GRADE=gon
+javax.measure.unit.format.UCUM.MINUTE_ANGLE='
+javax.measure.unit.format.UCUM.SECOND_ANGLE=''
+javax.measure.unit.format.UCUM.LITER=l
+javax.measure.unit.format.UCUM.LITER.1=L
+javax.measure.unit.format.UCUM.ARE=ar
+javax.measure.unit.format.UCUM.MINUTE=min
+javax.measure.unit.format.UCUM.HOUR=h
+javax.measure.unit.format.UCUM.DAY=d
+javax.measure.unit.format.UCUM.YEAR_TROPICAL=a_t
+javax.measure.unit.format.UCUM.YEAR_JULIAN=a_j
+javax.measure.unit.format.UCUM.YEAR_GREGORIAN=a_g
+javax.measure.unit.format.UCUM.YEAR=a
+javax.measure.unit.format.UCUM.MONTH_SYNODAL=mo_s
+javax.measure.unit.format.UCUM.MONTH_JULIAN=mo_j
+javax.measure.unit.format.UCUM.MONTH_GREGORIAN=mo_g
+javax.measure.unit.format.UCUM.MONTH=mo
+javax.measure.unit.format.UCUM.TONNE=t
+javax.measure.unit.format.UCUM.BAR=bar
+javax.measure.unit.format.UCUM.ATOMIC_MASS_UNIT=u
+javax.measure.unit.format.UCUM.ELECTRON_VOLT=eV
+javax.measure.unit.format.UCUM.ASTRONOMIC_UNIT=AU
+javax.measure.unit.format.UCUM.PARSEC=pc
+javax.measure.unit.format.UCUM.C=[c]
+javax.measure.unit.format.UCUM.PLANCK=[h]
+javax.measure.unit.format.UCUM.BOLTZMAN=[k]
+javax.measure.unit.format.UCUM.PERMITTIVITY_OF_VACUUM=[eps_0]
+javax.measure.unit.format.UCUM.PERMEABILITY_OF_VACUUM=[mu_0]
+javax.measure.unit.format.UCUM.ELEMENTARY_CHARGE=[e]
+javax.measure.unit.format.UCUM.ELECTRON_MASS=[m_e]
+javax.measure.unit.format.UCUM.PROTON_MASS=[m_p]
+javax.measure.unit.format.UCUM.NEWTON_CONSTANT_OF_GRAVITY=[G]
+javax.measure.unit.format.UCUM.ACCELLERATION_OF_FREEFALL=[g]
+javax.measure.unit.format.UCUM.ATMOSPHERE=atm
+javax.measure.unit.format.UCUM.LIGHT_YEAR=[ly]
+javax.measure.unit.format.UCUM.GRAM_FORCE=gf
+javax.measure.unit.format.UCUM.KAYSER=Ky
+javax.measure.unit.format.UCUM.GAL=Gal
+javax.measure.unit.format.UCUM.DYNE=dyn
+javax.measure.unit.format.UCUM.ERG=erg
+javax.measure.unit.format.UCUM.POISE=P
+javax.measure.unit.format.UCUM.BIOT=Bi
+javax.measure.unit.format.UCUM.STOKES=St
+javax.measure.unit.format.UCUM.MAXWELL=Mx
+javax.measure.unit.format.UCUM.GAUSS=G
+javax.measure.unit.format.UCUM.OERSTED=Oe
+javax.measure.unit.format.UCUM.GILBERT=Gb
+javax.measure.unit.format.UCUM.STILB=sb
+javax.measure.unit.format.UCUM.LAMBERT=Lmb
+javax.measure.unit.format.UCUM.PHOT=ph
+javax.measure.unit.format.UCUM.CURIE=Ci
+javax.measure.unit.format.UCUM.ROENTGEN=R
+javax.measure.unit.format.UCUM.RAD=RAD
+javax.measure.unit.format.UCUM.REM=REM
+javax.measure.unit.format.UCUM.INCH_INTERNATIONAL=[in_i]
+javax.measure.unit.format.UCUM.FOOT_INTERNATIONAL=[ft_i]
+javax.measure.unit.format.UCUM.YARD_INTERNATIONAL=[yd_i]
+javax.measure.unit.format.UCUM.MILE_INTERNATIONAL=[mi_i]
+javax.measure.unit.format.UCUM.FATHOM_INTERNATIONAL=[fth_i]
+javax.measure.unit.format.UCUM.NAUTICAL_MILE_INTERNATIONAL=[nmi_i]
+javax.measure.unit.format.UCUM.KNOT_INTERNATIONAL=[kn_i]
+javax.measure.unit.format.UCUM.SQUARE_INCH_INTERNATIONAL=[sin_i]
+javax.measure.unit.format.UCUM.SQUARE_FOOT_INTERNATIONAL=[sft_i]
+javax.measure.unit.format.UCUM.SQUARE_YARD_INTERNATIONAL=[syd_i]
+javax.measure.unit.format.UCUM.CUBIC_INCH_INTERNATIONAL=[cin_i]
+javax.measure.unit.format.UCUM.CUBIC_FOOT_INTERNATIONAL=[cft_i]
+javax.measure.unit.format.UCUM.CUBIC_YARD_INTERNATIONAL=[cyd_i]
+javax.measure.unit.format.UCUM.BOARD_FOOT_INTERNATIONAL=[bf_i]
+javax.measure.unit.format.UCUM.CORD_INTERNATIONAL=[cr_i]
+javax.measure.unit.format.UCUM.MIL_INTERNATIONAL=[mil_i]
+javax.measure.unit.format.UCUM.CIRCULAR_MIL_INTERNATIONAL=[cml_i]
+javax.measure.unit.format.UCUM.HAND_INTERNATIONAL=[hd_i]
+javax.measure.unit.format.UCUM.FOOT_US_SURVEY=[ft_us]
+javax.measure.unit.format.UCUM.YARD_US_SURVEY=[yd_us]
+javax.measure.unit.format.UCUM.INCH_US_SURVEY=[in_us]
+javax.measure.unit.format.UCUM.ROD_US_SURVEY=[rd_us]
+javax.measure.unit.format.UCUM.CHAIN_US_SURVEY=[ch_us]
+javax.measure.unit.format.UCUM.LINK_US_SURVEY=[lk_us]
+javax.measure.unit.format.UCUM.RAMDEN_CHAIN_US_SURVEY=[rch_us]
+javax.measure.unit.format.UCUM.RAMDEN_LINK_US_SURVEY=[rlk_us]
+javax.measure.unit.format.UCUM.FATHOM_US_SURVEY=[fth_us]
+javax.measure.unit.format.UCUM.FURLONG_US_SURVEY=[fur_us]
+javax.measure.unit.format.UCUM.MILE_US_SURVEY=[mi_us]
+javax.measure.unit.format.UCUM.ACRE_US_SURVEY=[acr_us]
+javax.measure.unit.format.UCUM.SQUARE_ROD_US_SURVEY=[srd_us]
+javax.measure.unit.format.UCUM.SQUARE_MILE_US_SURVEY=[smi_us]
+javax.measure.unit.format.UCUM.SECTION_US_SURVEY=[sct]
+javax.measure.unit.format.UCUM.TOWNSHP_US_SURVEY=[twp]
+javax.measure.unit.format.UCUM.MIL_US_SURVEY=[mil_us]
+javax.measure.unit.format.UCUM.INCH_BRITISH=[in_br]
+javax.measure.unit.format.UCUM.FOOT_BRITISH=[ft_br]
+javax.measure.unit.format.UCUM.ROD_BRITISH=[rd_br]
+javax.measure.unit.format.UCUM.CHAIN_BRITISH=[ch_br]
+javax.measure.unit.format.UCUM.LINK_BRITISH=[lk_br]
+javax.measure.unit.format.UCUM.FATHOM_BRITISH=[fth_br]
+javax.measure.unit.format.UCUM.PACE_BRITISH=[pc_br]
+javax.measure.unit.format.UCUM.YARD_BRITISH=[yd_br]
+javax.measure.unit.format.UCUM.MILE_BRITISH=[mi_br]
+javax.measure.unit.format.UCUM.NAUTICAL_MILE_BRITISH=[nmi_br]
+javax.measure.unit.format.UCUM.KNOT_BRITISH=[kn_br]
+javax.measure.unit.format.UCUM.ACRE_BRITISH=[acr_br]
+javax.measure.unit.format.UCUM.GALLON_US=[gal_us]
+javax.measure.unit.format.UCUM.BARREL_US=[bbl_us]
+javax.measure.unit.format.UCUM.QUART_US=[qt_us]
+javax.measure.unit.format.UCUM.PINT_US=[pt_us]
+javax.measure.unit.format.UCUM.GILL_US=[gil_us]
+javax.measure.unit.format.UCUM.FLUID_OUNCE_US=[foz_us]
+javax.measure.unit.format.UCUM.FLUID_DRAM_US=[fdr_us]
+javax.measure.unit.format.UCUM.MINIM_US=[min_us]
+javax.measure.unit.format.UCUM.CORD_US=[crd_us]
+javax.measure.unit.format.UCUM.BUSHEL_US=[bu_us]
+javax.measure.unit.format.UCUM.GALLON_WINCHESTER=[gal_wi]
+javax.measure.unit.format.UCUM.PECK_US=[pk_us]
+javax.measure.unit.format.UCUM.DRY_QUART_US=[dqt_us]
+javax.measure.unit.format.UCUM.DRY_PINT_US=[dpt_us]
+javax.measure.unit.format.UCUM.TABLESPOON_US=[tbs_us]
+javax.measure.unit.format.UCUM.TEASPOON_US=[tsp_us]
+javax.measure.unit.format.UCUM.CUP_US=[cup_us]
+javax.measure.unit.format.UCUM.GALLON_BRITISH=[gal_br]
+javax.measure.unit.format.UCUM.PECK_BRITISH=[pk_br]
+javax.measure.unit.format.UCUM.BUSHEL_BRITISH=[bu_br]
+javax.measure.unit.format.UCUM.QUART_BRITISH=[qt_br]
+javax.measure.unit.format.UCUM.PINT_BRITISH=[pt_br]
+javax.measure.unit.format.UCUM.GILL_BRITISH=[gil_br]
+javax.measure.unit.format.UCUM.FLUID_OUNCE_BRITISH=[foz_br]
+javax.measure.unit.format.UCUM.FLUID_DRAM_BRITISH=[fdr_br]
+javax.measure.unit.format.UCUM.MINIM_BRITISH=[min_br]
+javax.measure.unit.format.UCUM.GRAIN=[gr]
+javax.measure.unit.format.UCUM.POUND=[lb_av]
+javax.measure.unit.format.UCUM.OUNCE=[oz_av]
+javax.measure.unit.format.UCUM.DRAM=[dr_av]
+javax.measure.unit.format.UCUM.SHORT_HUNDREDWEIGHT=[scwt_av]
+javax.measure.unit.format.UCUM.LONG_HUNDREDWEIGHT=[lcwt_av]
+javax.measure.unit.format.UCUM.SHORT_TON=[ston_av]
+javax.measure.unit.format.UCUM.LONG_TON=[lton_av]
+javax.measure.unit.format.UCUM.STONE=[stone_av]
+javax.measure.unit.format.UCUM.POUND_FORCE=[lbf_av]
+javax.measure.unit.format.UCUM.PENNYWEIGHT_TROY=[pwt_tr]
+javax.measure.unit.format.UCUM.OUNCE_TROY=[oz_tr]
+javax.measure.unit.format.UCUM.POUND_TROY=[lb_tr]
+javax.measure.unit.format.UCUM.SCRUPLE_APOTHECARY=[sc_ap]
+javax.measure.unit.format.UCUM.DRAM_APOTHECARY=[dr_ap]
+javax.measure.unit.format.UCUM.OUNCE_APOTHECARY=[oz_ap]
+javax.measure.unit.format.UCUM.POUND_APOTHECARY=[lb_ap]
+javax.measure.unit.format.UCUM.LINE=[lne]
+javax.measure.unit.format.UCUM.POINT=[pnt]
+javax.measure.unit.format.UCUM.PICA=[pca]
+javax.measure.unit.format.UCUM.POINT_PRINTER=[pnt_pr]
+javax.measure.unit.format.UCUM.PICA_PRINTER=[pca_pr]
+javax.measure.unit.format.UCUM.PIED=[pied]
+javax.measure.unit.format.UCUM.POUCE=[pouce]
+javax.measure.unit.format.UCUM.LINGE=[ligne]
+javax.measure.unit.format.UCUM.DIDOT=[didot]
+javax.measure.unit.format.UCUM.CICERO=[cicero]
+javax.measure.unit.format.UCUM.FAHRENHEIT=[degF]
+javax.measure.unit.format.UCUM.CALORIE_AT_15C=cal_[15]
+javax.measure.unit.format.UCUM.CALORIE_AT_20C=cal_[20]
+javax.measure.unit.format.UCUM.CALORIE_MEAN=cal_m
+javax.measure.unit.format.UCUM.CALORIE_INTERNATIONAL_TABLE=cal_IT
+javax.measure.unit.format.UCUM.CALORIE_THERMOCHEMICAL=cal_th
+javax.measure.unit.format.UCUM.CALORIE=cal
+javax.measure.unit.format.UCUM.CALORIE_FOOD=[Cal]
+javax.measure.unit.format.UCUM.BTU_AT_39F=[Btu_39]
+javax.measure.unit.format.UCUM.BTU_AT_59F=[Btu_59]
+javax.measure.unit.format.UCUM.BTU_AT_60F=[Btu_60]
+javax.measure.unit.format.UCUM.BTU_MEAN=[Btu_m]
+javax.measure.unit.format.UCUM.BTU_INTERNATIONAL_TABLE=[Btu_IT]
+javax.measure.unit.format.UCUM.BTU_THERMOCHEMICAL=[Btu_th]
+javax.measure.unit.format.UCUM.BTU=[Btu]
+javax.measure.unit.format.UCUM.HORSEPOWER=[HP]
+javax.measure.unit.format.UCUM.STERE=st
+javax.measure.unit.format.UCUM.ANGSTROM=Ao
+javax.measure.unit.format.UCUM.BARN=b
+javax.measure.unit.format.UCUM.ATMOSPHERE_TECHNICAL=att
+javax.measure.unit.format.UCUM.MHO=mho
+javax.measure.unit.format.UCUM.POUND_PER_SQUARE_INCH=[psi]
+javax.measure.unit.format.UCUM.CIRCLE=circ
+javax.measure.unit.format.UCUM.SPHERE=sph
+javax.measure.unit.format.UCUM.CARAT_METRIC=[car_m]
+javax.measure.unit.format.UCUM.CARAT_GOLD=[car_Au]
+javax.measure.unit.format.UCUM.BIT=bit
+javax.measure.unit.format.UCUM.BYTE=By
+javax.measure.unit.format.UCUM.BAUD=Bd
+
diff --git a/src/main/java/javax/measure/unit/format/UCUM_Print.properties b/src/main/java/javax/measure/unit/format/UCUM_Print.properties
new file mode 100644
index 0000000..f72d15f
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UCUM_Print.properties
@@ -0,0 +1,252 @@
+# NOTE: as a Java properties file, this file must use the
+# ISO 8859-1 encoding, so all non-ASCII Unicode characters 
+# must be escaped using the \uXXXX syntax.
+# See http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html#encoding
+
+# Prefixes
+
+javax.measure.unit.format.Prefix.YOTTA=Y
+javax.measure.unit.format.Prefix.ZETTA=Z
+javax.measure.unit.format.Prefix.EXA=E
+javax.measure.unit.format.Prefix.PETA=P
+javax.measure.unit.format.Prefix.TERA=T
+javax.measure.unit.format.Prefix.GIGA=G
+javax.measure.unit.format.Prefix.MEGA=M
+javax.measure.unit.format.Prefix.KILO=k
+javax.measure.unit.format.Prefix.HECTO=h
+javax.measure.unit.format.Prefix.DEKA=da
+javax.measure.unit.format.Prefix.DECI=d
+javax.measure.unit.format.Prefix.CENTI=c
+javax.measure.unit.format.Prefix.MILLI=m
+javax.measure.unit.format.Prefix.MICRO=\u03BC
+javax.measure.unit.format.Prefix.NANO=n
+javax.measure.unit.format.Prefix.PICO=p
+javax.measure.unit.format.Prefix.FEMTO=f
+javax.measure.unit.format.Prefix.ATTO=a
+javax.measure.unit.format.Prefix.ZEPTO=z
+javax.measure.unit.format.Prefix.YOCTO=y
+
+# Units
+
+javax.measure.unit.format.UCUM.METER=m
+javax.measure.unit.format.UCUM.SECOND=s
+javax.measure.unit.format.UCUM.GRAM=g
+javax.measure.unit.format.UCUM.RADIAN=rad
+javax.measure.unit.format.UCUM.KELVIN=K
+javax.measure.unit.format.UCUM.COULOMB=C
+javax.measure.unit.format.UCUM.CANDELA=ca
+javax.measure.unit.format.UCUM.TRIILLIONS=10\u00B9\u00B2
+javax.measure.unit.format.UCUM.BILLIONS=10\u2079
+javax.measure.unit.format.UCUM.MILLIONS=10\u2076
+javax.measure.unit.format.UCUM.THOUSANDS=10\u00B3
+javax.measure.unit.format.UCUM.HUNDREDS=10\u00B2
+javax.measure.unit.format.UCUM.PI=\u03C0
+javax.measure.unit.format.UCUM.PERCENT=%
+javax.measure.unit.format.UCUM.PER_THOUSAND=ppth
+javax.measure.unit.format.UCUM.PER_MILLION=ppm
+javax.measure.unit.format.UCUM.PER_BILLION=ppb
+javax.measure.unit.format.UCUM.PER_TRILLION=pptr
+javax.measure.unit.format.UCUM.MOLE=mol
+javax.measure.unit.format.UCUM.STERADIAN=sr
+javax.measure.unit.format.UCUM.HERTZ=Hz
+javax.measure.unit.format.UCUM.NEWTON=N
+javax.measure.unit.format.UCUM.PASCAL=Pa
+javax.measure.unit.format.UCUM.JOULE=J
+javax.measure.unit.format.UCUM.WATT=W
+javax.measure.unit.format.UCUM.AMPERE=A
+javax.measure.unit.format.UCUM.VOLT=V
+javax.measure.unit.format.UCUM.FARAD=F
+javax.measure.unit.format.UCUM.OHM=\u03A9
+javax.measure.unit.format.UCUM.SIEMENS=S
+javax.measure.unit.format.UCUM.WEBER=Wb
+javax.measure.unit.format.UCUM.CELSIUS=\u00B0C
+javax.measure.unit.format.UCUM.TESLA=T
+javax.measure.unit.format.UCUM.HENRY=H
+javax.measure.unit.format.UCUM.LUMEN=lm
+javax.measure.unit.format.UCUM.LUX=lx
+javax.measure.unit.format.UCUM.BECQUEREL=Bq
+javax.measure.unit.format.UCUM.GRAY=Gy
+javax.measure.unit.format.UCUM.SIEVERT=Sv
+javax.measure.unit.format.UCUM.DEGREE=\u00B0
+javax.measure.unit.format.UCUM.GRADE=\u25A1g
+javax.measure.unit.format.UCUM.MINUTE_ANGLE='
+javax.measure.unit.format.UCUM.SECOND_ANGLE=\"
+javax.measure.unit.format.UCUM.LITER=l
+javax.measure.unit.format.UCUM.ARE=a
+javax.measure.unit.format.UCUM.MINUTE=min
+javax.measure.unit.format.UCUM.HOUR=h
+javax.measure.unit.format.UCUM.DAY=d
+javax.measure.unit.format.UCUM.YEAR_TROPICAL=a_t
+javax.measure.unit.format.UCUM.YEAR_JULIAN=a_j
+javax.measure.unit.format.UCUM.YEAR_GREGORIAN=a_g
+javax.measure.unit.format.UCUM.YEAR=a
+javax.measure.unit.format.UCUM.MONTH_SYNODAL=mo_s
+javax.measure.unit.format.UCUM.MONTH_JULIAN=mo_j
+javax.measure.unit.format.UCUM.MONTH_GREGORIAN=mo_g
+javax.measure.unit.format.UCUM.MONTH=mo
+javax.measure.unit.format.UCUM.TONNE=t
+javax.measure.unit.format.UCUM.BAR=bar
+javax.measure.unit.format.UCUM.ATOMIC_MASS_UNIT=u
+javax.measure.unit.format.UCUM.ELECTRON_VOLT=eV
+javax.measure.unit.format.UCUM.ASTRONOMIC_UNIT=AU
+javax.measure.unit.format.UCUM.PARSEC=PC
+javax.measure.unit.format.UCUM.C=c
+javax.measure.unit.format.UCUM.PLANCK=h
+javax.measure.unit.format.UCUM.BOLTZMAN=k
+javax.measure.unit.format.UCUM.PERMITTIVITY_OF_VACUUM=\u03B5\u2080
+javax.measure.unit.format.UCUM.PERMEABILITY_OF_VACUUM=\u03BC\u2080
+javax.measure.unit.format.UCUM.ELEMENTARY_CHARGE=e
+javax.measure.unit.format.UCUM.ELECTRON_MASS=m_e
+javax.measure.unit.format.UCUM.PROTON_MASS=m_p
+javax.measure.unit.format.UCUM.NEWTON_CONSTANT_OF_GRAVITY=G
+javax.measure.unit.format.UCUM.ACCELLERATION_OF_FREEFALL=g_n
+javax.measure.unit.format.UCUM.ATMOSPHERE=atm
+javax.measure.unit.format.UCUM.LIGHT_YEAR=l.y.
+javax.measure.unit.format.UCUM.GRAM_FORCE=gf
+javax.measure.unit.format.UCUM.KAYSER=K
+javax.measure.unit.format.UCUM.GAL=Gal
+javax.measure.unit.format.UCUM.DYNE=dyn
+javax.measure.unit.format.UCUM.ERG=erg
+javax.measure.unit.format.UCUM.POISE=P
+javax.measure.unit.format.UCUM.BIOT=Bi
+javax.measure.unit.format.UCUM.STOKES=St
+javax.measure.unit.format.UCUM.MAXWELL=Mx
+javax.measure.unit.format.UCUM.GAUSS=Gs
+javax.measure.unit.format.UCUM.OERSTED=Oe
+javax.measure.unit.format.UCUM.GILBERT=Gb
+javax.measure.unit.format.UCUM.STILB=sb
+javax.measure.unit.format.UCUM.LAMBERT=L
+javax.measure.unit.format.UCUM.PHOT=ph
+javax.measure.unit.format.UCUM.CURIE=Ci
+javax.measure.unit.format.UCUM.ROENTGEN=R
+javax.measure.unit.format.UCUM.RAD=RAD
+javax.measure.unit.format.UCUM.REM=REM
+javax.measure.unit.format.UCUM.INCH_INTERNATIONAL=in_i
+javax.measure.unit.format.UCUM.FOOT_INTERNATIONAL=ft_i
+javax.measure.unit.format.UCUM.YARD_INTERNATIONAL=yd_i
+javax.measure.unit.format.UCUM.MILE_INTERNATIONAL=mi_i
+javax.measure.unit.format.UCUM.FATHOM_INTERNATIONAL=fth_i
+javax.measure.unit.format.UCUM.NAUTICAL_MILE_INTERNATIONAL=nmi_i
+javax.measure.unit.format.UCUM.KNOT_INTERNATIONAL=kn_i
+javax.measure.unit.format.UCUM.SQUARE_INCH_INTERNATIONAL=sin_i
+javax.measure.unit.format.UCUM.SQUARE_FOOT_INTERNATIONAL=sft_i
+javax.measure.unit.format.UCUM.SQUARE_YARD_INTERNATIONAL=syd_i
+javax.measure.unit.format.UCUM.CUBIC_INCH_INTERNATIONAL=cin_i
+javax.measure.unit.format.UCUM.CUBIC_FOOT_INTERNATIONAL=cft_i
+javax.measure.unit.format.UCUM.CUBIC_YARD_INTERNATIONAL=cyd_i
+javax.measure.unit.format.UCUM.BOARD_FOOT_INTERNATIONAL=bf_i
+javax.measure.unit.format.UCUM.CORD_INTERNATIONAL=cr_i
+javax.measure.unit.format.UCUM.MIL_INTERNATIONAL=mil_i
+javax.measure.unit.format.UCUM.CIRCULAR_MIL_INTERNATIONAL=cml_i
+javax.measure.unit.format.UCUM.HAND_INTERNATIONAL=hd_i
+javax.measure.unit.format.UCUM.FOOT_US_SURVEY=ft_us
+javax.measure.unit.format.UCUM.YARD_US_SURVEY=yd_us
+javax.measure.unit.format.UCUM.INCH_US_SURVEY=in_us
+javax.measure.unit.format.UCUM.ROD_US_SURVEY=rd_us
+javax.measure.unit.format.UCUM.CHAIN_US_SURVEY=ch_us
+javax.measure.unit.format.UCUM.LINK_US_SURVEY=lk_us
+javax.measure.unit.format.UCUM.RAMDEN_CHAIN_US_SURVEY=rch_us
+javax.measure.unit.format.UCUM.RAMDEN_LINK_US_SURVEY=rlk_us
+javax.measure.unit.format.UCUM.FATHOM_US_SURVEY=fth_us
+javax.measure.unit.format.UCUM.FURLONG_US_SURVEY=fur_us
+javax.measure.unit.format.UCUM.MILE_US_SURVEY=mi_us
+javax.measure.unit.format.UCUM.ACRE_US_SURVEY=acr_us
+javax.measure.unit.format.UCUM.SQUARE_ROD_US_SURVEY=src_us
+javax.measure.unit.format.UCUM.SQUARE_MILE_US_SURVEY=smi_us
+javax.measure.unit.format.UCUM.SECTION_US_SURVEY=sct
+javax.measure.unit.format.UCUM.TOWNSHP_US_SURVEY=twp
+javax.measure.unit.format.UCUM.MIL_US_SURVEY=mil_us
+javax.measure.unit.format.UCUM.INCH_BRITISH=in_br
+javax.measure.unit.format.UCUM.FOOT_BRITISH=ft_br
+javax.measure.unit.format.UCUM.ROD_BRITISH=rd_br
+javax.measure.unit.format.UCUM.CHAIN_BRITISH=ch_br
+javax.measure.unit.format.UCUM.LINK_BRITISH=lk_br
+javax.measure.unit.format.UCUM.FATHOM_BRITISH=fth_br
+javax.measure.unit.format.UCUM.PACE_BRITISH=pc_br
+javax.measure.unit.format.UCUM.YARD_BRITISH=yd_br
+javax.measure.unit.format.UCUM.MILE_BRITISH=mi_br
+javax.measure.unit.format.UCUM.NAUTICAL_MILE_BRITISH=nmi_br
+javax.measure.unit.format.UCUM.KNOT_BRITISH=kn_br
+javax.measure.unit.format.UCUM.ACRE_BRITISH=acr_br
+javax.measure.unit.format.UCUM.GALLON_US=gal_us
+javax.measure.unit.format.UCUM.BARREL_US=bbl_us
+javax.measure.unit.format.UCUM.QUART_US=qt_us
+javax.measure.unit.format.UCUM.PINT_US=pt_us
+javax.measure.unit.format.UCUM.GILL_US=gil_us
+javax.measure.unit.format.UCUM.FLUID_OUNCE_US=foz_us
+javax.measure.unit.format.UCUM.FLUID_DRAM_US=fdr_us
+javax.measure.unit.format.UCUM.MINIM_US=min_us
+javax.measure.unit.format.UCUM.CORD_US=crd_us
+javax.measure.unit.format.UCUM.BUSHEL_US=bu_us
+javax.measure.unit.format.UCUM.GALLON_WINCHESTER=gal_wi
+javax.measure.unit.format.UCUM.PECK_US=pk_us
+javax.measure.unit.format.UCUM.DRY_QUART_US=dqt_us
+javax.measure.unit.format.UCUM.DRY_PINT_US=dpt_us
+javax.measure.unit.format.UCUM.TABLESPOON_US=tbs_us
+javax.measure.unit.format.UCUM.TEASPOON_US=tsp_us
+javax.measure.unit.format.UCUM.CUP_US=cup_us
+javax.measure.unit.format.UCUM.GALLON_BRITISH=gal_br
+javax.measure.unit.format.UCUM.PECK_BRITISH=pk_br
+javax.measure.unit.format.UCUM.BUSHEL_BRITISH=bu_br
+javax.measure.unit.format.UCUM.QUART_BRITISH=qt_br
+javax.measure.unit.format.UCUM.PINT_BRITISH=pt_br
+javax.measure.unit.format.UCUM.GILL_BRITISH=gil_br
+javax.measure.unit.format.UCUM.FLUID_OUNCE_BRITISH=foz_br
+javax.measure.unit.format.UCUM.FLUID_DRAM_BRITISH=fdr_br
+javax.measure.unit.format.UCUM.MINIM_BRITISH=min_br
+javax.measure.unit.format.UCUM.GRAIN=gr
+javax.measure.unit.format.UCUM.POUND=lb_av
+javax.measure.unit.format.UCUM.OUNCE=oz_av
+javax.measure.unit.format.UCUM.DRAM=dr_av
+javax.measure.unit.format.UCUM.SHORT_HUNDREDWEIGHT=scwt_av
+javax.measure.unit.format.UCUM.LONG_HUNDREDWEIGHT=lcwt_av
+javax.measure.unit.format.UCUM.SHORT_TON=ston_av
+javax.measure.unit.format.UCUM.LONG_TON=lton_av
+javax.measure.unit.format.UCUM.STONE=stone_av
+javax.measure.unit.format.UCUM.POUND_FORCE=lbf
+javax.measure.unit.format.UCUM.PENNYWEIGHT_TROY=pwt_tr
+javax.measure.unit.format.UCUM.OUNCE_TROY=oz_tr
+javax.measure.unit.format.UCUM.POUND_TROY=lb_tr
+javax.measure.unit.format.UCUM.SCRUPLE_APOTHECARY=sc_ap
+javax.measure.unit.format.UCUM.DRAM_APOTHECARY=dr_ap
+javax.measure.unit.format.UCUM.OUNCE_APOTHECARY=oz_ap
+javax.measure.unit.format.UCUM.POUND_APOTHECARY=lb_ap
+javax.measure.unit.format.UCUM.LINE=lne
+javax.measure.unit.format.UCUM.POINT=pnt
+javax.measure.unit.format.UCUM.PICA=pca
+javax.measure.unit.format.UCUM.POINT_PRINTER=pnt_pr
+javax.measure.unit.format.UCUM.PICA_PRINTER=pca_pr
+javax.measure.unit.format.UCUM.PIED=pied
+javax.measure.unit.format.UCUM.POUCE=pouce
+javax.measure.unit.format.UCUM.LINGE=linge
+javax.measure.unit.format.UCUM.DIDOT=didot
+javax.measure.unit.format.UCUM.CICERO=cicero
+javax.measure.unit.format.UCUM.FAHRENHEIT=\u00B0F
+javax.measure.unit.format.UCUM.CALORIE_AT_15C=cal15\u00B0C
+javax.measure.unit.format.UCUM.CALORIE_AT_20C=cal20\u00B0C
+javax.measure.unit.format.UCUM.CALORIE_MEAN=cal_m
+javax.measure.unit.format.UCUM.CALORIE_INTERNATIONAL_TABLE=cal_IT
+javax.measure.unit.format.UCUM.CALORIE_THERMOCHEMICAL=cal_th
+javax.measure.unit.format.UCUM.CALORIE=cal
+javax.measure.unit.format.UCUM.CALORIE_FOOD=Cal
+javax.measure.unit.format.UCUM.BTU_AT_39F=Btu39\u00B0F
+javax.measure.unit.format.UCUM.BTU_AT_59F=Btu59\u00B0F
+javax.measure.unit.format.UCUM.BTU_AT_60F=Btu60\u00B0F
+javax.measure.unit.format.UCUM.BTU_MEAN=Btu_m
+javax.measure.unit.format.UCUM.BTU_INTERNATIONAL_TABLE=Btu_IT
+javax.measure.unit.format.UCUM.BTU_THERMOCHEMICAL=Btu_th
+javax.measure.unit.format.UCUM.BTU=btu
+javax.measure.unit.format.UCUM.HORSEPOWER=HP
+javax.measure.unit.format.UCUM.STERE=st
+javax.measure.unit.format.UCUM.ANGSTROM=\u00C5
+javax.measure.unit.format.UCUM.BARN=b
+javax.measure.unit.format.UCUM.ATMOSPHERE_TECHNICAL=at
+javax.measure.unit.format.UCUM.MHO=mho
+javax.measure.unit.format.UCUM.POUND_PER_SQUARE_INCH=psi
+javax.measure.unit.format.UCUM.CIRCLE=circ
+javax.measure.unit.format.UCUM.SPHERE=sph
+javax.measure.unit.format.UCUM.CARAT_METRIC=ct_m
+javax.measure.unit.format.UCUM.CARAT_GOLD=ct_Au
+javax.measure.unit.format.UCUM.BIT=bit
+javax.measure.unit.format.UCUM.BYTE=B
+javax.measure.unit.format.UCUM.BAUD=Bd
diff --git a/src/main/java/javax/measure/unit/format/UnitParser.java b/src/main/java/javax/measure/unit/format/UnitParser.java
new file mode 100644
index 0000000..c89ff4b
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UnitParser.java
@@ -0,0 +1,759 @@
+/* Generated By:JavaCC: Do not edit this line. UnitParser.java */
+package javax.measure.unit.format;
+
+/** */
+class UnitParser implements UnitParserConstants {
+
+    private static class Exponent {
+        public final int pow;
+        public final int root;
+        public Exponent (int pow, int root) {
+            this.pow = pow;
+            this.root = root;
+        }
+    }
+
+    private SymbolMap _symbols;
+
+    public UnitParser (SymbolMap symbols, java.io.Reader in) {
+        this(in);
+        _symbols = symbols;
+    }
+
+//
+// Parser productions
+//
+  final public javax.measure.unit.Unit parseUnit() throws ParseException {
+        javax.measure.unit.Unit result;
+    result = CompoundExpr();
+    jj_consume_token(0);
+        {if (true) return result;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public javax.measure.unit.Unit CompoundExpr() throws ParseException {
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        javax.measure.unit.Unit temp = javax.measure.unit.Unit.ONE;
+    result = AddExpr();
+    label_1:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case COLON:
+        ;
+        break;
+      default:
+        jj_la1[0] = jj_gen;
+        break label_1;
+      }
+      jj_consume_token(COLON);
+      temp = AddExpr();
+                               result=result.compound(temp);
+    }
+      {if (true) return result;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public javax.measure.unit.Unit AddExpr() throws ParseException {
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        Number n1 = null;
+        Token sign1 = null;
+        Number n2 = null;
+        Token sign2 = null;
+    if (jj_2_1(2147483647)) {
+      n1 = NumberExpr();
+      sign1 = Sign();
+    } else {
+      ;
+    }
+    result = MulExpr();
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case PLUS:
+    case MINUS:
+      sign2 = Sign();
+      n2 = NumberExpr();
+      break;
+    default:
+      jj_la1[1] = jj_gen;
+      ;
+    }
+        if (n1 != null) {
+            if (sign1.image.equals("-")) {
+                result = result.times(-1);
+            }
+            result = result.plus(n1.doubleValue());
+        }
+        if (n2 != null) {
+            double offset = n2.doubleValue();
+            if (sign2.image.equals("-")) {
+                offset = -offset;
+            }
+            result = result.plus(offset);
+        }
+        {if (true) return result;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public javax.measure.unit.Unit MulExpr() throws ParseException {
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        javax.measure.unit.Unit temp = javax.measure.unit.Unit.ONE;
+    result = ExponentExpr();
+    label_2:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case ASTERISK:
+      case MIDDLE_DOT:
+      case SOLIDUS:
+        ;
+        break;
+      default:
+        jj_la1[2] = jj_gen;
+        break label_2;
+      }
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case ASTERISK:
+      case MIDDLE_DOT:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case ASTERISK:
+          jj_consume_token(ASTERISK);
+          break;
+        case MIDDLE_DOT:
+          jj_consume_token(MIDDLE_DOT);
+          break;
+        default:
+          jj_la1[3] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+        temp = ExponentExpr();
+                                                          result=result.times(temp);
+        break;
+      case SOLIDUS:
+        jj_consume_token(SOLIDUS);
+        temp = ExponentExpr();
+                                        result=result.divide(temp);
+        break;
+      default:
+        jj_la1[4] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+      {if (true) return result;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public javax.measure.unit.Unit ExponentExpr() throws ParseException {
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        javax.measure.unit.Unit temp = javax.measure.unit.Unit.ONE;
+        Exponent exponent = null;
+        Token token = null;
+    if (jj_2_2(2147483647)) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case INTEGER:
+        token = jj_consume_token(INTEGER);
+        break;
+      case E:
+        token = jj_consume_token(E);
+        break;
+      default:
+        jj_la1[5] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+      jj_consume_token(CARET);
+      result = AtomicExpr();
+        double base;
+        if (token.kind == INTEGER) {
+            base = Integer.parseInt(token.image);
+        } else {
+            base = StrictMath.E;
+        }
+        {if (true) return result.transform(new javax.measure.converter.LogConverter(base).inverse());}
+    } else {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case OPEN_PAREN:
+      case INTEGER:
+      case FLOATING_POINT:
+      case UNIT_IDENTIFIER:
+        result = AtomicExpr();
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case CARET:
+        case SUPERSCRIPT_INTEGER:
+          exponent = Exp();
+          break;
+        default:
+          jj_la1[6] = jj_gen;
+          ;
+        }
+        if (exponent != null) {
+            if (exponent.pow != 1) {
+                result = result.pow(exponent.pow);
+            }
+            if (exponent.root != 1) {
+                result = result.root(exponent.root);
+            }
+        }
+        {if (true) return result;}
+        break;
+      case LOG:
+      case NAT_LOG:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case LOG:
+          jj_consume_token(LOG);
+          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+          case INTEGER:
+            token = jj_consume_token(INTEGER);
+            break;
+          default:
+            jj_la1[7] = jj_gen;
+            ;
+          }
+          break;
+        case NAT_LOG:
+          token = jj_consume_token(NAT_LOG);
+          break;
+        default:
+          jj_la1[8] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+        jj_consume_token(OPEN_PAREN);
+        result = AddExpr();
+        jj_consume_token(CLOSE_PAREN);
+        double base = 10;
+        if (token != null) {
+            if (token.kind == INTEGER) {
+                base = Integer.parseInt(token.image);
+            } else if (token.kind == NAT_LOG) {
+                base = StrictMath.E;
+            }
+        }
+        {if (true) return result.transform(new javax.measure.converter.LogConverter(base));}
+        break;
+      default:
+        jj_la1[9] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public javax.measure.unit.Unit AtomicExpr() throws ParseException {
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        javax.measure.unit.Unit temp = javax.measure.unit.Unit.ONE;
+        Number n = null;
+        Token token = null;
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case INTEGER:
+    case FLOATING_POINT:
+      n = NumberExpr();
+        if (n instanceof Integer) {
+            {if (true) return result.times(n.intValue());}
+        } else {
+            {if (true) return result.times(n.doubleValue());}
+        }
+      break;
+    case UNIT_IDENTIFIER:
+      token = jj_consume_token(UNIT_IDENTIFIER);
+        javax.measure.unit.Unit unit = _symbols.getUnit(token.image);
+        if (unit == null) {
+            Prefix prefix = _symbols.getPrefix(token.image);
+            if (prefix != null) {
+                String prefixSymbol = _symbols.getSymbol(prefix);
+                unit = _symbols.getUnit(token.image.substring(prefixSymbol.length()));
+                if (unit != null) {
+                    {if (true) return unit.transform(prefix.getConverter());}
+                }
+            }
+            {if (true) throw new ParseException();}
+        } else {
+            {if (true) return unit;}
+        }
+      break;
+    case OPEN_PAREN:
+      jj_consume_token(OPEN_PAREN);
+      result = AddExpr();
+      jj_consume_token(CLOSE_PAREN);
+        {if (true) return result;}
+      break;
+    default:
+      jj_la1[10] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Token Sign() throws ParseException {
+        Token result = null;
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case PLUS:
+      result = jj_consume_token(PLUS);
+      break;
+    case MINUS:
+      result = jj_consume_token(MINUS);
+      break;
+    default:
+      jj_la1[11] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+        {if (true) return result;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Number NumberExpr() throws ParseException {
+        Token token = null;
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case INTEGER:
+      token = jj_consume_token(INTEGER);
+        {if (true) return Long.valueOf(token.image);}
+      break;
+    case FLOATING_POINT:
+      token = jj_consume_token(FLOATING_POINT);
+        {if (true) return Double.valueOf(token.image);}
+      break;
+    default:
+      jj_la1[12] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Exponent Exp() throws ParseException {
+        Token powSign = null;
+        Token powToken = null;
+        Token rootSign = null;
+        Token rootToken = null;
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case CARET:
+      jj_consume_token(CARET);
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case PLUS:
+      case MINUS:
+      case INTEGER:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case PLUS:
+        case MINUS:
+          powSign = Sign();
+          break;
+        default:
+          jj_la1[13] = jj_gen;
+          ;
+        }
+        powToken = jj_consume_token(INTEGER);
+            int pow = Integer.parseInt(powToken.image);
+            if ((powSign != null) && powSign.image.equals("-")) {
+                pow = -pow;
+            }
+            {if (true) return new Exponent(pow, 1);}
+        break;
+      case OPEN_PAREN:
+        jj_consume_token(OPEN_PAREN);
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case PLUS:
+        case MINUS:
+          powSign = Sign();
+          break;
+        default:
+          jj_la1[14] = jj_gen;
+          ;
+        }
+        powToken = jj_consume_token(INTEGER);
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case SOLIDUS:
+          jj_consume_token(SOLIDUS);
+          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+          case PLUS:
+          case MINUS:
+            rootSign = Sign();
+            break;
+          default:
+            jj_la1[15] = jj_gen;
+            ;
+          }
+          rootToken = jj_consume_token(INTEGER);
+          break;
+        default:
+          jj_la1[16] = jj_gen;
+          ;
+        }
+        jj_consume_token(CLOSE_PAREN);
+            pow = Integer.parseInt(powToken.image);
+            if ((powSign != null) && powSign.image.equals("-")) {
+                pow = -pow;
+            }
+            int root = 1;
+            if (rootToken != null) {
+                root = Integer.parseInt(rootToken.image);
+                if ((rootSign != null) && rootSign.image.equals("-")) {
+                    root = -root;
+                }
+            }
+            {if (true) return new Exponent(pow, root);}
+        break;
+      default:
+        jj_la1[17] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+      break;
+    case SUPERSCRIPT_INTEGER:
+      powToken = jj_consume_token(SUPERSCRIPT_INTEGER);
+        int pow = 0;
+        for (int i = 0; i < powToken.image.length(); i += 1) {
+            pow *= 10;
+            switch (powToken.image.charAt(i)) {
+                case '\u00b9': pow += 1; break;
+                case '\u00b2': pow += 2; break;
+                case '\u00b3': pow += 3; break;
+                case '\u2074': pow += 4; break;
+                case '\u2075': pow += 5; break;
+                case '\u2076': pow += 6; break;
+                case '\u2077': pow += 7; break;
+                case '\u2078': pow += 8; break;
+                case '\u2079': pow += 9; break;
+            }
+        }
+        {if (true) return new Exponent(pow, 1);}
+      break;
+    default:
+      jj_la1[18] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final private boolean jj_2_1(int xla) {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_1(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(0, xla); }
+  }
+
+  final private boolean jj_2_2(int xla) {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_2(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(1, xla); }
+  }
+
+  final private boolean jj_3R_3() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_5()) {
+    jj_scanpos = xsp;
+    if (jj_3R_6()) return true;
+    }
+    return false;
+  }
+
+  final private boolean jj_3R_6() {
+    if (jj_scan_token(FLOATING_POINT)) return true;
+    return false;
+  }
+
+  final private boolean jj_3_2() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(14)) {
+    jj_scanpos = xsp;
+    if (jj_scan_token(19)) return true;
+    }
+    if (jj_scan_token(CARET)) return true;
+    return false;
+  }
+
+  final private boolean jj_3_1() {
+    if (jj_3R_3()) return true;
+    if (jj_3R_4()) return true;
+    return false;
+  }
+
+  final private boolean jj_3R_4() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(5)) {
+    jj_scanpos = xsp;
+    if (jj_scan_token(6)) return true;
+    }
+    return false;
+  }
+
+  final private boolean jj_3R_5() {
+    if (jj_scan_token(INTEGER)) return true;
+    return false;
+  }
+
+  public UnitParserTokenManager token_source;
+  SimpleCharStream jj_input_stream;
+  public Token token, jj_nt;
+  private int jj_ntk;
+  private Token jj_scanpos, jj_lastpos;
+  private int jj_la;
+  public boolean lookingAhead = false;
+  private boolean jj_semLA;
+  private int jj_gen;
+  final private int[] jj_la1 = new int[19];
+  static private int[] jj_la1_0;
+  static {
+      jj_la1_0();
+   }
+   private static void jj_la1_0() {
+      jj_la1_0 = new int[] {0x800,0x60,0x380,0x180,0x380,0x84000,0x8400,0x4000,0x60000,0x175000,0x115000,0x60,0x14000,0x60,0x60,0x60,0x200,0x5060,0x8400,};
+   }
+  final private JJCalls[] jj_2_rtns = new JJCalls[2];
+  private boolean jj_rescan = false;
+  private int jj_gc = 0;
+
+  public UnitParser(java.io.InputStream stream) {
+     this(stream, null);
+  }
+  public UnitParser(java.io.InputStream stream, String encoding) {
+    try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+    token_source = new UnitParserTokenManager(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 19; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public void ReInit(java.io.InputStream stream) {
+     ReInit(stream, null);
+  }
+  public void ReInit(java.io.InputStream stream, String encoding) {
+    try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+    token_source.ReInit(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 19; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public UnitParser(java.io.Reader stream) {
+    jj_input_stream = new SimpleCharStream(stream, 1, 1);
+    token_source = new UnitParserTokenManager(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 19; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public void ReInit(java.io.Reader stream) {
+    jj_input_stream.ReInit(stream, 1, 1);
+    token_source.ReInit(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 19; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public UnitParser(UnitParserTokenManager tm) {
+    token_source = tm;
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 19; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public void ReInit(UnitParserTokenManager tm) {
+    token_source = tm;
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 19; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  final private Token jj_consume_token(int kind) throws ParseException {
+    Token oldToken;
+    if ((oldToken = token).next != null) token = token.next;
+    else token = token.next = token_source.getNextToken();
+    jj_ntk = -1;
+    if (token.kind == kind) {
+      jj_gen++;
+      if (++jj_gc > 100) {
+        jj_gc = 0;
+        for (int i = 0; i < jj_2_rtns.length; i++) {
+          JJCalls c = jj_2_rtns[i];
+          while (c != null) {
+            if (c.gen < jj_gen) c.first = null;
+            c = c.next;
+          }
+        }
+      }
+      return token;
+    }
+    token = oldToken;
+    jj_kind = kind;
+    throw generateParseException();
+  }
+
+  static private final class LookaheadSuccess extends java.lang.Error { }
+  final private LookaheadSuccess jj_ls = new LookaheadSuccess();
+  final private boolean jj_scan_token(int kind) {
+    if (jj_scanpos == jj_lastpos) {
+      jj_la--;
+      if (jj_scanpos.next == null) {
+        jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken();
+      } else {
+        jj_lastpos = jj_scanpos = jj_scanpos.next;
+      }
+    } else {
+      jj_scanpos = jj_scanpos.next;
+    }
+    if (jj_rescan) {
+      int i = 0; Token tok = token;
+      while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; }
+      if (tok != null) jj_add_error_token(kind, i);
+    }
+    if (jj_scanpos.kind != kind) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls;
+    return false;
+  }
+
+  final public Token getNextToken() {
+    if (token.next != null) token = token.next;
+    else token = token.next = token_source.getNextToken();
+    jj_ntk = -1;
+    jj_gen++;
+    return token;
+  }
+
+  final public Token getToken(int index) {
+    Token t = lookingAhead ? jj_scanpos : token;
+    for (int i = 0; i < index; i++) {
+      if (t.next != null) t = t.next;
+      else t = t.next = token_source.getNextToken();
+    }
+    return t;
+  }
+
+  final private int jj_ntk() {
+    if ((jj_nt=token.next) == null)
+      return (jj_ntk = (token.next=token_source.getNextToken()).kind);
+    else
+      return (jj_ntk = jj_nt.kind);
+  }
+
+  private java.util.Vector jj_expentries = new java.util.Vector();
+  private int[] jj_expentry;
+  private int jj_kind = -1;
+  private int[] jj_lasttokens = new int[100];
+  private int jj_endpos;
+
+  private void jj_add_error_token(int kind, int pos) {
+    if (pos >= 100) return;
+    if (pos == jj_endpos + 1) {
+      jj_lasttokens[jj_endpos++] = kind;
+    } else if (jj_endpos != 0) {
+      jj_expentry = new int[jj_endpos];
+      for (int i = 0; i < jj_endpos; i++) {
+        jj_expentry[i] = jj_lasttokens[i];
+      }
+      boolean exists = false;
+      for (java.util.Enumeration e = jj_expentries.elements(); e.hasMoreElements();) {
+        int[] oldentry = (int[])(e.nextElement());
+        if (oldentry.length == jj_expentry.length) {
+          exists = true;
+          for (int i = 0; i < jj_expentry.length; i++) {
+            if (oldentry[i] != jj_expentry[i]) {
+              exists = false;
+              break;
+            }
+          }
+          if (exists) break;
+        }
+      }
+      if (!exists) jj_expentries.addElement(jj_expentry);
+      if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind;
+    }
+  }
+
+  public ParseException generateParseException() {
+    jj_expentries.removeAllElements();
+    boolean[] la1tokens = new boolean[21];
+    for (int i = 0; i < 21; i++) {
+      la1tokens[i] = false;
+    }
+    if (jj_kind >= 0) {
+      la1tokens[jj_kind] = true;
+      jj_kind = -1;
+    }
+    for (int i = 0; i < 19; i++) {
+      if (jj_la1[i] == jj_gen) {
+        for (int j = 0; j < 32; j++) {
+          if ((jj_la1_0[i] & (1<<j)) != 0) {
+            la1tokens[j] = true;
+          }
+        }
+      }
+    }
+    for (int i = 0; i < 21; i++) {
+      if (la1tokens[i]) {
+        jj_expentry = new int[1];
+        jj_expentry[0] = i;
+        jj_expentries.addElement(jj_expentry);
+      }
+    }
+    jj_endpos = 0;
+    jj_rescan_token();
+    jj_add_error_token(0, 0);
+    int[][] exptokseq = new int[jj_expentries.size()][];
+    for (int i = 0; i < jj_expentries.size(); i++) {
+      exptokseq[i] = (int[])jj_expentries.elementAt(i);
+    }
+    return new ParseException(token, exptokseq, tokenImage);
+  }
+
+  final public void enable_tracing() {
+  }
+
+  final public void disable_tracing() {
+  }
+
+  final private void jj_rescan_token() {
+    jj_rescan = true;
+    for (int i = 0; i < 2; i++) {
+    try {
+      JJCalls p = jj_2_rtns[i];
+      do {
+        if (p.gen > jj_gen) {
+          jj_la = p.arg; jj_lastpos = jj_scanpos = p.first;
+          switch (i) {
+            case 0: jj_3_1(); break;
+            case 1: jj_3_2(); break;
+          }
+        }
+        p = p.next;
+      } while (p != null);
+      } catch(LookaheadSuccess ls) { }
+    }
+    jj_rescan = false;
+  }
+
+  final private void jj_save(int index, int xla) {
+    JJCalls p = jj_2_rtns[index];
+    while (p.gen > jj_gen) {
+      if (p.next == null) { p = p.next = new JJCalls(); break; }
+      p = p.next;
+    }
+    p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla;
+  }
+
+  static final class JJCalls {
+    int gen;
+    Token first;
+    int arg;
+    JJCalls next;
+  }
+
+}
diff --git a/src/main/java/javax/measure/unit/format/UnitParser.jj b/src/main/java/javax/measure/unit/format/UnitParser.jj
new file mode 100644
index 0000000..14b89f5
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UnitParser.jj
@@ -0,0 +1,332 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2008 - JScience
+ * All rights reserved.
+ * 
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+
+options {
+  STATIC = false;
+  UNICODE_INPUT = true;
+  DEBUG_PARSER = false;
+  DEBUG_LOOKAHEAD = false;
+  DEBUG_TOKEN_MANAGER = false;
+}
+
+PARSER_BEGIN(UnitParser)
+
+package javax.measure.unit.ucum;
+
+/** */
+class UnitParser {
+    
+    private static class Exponent {
+        public final int pow;
+        public final int root;
+        public Exponent (int pow, int root) {
+            this.pow = pow;
+            this.root = root;
+        }
+    }
+    
+    private SymbolMap _symbols;
+    
+    public UnitParser (SymbolMap symbols, java.io.Reader in) {
+        this(in);
+        _symbols = symbols;
+    }
+}
+
+PARSER_END(UnitParser)
+
+//
+// Lexical entities
+//
+
+TOKEN: { <#DIGIT: [ "0","1","2","3","4","5","6","7","8","9" ] >
+       | <#SUPERSCRIPT_DIGIT: [ "\u2070", "\u00B9", "\u00B2", "\u00B3", "\u2074", "\u2075", "\u2076", "\u2077", "\u2078", "\u2079" ] >
+       | <#INITIAL_CHAR: ~["\u0000"-"\u0020", "(", ")", "*", "+", "-", ".", "/", "0"-"9", ":", "^", "\u00B2", "\u00B3", "\u00B7", "\u00B9", "\u2070", "\u2074", "\u2075", "\u2076", "\u2077", "\u2078", "\u2079" ] >
+       | <#EXTENDED_CHAR: ~["\u0000"-"\u0020", "(", ")", "*", "+", "-", ".", "/", ":", "^", "\u00B2", "\u00B3", "\u00B7", "\u00B9", "\u2070", "\u2074", "\u2075", "\u2076", "\u2077", "\u2078", "\u2079" ] > }
+TOKEN: { <PLUS: "+" > }
+TOKEN: { <MINUS: "-" > }
+TOKEN: { <ASTERISK: "*" > }
+TOKEN: { <MIDDLE_DOT: "\u00B7" > }
+TOKEN: { <SOLIDUS: "/" > }
+TOKEN: { <CARET: "^" > }
+TOKEN: { <COLON: ":" > }
+TOKEN: { <OPEN_PAREN: "(" > }
+TOKEN: { <CLOSE_PAREN: ")" > }
+TOKEN: { <INTEGER: (<DIGIT>)+ > }
+TOKEN: { <SUPERSCRIPT_INTEGER: (<SUPERSCRIPT_DIGIT>)+ > }
+TOKEN: { <FLOATING_POINT: (<DIGIT>)* (".")? (<DIGIT>)+ (("e" | "E") ((<PLUS>)|(<MINUS>))? (<DIGIT>)+)? > }
+TOKEN: { <LOG: "l" "o" "g" > 
+       | <NAT_LOG: "l" "n" >
+       | <E: "e" > }
+TOKEN: { <UNIT_IDENTIFIER: <INITIAL_CHAR> (<EXTENDED_CHAR>)* > }
+
+//
+// Parser productions
+//
+
+javax.measure.unit.Unit parseUnit () :
+    {
+        javax.measure.unit.Unit result;
+    }
+{
+    result=CompoundExpr() <EOF>
+    { 
+        return result; 
+    }
+}
+
+javax.measure.unit.Unit CompoundExpr () :
+    { 
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        javax.measure.unit.Unit temp = javax.measure.unit.Unit.ONE; 
+    }
+{
+(
+    result=AddExpr() 
+    ( 
+      <COLON> temp=AddExpr() { result=result.compound(temp); } 
+    )*
+    { return result; }
+)
+}
+
+javax.measure.unit.Unit AddExpr () :
+    { 
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        Number n1 = null;
+        Token sign1 = null;
+        Number n2 = null;
+        Token sign2 = null;
+    }
+{
+(
+    ( LOOKAHEAD(NumberExpr() Sign()) n1=NumberExpr() sign1=Sign() )? 
+    result=MulExpr() 
+    ( sign2=Sign() n2=NumberExpr() )?
+    {
+        if (n1 != null) {
+            if (sign1.image.equals("-")) {
+                result = result.times(-1);
+            }
+            result = result.plus(n1.doubleValue());
+        }
+        if (n2 != null) {
+            double offset = n2.doubleValue();
+            if (sign2.image.equals("-")) {
+                offset = -offset;
+            }
+            result = result.plus(offset);
+        }
+        return result;
+    }
+)
+}
+
+javax.measure.unit.Unit MulExpr () :
+    { 
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        javax.measure.unit.Unit temp = javax.measure.unit.Unit.ONE;
+    }
+{
+(
+    result=ExponentExpr() 
+    ( 
+      ( (<ASTERISK> | <MIDDLE_DOT>) temp=ExponentExpr() { result=result.times(temp); } ) 
+    |
+      ( <SOLIDUS> temp=ExponentExpr() { result=result.divide(temp); } )
+    )*
+    { return result; }
+)
+}
+
+javax.measure.unit.Unit ExponentExpr () :
+    { 
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        javax.measure.unit.Unit temp = javax.measure.unit.Unit.ONE;
+        Exponent exponent = null;
+        Token token = null;
+    }
+{
+(
+    LOOKAHEAD((<INTEGER> | <E>) <CARET>)
+    ( ((token=<INTEGER>) | token=<E>) <CARET> result=AtomicExpr() )
+    { 
+        double base;
+        if (token.kind == INTEGER) {
+            base = Integer.parseInt(token.image);
+        } else {
+            base = StrictMath.E;
+        }
+        return result.transform(new javax.measure.converter.LogConverter(base).inverse());
+    }
+|
+    ( result=AtomicExpr() ( exponent=Exp() )? )
+    {
+        if (exponent != null) {
+            if (exponent.pow != 1) {
+                result = result.pow(exponent.pow);
+            }
+            if (exponent.root != 1) {
+                result = result.root(exponent.root);
+            }
+        }
+        return result;
+    }
+|
+    ( ( ( <LOG> (token=<INTEGER>)? ) | token=<NAT_LOG> ) <OPEN_PAREN> result=AddExpr() <CLOSE_PAREN> )
+    { 
+        double base = 10;
+        if (token != null) {
+            if (token.kind == INTEGER) {
+                base = Integer.parseInt(token.image);
+            } else if (token.kind == NAT_LOG) {
+                base = StrictMath.E;
+            }
+        }
+        return result.transform(new javax.measure.converter.LogConverter(base));
+    }
+)
+}
+
+javax.measure.unit.Unit AtomicExpr () :
+    { 
+        javax.measure.unit.Unit result = javax.measure.unit.Unit.ONE;
+        javax.measure.unit.Unit temp = javax.measure.unit.Unit.ONE;
+        Number n = null;
+        Token token = null;
+    }
+{
+(
+    ( n=NumberExpr() )
+    { 
+        if (n instanceof Integer) {
+            return result.times(n.intValue());
+        } else {
+            return result.times(n.doubleValue());
+        }
+    }
+|
+    ( token=<UNIT_IDENTIFIER> )
+    {
+        javax.measure.unit.Unit unit = _symbols.getUnit(token.image);
+        if (unit == null) {
+            Prefix prefix = _symbols.getPrefix(token.image);
+            if (prefix != null) {
+                String prefixSymbol = _symbols.getSymbol(prefix);
+                unit = _symbols.getUnit(token.image.substring(prefixSymbol.length()));
+                if (unit != null) {
+                    return unit.transform(prefix.getConverter());
+                } 
+            }
+            throw new ParseException();
+        } else {
+            return unit;
+        }
+    }
+|
+    ( <OPEN_PAREN> result=AddExpr() <CLOSE_PAREN> )
+    { 
+        return result; 
+    }
+)
+}
+
+Token Sign () :
+    { 
+        Token result = null;
+    }
+{
+( 
+    (result=<PLUS>) 
+| 
+    (result=<MINUS>) 
+)
+    { 
+        return result; 
+    }
+}
+
+Number NumberExpr () :
+    { 
+        Token token = null;
+    }
+{
+(
+    ( token=<INTEGER> )
+    { 
+        return Long.valueOf(token.image); 
+    }
+|
+    ( token=<FLOATING_POINT> )
+    { 
+        return Double.valueOf(token.image); 
+    }
+)
+}
+
+Exponent Exp () :
+    {
+        Token powSign = null;
+        Token powToken = null;
+        Token rootSign = null;
+        Token rootToken = null;
+    }
+{
+(
+    ( 
+      <CARET> 
+      ( 
+        ( (powSign=Sign())? powToken=<INTEGER> )
+        { 
+            int pow = Integer.parseInt(powToken.image);
+            if ((powSign != null) && powSign.image.equals("-")) {
+                pow = -pow;
+            }
+            return new Exponent(pow, 1);
+        }   
+      |
+        ( <OPEN_PAREN> (powSign=Sign())? powToken=<INTEGER> ( <SOLIDUS> (rootSign=Sign())? rootToken=<INTEGER> )? <CLOSE_PAREN> )
+        { 
+            pow = Integer.parseInt(powToken.image);
+            if ((powSign != null) && powSign.image.equals("-")) {
+                pow = -pow;
+            }
+            int root = 1;
+            if (rootToken != null) {
+                root = Integer.parseInt(rootToken.image);
+                if ((rootSign != null) && rootSign.image.equals("-")) {
+                    root = -root;
+                }
+            }
+            return new Exponent(pow, root);
+        }   
+      )
+    )
+|
+    ( powToken=<SUPERSCRIPT_INTEGER> )
+    {
+        int pow = 0;
+        for (int i = 0; i < powToken.image.length(); i += 1) {
+            pow *= 10;
+            switch (powToken.image.charAt(i)) {
+                case '\u00B9': pow += 1; break;
+                case '\u00B2': pow += 2; break;
+                case '\u00B3': pow += 3; break;
+                case '\u2074': pow += 4; break;
+                case '\u2075': pow += 5; break;
+                case '\u2076': pow += 6; break;
+                case '\u2077': pow += 7; break;
+                case '\u2078': pow += 8; break;
+                case '\u2079': pow += 9; break;
+            }
+        }
+        return new Exponent(pow, 1);
+    }
+)
+}
diff --git a/src/main/java/javax/measure/unit/format/UnitParserConstants.java b/src/main/java/javax/measure/unit/format/UnitParserConstants.java
new file mode 100644
index 0000000..06643eb
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UnitParserConstants.java
@@ -0,0 +1,54 @@
+/* Generated By:JavaCC: Do not edit this line. UnitParserConstants.java */
+package javax.measure.unit.format;
+
+interface UnitParserConstants {
+
+  int EOF = 0;
+  int DIGIT = 1;
+  int SUPERSCRIPT_DIGIT = 2;
+  int INITIAL_CHAR = 3;
+  int EXTENDED_CHAR = 4;
+  int PLUS = 5;
+  int MINUS = 6;
+  int ASTERISK = 7;
+  int MIDDLE_DOT = 8;
+  int SOLIDUS = 9;
+  int CARET = 10;
+  int COLON = 11;
+  int OPEN_PAREN = 12;
+  int CLOSE_PAREN = 13;
+  int INTEGER = 14;
+  int SUPERSCRIPT_INTEGER = 15;
+  int FLOATING_POINT = 16;
+  int LOG = 17;
+  int NAT_LOG = 18;
+  int E = 19;
+  int UNIT_IDENTIFIER = 20;
+
+  int DEFAULT = 0;
+
+  String[] tokenImage = {
+    "<EOF>",
+    "<DIGIT>",
+    "<SUPERSCRIPT_DIGIT>",
+    "<INITIAL_CHAR>",
+    "<EXTENDED_CHAR>",
+    "\"+\"",
+    "\"-\"",
+    "\"*\"",
+    "\"\\u00b7\"",
+    "\"/\"",
+    "\"^\"",
+    "\":\"",
+    "\"(\"",
+    "\")\"",
+    "<INTEGER>",
+    "<SUPERSCRIPT_INTEGER>",
+    "<FLOATING_POINT>",
+    "<LOG>",
+    "<NAT_LOG>",
+    "\"e\"",
+    "<UNIT_IDENTIFIER>",
+  };
+
+}
diff --git a/src/main/java/javax/measure/unit/format/UnitParserTokenManager.java b/src/main/java/javax/measure/unit/format/UnitParserTokenManager.java
new file mode 100644
index 0000000..e0135b2
--- /dev/null
+++ b/src/main/java/javax/measure/unit/format/UnitParserTokenManager.java
@@ -0,0 +1,449 @@
+/* Generated By:JavaCC: Do not edit this line. UnitParserTokenManager.java */
+package javax.measure.unit.format;
+
+class UnitParserTokenManager implements UnitParserConstants
+{
+  public  java.io.PrintStream debugStream = System.out;
+  public  void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
+private final int jjStopStringLiteralDfa_0(int pos, long active0)
+{
+   switch (pos)
+   {
+      default :
+         return -1;
+   }
+}
+private final int jjStartNfa_0(int pos, long active0)
+{
+   return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
+}
+private final int jjStopAtPos(int pos, int kind)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   return pos + 1;
+}
+private final int jjStartNfaWithStates_0(int pos, int kind, int state)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) { return pos + 1; }
+   return jjMoveNfa_0(state, pos + 1);
+}
+private final int jjMoveStringLiteralDfa0_0()
+{
+   switch(curChar)
+   {
+      case 40:
+         return jjStopAtPos(0, 12);
+      case 41:
+         return jjStopAtPos(0, 13);
+      case 42:
+         return jjStopAtPos(0, 7);
+      case 43:
+         return jjStopAtPos(0, 5);
+      case 45:
+         return jjStopAtPos(0, 6);
+      case 47:
+         return jjStopAtPos(0, 9);
+      case 58:
+         return jjStopAtPos(0, 11);
+      case 94:
+         return jjStopAtPos(0, 10);
+      case 101:
+         return jjStartNfaWithStates_0(0, 19, 7);
+      case 183:
+         return jjStopAtPos(0, 8);
+      default :
+         return jjMoveNfa_0(6, 0);
+   }
+}
+private final void jjCheckNAdd(int state)
+{
+   if (jjrounds[state] != jjround)
+   {
+      jjstateSet[jjnewStateCnt++] = state;
+      jjrounds[state] = jjround;
+   }
+}
+private final void jjAddStates(int start, int end)
+{
+   do {
+      jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+   } while (start++ != end);
+}
+private final void jjCheckNAddTwoStates(int state1, int state2)
+{
+   jjCheckNAdd(state1);
+   jjCheckNAdd(state2);
+}
+private final void jjCheckNAddStates(int start, int end)
+{
+   do {
+      jjCheckNAdd(jjnextStates[start]);
+   } while (start++ != end);
+}
+private final void jjCheckNAddStates(int start)
+{
+   jjCheckNAdd(jjnextStates[start]);
+   jjCheckNAdd(jjnextStates[start + 1]);
+}
+static final long[] jjbitVec0 = {
+   0x0L, 0x0L, 0x20c000000000000L, 0x0L
+};
+static final long[] jjbitVec1 = {
+   0x0L, 0x3f1000000000000L, 0x0L, 0x0L
+};
+static final long[] jjbitVec2 = {
+   0xfffffffefffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+static final long[] jjbitVec4 = {
+   0x0L, 0x0L, 0xfd73ffffffffffffL, 0xffffffffffffffffL
+};
+static final long[] jjbitVec5 = {
+   0xffffffffffffffffL, 0xfc0effffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+private final int jjMoveNfa_0(int startState, int curPos)
+{
+   int[] nextStates;
+   int startsAt = 0;
+   jjnewStateCnt = 15;
+   int i = 1;
+   jjstateSet[0] = startState;
+   int j, kind = 0x7fffffff;
+   for (;;)
+   {
+      if (++jjround == 0x7fffffff)
+         ReInitRounds();
+      if (curChar < 64)
+      {
+         long l = 1L << curChar;
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 6:
+                  if ((0xf80010fe00000000L & l) != 0L)
+                  {
+                     if (kind > 20)
+                        kind = 20;
+                     jjCheckNAdd(7);
+                  }
+                  else if ((0x3ff000000000000L & l) != 0L)
+                  {
+                     if (kind > 14)
+                        kind = 14;
+                     jjCheckNAddStates(0, 4);
+                  }
+                  else if (curChar == 46)
+                     jjCheckNAdd(2);
+                  break;
+               case 1:
+                  if (curChar == 46)
+                     jjCheckNAdd(2);
+                  break;
+               case 2:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 16)
+                     kind = 16;
+                  jjCheckNAddTwoStates(2, 3);
+                  break;
+               case 4:
+                  if ((0x280000000000L & l) != 0L)
+                     jjCheckNAdd(5);
+                  break;
+               case 5:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 16)
+                     kind = 16;
+                  jjCheckNAdd(5);
+                  break;
+               case 7:
+                  if ((0xfbff10fe00000000L & l) == 0L)
+                     break;
+                  if (kind > 20)
+                     kind = 20;
+                  jjCheckNAdd(7);
+                  break;
+               case 8:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 14)
+                     kind = 14;
+                  jjCheckNAddStates(0, 4);
+                  break;
+               case 9:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 14)
+                     kind = 14;
+                  jjCheckNAdd(9);
+                  break;
+               case 10:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 16)
+                     kind = 16;
+                  jjCheckNAddStates(5, 8);
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else if (curChar < 128)
+      {
+         long l = 1L << (curChar & 077);
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 6:
+                  if ((0xffffffffbfffffffL & l) != 0L)
+                  {
+                     if (kind > 20)
+                        kind = 20;
+                     jjCheckNAdd(7);
+                  }
+                  if (curChar == 108)
+                     jjAddStates(9, 10);
+                  break;
+               case 3:
+                  if ((0x2000000020L & l) != 0L)
+                     jjAddStates(11, 12);
+                  break;
+               case 7:
+                  if ((0xffffffffbfffffffL & l) == 0L)
+                     break;
+                  if (kind > 20)
+                     kind = 20;
+                  jjCheckNAdd(7);
+                  break;
+               case 11:
+                  if (curChar == 108)
+                     jjAddStates(9, 10);
+                  break;
+               case 12:
+                  if (curChar == 111)
+                     jjstateSet[jjnewStateCnt++] = 13;
+                  break;
+               case 13:
+                  if (curChar == 103 && kind > 17)
+                     kind = 17;
+                  break;
+               case 14:
+                  if (curChar == 110 && kind > 18)
+                     kind = 18;
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else
+      {
+         int hiByte = (int)(curChar >> 8);
+         int i1 = hiByte >> 6;
+         long l1 = 1L << (hiByte & 077);
+         int i2 = (curChar & 0xff) >> 6;
+         long l2 = 1L << (curChar & 077);
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 6:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                  {
+                     if (kind > 15)
+                        kind = 15;
+                     jjCheckNAdd(0);
+                  }
+                  if (jjCanMove_1(hiByte, i1, i2, l1, l2))
+                  {
+                     if (kind > 20)
+                        kind = 20;
+                     jjCheckNAdd(7);
+                  }
+                  break;
+               case 0:
+                  if (!jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     break;
+                  if (kind > 15)
+                     kind = 15;
+                  jjCheckNAdd(0);
+                  break;
+               case 7:
+                  if (!jjCanMove_1(hiByte, i1, i2, l1, l2))
+                     break;
+                  if (kind > 20)
+                     kind = 20;
+                  jjCheckNAdd(7);
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      if (kind != 0x7fffffff)
+      {
+         jjmatchedKind = kind;
+         jjmatchedPos = curPos;
+         kind = 0x7fffffff;
+      }
+      ++curPos;
+      if ((i = jjnewStateCnt) == (startsAt = 15 - (jjnewStateCnt = startsAt)))
+         return curPos;
+      try { curChar = input_stream.readChar(); }
+      catch(java.io.IOException e) { return curPos; }
+   }
+}
+static final int[] jjnextStates = {
+   9, 1, 2, 3, 10, 1, 2, 3, 10, 12, 14, 4, 5, 
+};
+private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, long l2)
+{
+   switch(hiByte)
+   {
+      case 0:
+         return ((jjbitVec0[i2] & l2) != 0L);
+      case 32:
+         return ((jjbitVec1[i2] & l2) != 0L);
+      default : 
+         return false;
+   }
+}
+private static final boolean jjCanMove_1(int hiByte, int i1, int i2, long l1, long l2)
+{
+   switch(hiByte)
+   {
+      case 0:
+         return ((jjbitVec4[i2] & l2) != 0L);
+      case 32:
+         return ((jjbitVec5[i2] & l2) != 0L);
+      default : 
+         if ((jjbitVec2[i1] & l1) != 0L)
+            return true;
+         return false;
+   }
+}
+public static final String[] jjstrLiteralImages = {
+"", null, null, null, null, "\53", "\55", "\52", "\267", "\57", "\136", "\72", 
+"\50", "\51", null, null, null, null, null, "\145", null, };
+public static final String[] lexStateNames = {
+   "DEFAULT", 
+};
+protected SimpleCharStream input_stream;
+private final int[] jjrounds = new int[15];
+private final int[] jjstateSet = new int[30];
+protected char curChar;
+public UnitParserTokenManager(SimpleCharStream stream){
+   if (SimpleCharStream.staticFlag)
+      throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
+   input_stream = stream;
+}
+public UnitParserTokenManager(SimpleCharStream stream, int lexState){
+   this(stream);
+   SwitchTo(lexState);
+}
+public void ReInit(SimpleCharStream stream)
+{
+   jjmatchedPos = jjnewStateCnt = 0;
+   curLexState = defaultLexState;
+   input_stream = stream;
+   ReInitRounds();
+}
+private final void ReInitRounds()
+{
+   int i;
+   jjround = 0x80000001;
+   for (i = 15; i-- > 0;)
+      jjrounds[i] = 0x80000000;
+}
+public void ReInit(SimpleCharStream stream, int lexState)
+{
+   ReInit(stream);
+   SwitchTo(lexState);
+}
+public void SwitchTo(int lexState)
+{
+   if (lexState >= 1 || lexState < 0)
+      throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
+   else
+      curLexState = lexState;
+}
+
+protected Token jjFillToken()
+{
+   Token t = Token.newToken(jjmatchedKind);
+   t.kind = jjmatchedKind;
+   String im = jjstrLiteralImages[jjmatchedKind];
+   t.image = (im == null) ? input_stream.GetImage() : im;
+   t.beginLine = input_stream.getBeginLine();
+   t.beginColumn = input_stream.getBeginColumn();
+   t.endLine = input_stream.getEndLine();
+   t.endColumn = input_stream.getEndColumn();
+   return t;
+}
+
+int curLexState = 0;
+int defaultLexState = 0;
+int jjnewStateCnt;
+int jjround;
+int jjmatchedPos;
+int jjmatchedKind;
+
+public Token getNextToken() 
+{
+  int kind;
+  Token specialToken = null;
+  Token matchedToken;
+  int curPos = 0;
+
+  EOFLoop :
+  for (;;)
+  {   
+   try   
+   {     
+      curChar = input_stream.BeginToken();
+   }     
+   catch(java.io.IOException e)
+   {        
+      jjmatchedKind = 0;
+      matchedToken = jjFillToken();
+      return matchedToken;
+   }
+
+   jjmatchedKind = 0x7fffffff;
+   jjmatchedPos = 0;
+   curPos = jjMoveStringLiteralDfa0_0();
+   if (jjmatchedKind != 0x7fffffff)
+   {
+      if (jjmatchedPos + 1 < curPos)
+         input_stream.backup(curPos - jjmatchedPos - 1);
+         matchedToken = jjFillToken();
+         return matchedToken;
+   }
+   int error_line = input_stream.getEndLine();
+   int error_column = input_stream.getEndColumn();
+   String error_after = null;
+   boolean EOFSeen = false;
+   try { input_stream.readChar(); input_stream.backup(1); }
+   catch (java.io.IOException e1) {
+      EOFSeen = true;
+      error_after = curPos <= 1 ? "" : input_stream.GetImage();
+      if (curChar == '\n' || curChar == '\r') {
+         error_line++;
+         error_column = 0;
+      }
+      else
+         error_column++;
+   }
+   if (!EOFSeen) {
+      input_stream.backup(1);
+      error_after = curPos <= 1 ? "" : input_stream.GetImage();
+   }
+   throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
+  }
+}
+
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/jsr-275.git



More information about the Pkg-grass-devel mailing list