This commit was manufactured by cvs2svn to create tag
'release-2-0-d01'.

X-SVN-Rev: 6490
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..96e1c11
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,72 @@
+* text=auto !eol
+
+*.c text !eol
+*.cc text !eol
+*.classpath text !eol
+*.cpp text !eol
+*.css text !eol
+*.dsp text !eol
+*.dsw text !eol
+*.filters text !eol
+*.h text !eol
+*.htm text !eol
+*.html text !eol
+*.in text !eol
+*.java text !eol
+*.launch text !eol
+*.mak text !eol
+*.md text !eol
+*.MF text !eol
+*.mk text !eol
+*.pl text !eol
+*.pm text !eol
+*.project text !eol
+*.properties text !eol
+*.py text !eol
+*.rc text !eol
+*.sh text eol=lf
+*.sln text !eol
+*.stub text !eol
+*.txt text !eol
+*.ucm text !eol
+*.vcproj text !eol
+*.vcxproj text !eol
+*.xml text !eol
+*.xsl text !eol
+*.xslt text !eol
+Makefile text !eol
+configure text !eol
+LICENSE text !eol
+README text !eol
+
+*.bin -text
+*.brk -text
+*.cnv -text
+*.icu -text
+*.res -text
+*.nrm -text
+*.spp -text
+*.tri2 -text
+
+src/com/ibm/data/misc/english.dict -text
+src/com/ibm/text/resources/Transliterator_Fullwidth_Halfwidth.utf8.txt -text
+src/com/ibm/text/resources/Transliterator_Han_Pinyin.utf8.txt -text
+src/com/ibm/text/resources/Transliterator_Hiragana_Katakana.utf8.txt -text
+src/com/ibm/text/resources/Transliterator_Kanji_English.utf8.txt -text
+src/com/ibm/text/resources/Transliterator_Kanji_OnRomaji.utf8.txt -text
+src/com/ibm/text/resources/Transliterator_Latin_Jamo.utf8.txt -text
+src/com/ibm/text/resources/thai_dict -text
+src/com/ibm/text/resources/unames.dat -text
+src/com/ibm/text/resources/uprops.dat -text
+src/data/holidays_jp.ucs -text
+src/data/thai6.ucs -text
+src/data/unicode/Draft-TestSuite.txt -text
+
+# The following file types are stored in Git-LFS.
+*.jar filter=lfs diff=lfs merge=lfs -text
+*.dat filter=lfs diff=lfs merge=lfs -text
+*.zip filter=lfs diff=lfs merge=lfs -text
+*.gz filter=lfs diff=lfs merge=lfs -text
+*.bz2 filter=lfs diff=lfs merge=lfs -text
+*.gif filter=lfs diff=lfs merge=lfs -text
+
diff --git a/build.bat b/build.bat
new file mode 100755
index 0000000..1d1c346
--- /dev/null
+++ b/build.bat
@@ -0,0 +1,15 @@
+@echo off
+
+REM *******************************************************************************
+REM * Copyright (C) 1997-2000, International Business Machines Corporation and    *
+REM * others. All Rights Reserved.                                                *
+REM *******************************************************************************
+
+REM $Source: /xsrl/Nsvn/icu/icu4j/Attic/build.bat,v $ 
+REM $Date: 2000/03/15 00:40:27 $ 
+REM $Revision: 1.4 $
+
+REM *******************************************************************************
+
+REM convience bat file to build with
+java -classpath "build\icu4jtools.jar;jakarta-ant\lib\ant.jar;jakarta-ant\lib\xml.jar;%CLASSPATH%" org.apache.tools.ant.Main %1 %2 %3 %4 %5
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..8f5de2a
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,26 @@
+#/*
+#*******************************************************************************
+#* Copyright (C) 1997-2000, International Business Machines Corporation and    *
+#* others. All Rights Reserved.                                                *
+#*******************************************************************************
+#*
+#* $Source: /xsrl/Nsvn/icu/icu4j/Attic/build.sh,v $ 
+#* $Date: 2000/03/15 00:40:27 $ 
+#* $Revision: 1.3 $
+#*
+#*****************************************************************************************
+#*/
+#!/bin/sh
+
+ADDL_CLASSPATH=build/icu4jtoolz.zip:jakarta-ant/lib/ant.jar:jakarta-ant/lib/xml.jar
+
+if [ "$CLASSPATH" != "" ] ; then
+  CLASSPATH=$CLASSPATH:$ADDL_CLASSPATH
+else
+ CLASSPATH=$ADDL_CLASSPATH
+fi
+export CLASSPATH
+
+echo Building with classpath $CLASSPATH
+
+java org.apache.tools.ant.Main $*
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..78ecc58
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,175 @@
+<!-- 
+/*
+*******************************************************************************
+* Copyright (C) 1997-2001, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+* $Source: /xsrl/Nsvn/icu/icu4j/build.xml,v $ 
+* $Date: 2001/10/23 20:56:32 $ 
+* $Revision: 1.38 $
+*
+*******************************************************************************
+* This is the ant build file for ICU4J.  See readme.html for more information.
+*/
+-->
+
+<project name="ICU4J" default="core" basedir=".">
+
+  <target name="init">
+    <tstamp/>
+    <property name="src.dir" value="src"/>
+    <property name="doc.dir" value="doc"/>
+    <property name="build.dir" value="classes"/>
+    <property name="obsolete.dir" value="build"/>
+    <property name="jar.file" value="icu4j.jar"/>
+    <property name="zipbin.file" value="../icu4jbin${DSTAMP}.zip"/>
+    <property name="zip.file" value="../icu4j${DSTAMP}.zip"/>
+    <property name="classpath" value="${build.dir}"/>
+    <property name="build.compiler" value="classic"/>
+    <property name="richedit.dist.dir" value="richeditDist"/>
+    <property name="richedit.cont.dir" value="richedit"/>
+    <property name="richedit.archive.dir" value="${richedit.dist.dir}/${richedit.cont.dir}"/>
+    <property name="richedit.jar.file" value="${richedit.archive.dir}/richedit.jar"/>
+    <property name="richedit.doc.dir" value="${richedit.archive.dir}/doc"/>
+    <property name="richedit.zip.file" value="${richedit.dist.dir}/richedit.zip"/>
+    <property name="richedit.manifest" value="${richedit.dist.dir}/manifest.stub"/>
+  </target>
+
+  <target name="all" depends="core,tests,tools,demos,jar,docs"/>
+  
+  <target name="core" depends="init,coreData">
+    <mkdir dir="${build.dir}"/>
+    <copy file="${src.dir}/com/ibm/text/resources/thai_dict"
+           todir="${build.dir}/com/ibm/text/resources/"/>
+    <javac includes="com/ibm/util/**/*.java,com/ibm/text/**/*.java,com/ibm/math/**/*.java,com/ibm/richtext/**/*.java"
+           excludes="**/CVS/**/*"
+           srcdir="${src.dir}"
+    	   destdir="${build.dir}" 
+    	   classpath="${classpath}"
+           debug="on" deprecation="off"/>
+  </target>
+  
+  <target name="tests" depends="core,testData">
+    <javac includes="com/ibm/test/**/*.java,com/ibm/icu/test/**/*.java"
+           excludes="**/CVS/**/*"
+    	   srcdir="${src.dir}"
+    	   destdir="${build.dir}" 
+    	   classpath="${classpath}"
+           debug="on" deprecation="off"/>
+  </target>
+  
+  <target name="demos" depends="core,testData">
+    <javac includes="com/ibm/demo/**/*.java"
+           excludes="**/CVS/**/*"
+    	   srcdir="${src.dir}"
+    	   destdir="${build.dir}" 
+    	   classpath="${classpath}"
+           debug="on" deprecation="off"/>
+  </target>
+  
+  <target name="tools" depends="core">
+    <javac includes="com/ibm/tools/**/*.java"
+           excludes="**/CVS/**/*"
+    	   srcdir="${src.dir}"
+    	   destdir="${build.dir}" 
+    	   classpath="${classpath}"
+           debug="on" deprecation="off"/>
+  </target>
+  
+  <target name="docs" depends="core">
+    <mkdir dir="${doc.dir}"/>
+    <javadoc packagenames="com.ibm.util,com.ibm.text,com.ibm.math,com.ibm.richtext.awtui,com.ibm.richtext.swingui,com.ibm.richtext.textpanel,com.ibm.richtext.styledtext,com.ibm.textlayout.attributes,com.ibm.richtext.print"
+              sourcepath="${src.dir}"
+    		  destdir="${doc.dir}"
+    		  nodeprecatedlist="true"
+			  windowtitle="icu4j"
+			  doctitle="icu4j"
+			  encoding="iso-8859-1"
+			  docencoding="iso-8859-1"
+			  bottom="&lt;font size=-1>Copyright (c) 1998-2000 IBM Corporation and others.&lt;/font>"
+    		  />    		  
+  </target>
+
+  <target name ="coreData" depends="init">
+    <copy todir="${build.dir}/com/ibm/text/resources">
+      <fileset dir="${src.dir}/com/ibm/text/resources"
+               includes="Transliterator_*.txt,*.dat"/>
+    </copy>
+  </target>
+
+  <target name ="testData" depends="init">
+    <copy file="${src.dir}/com/ibm/data/misc/english.dict"
+    	   todir="${build.dir}/com/ibm/data/misc/"/>
+  </target>
+  
+  <target name="jar" depends="core">
+    <jar jarfile="${jar.file}"
+         includes="com/ibm/util/**/*,com/ibm/text/**/*,com/ibm/math/**/*,com/ibm/richtext/**/*"
+         basedir="${build.dir}"/>
+  </target>
+
+  <target name="richeditJar" depends="core">
+    <jar jarfile="${richedit.jar.file}"
+         includes="com/ibm/richtext/**/*,com/ibm/textlayout/**/*"
+         basedir="${build.dir}"
+         manifest="${richedit.manifest}"/>
+  </target>
+
+    <!-- 
+        Note:  I used to use -linkoffline http://java.sun.com/products/jdk/1.2/docs/api/ C:\jdk1.2.2\docs\api
+        This links to core docs on Sun's site - a very nice feature.  But it requires the 1.2 docs to be
+        on the build machine at a known location.
+    -->
+  <target name="richeditDocs" depends="core">
+    <mkdir dir="${richedit.doc.dir}"/>
+    <javadoc  packagenames="com.ibm.richtext.awtui,com.ibm.richtext.swingui,com.ibm.richtext.textpanel,com.ibm.richtext.styledtext,com.ibm.textlayout.attributes,com.ibm.richtext.print"
+              sourcepath="${src.dir}"
+    		  destdir="${richedit.doc.dir}"
+    		  nodeprecatedlist="true"
+			  windowtitle="RichEdit Control"
+			  doctitle="RichEdit Control"
+			  encoding="iso-8859-1"
+			  docencoding="iso-8859-1"
+			  bottom="&lt;font size=-1>Copyright (c) 1998-2000 IBM Corporation and others.&lt;/font>"
+    		  />    		  
+  </target>
+
+  <target name="richeditZip" depends="richeditJar,richeditDocs">
+    <!--Create a zip archive of the richedit jar and readme -->
+    <zip zipfile="${richedit.zip.file}"
+         basedir="${richedit.dist.dir}"
+         includes="${richedit.cont.dir}/**/*"/>
+  </target>
+  
+  <target name="zipbin" depends="docs,jar">
+    <!--Create a zip archive of the source, docs, and jar file for
+    distribution.  The zip file will be created in the directory above
+    the root ICU4J directory. The exclude pattern ${src.dir}/data/unicode/UnicodeData-*.txt
+    and ${src.dir}/data/unicode/SpecialCasing-*.txt
+    eliminates old archive copies like SpecialCasing-2.txt and
+    UnicodeData-2.1.8.txt etc -->
+    <zip zipfile="${zipbin.file}"
+         basedir="."
+         excludes="${richedit.dist.dir},test_*,${src.dir}/data/unicode/UnicodeData-*.txt,${src.dir}/data/unicode/SpecialCasing-*.txt,${src.dir}/data/unicode/CompositionExclusions-*.txt,${obsolete.dir}/**,**/*~,${src.dir}/**/*.class,${build.dir}/**,**/CVS/**/*"/>
+  </target>
+
+  <target name="zip" depends="init">
+    <!--Create a zip archive of just the source for distribution.  The
+    zip file will be created in the directory above the root ICU4J
+    directory. The exclude pattern ${src.dir}/data/unicode/UnicodeData-*.txt
+    and ${src.dir}/data/unicode/SpecialCasing-*.txt
+    eliminates old archive copies like SpecialCasing-2.txt and
+    UnicodeData-2.1.8.txt -->
+    <zip zipfile="${zip.file}"
+         basedir="."
+         excludes="${richedit.dist.dir},test_*,${src.dir}/data/unicode/UnicodeData-*.txt,${src.dir}/data/unicode/SpecialCasing-*.txt,${src.dir}/data/unicode/CompositionExclusions-*.txt,${obsolete.dir}/**,**/*~,${src.dir}/**/*.class,${build.dir}/**,**/CVS/**/*,${doc.dir}/**,${jar.file}"/>
+  </target>
+
+  <target name="clean" depends="init">
+    <delete dir="${build.dir}"/>
+    <delete dir="${doc.dir}"/>
+    <delete  file="${jar.file}"/>
+  </target>
+
+</project>
diff --git a/buildall.bat b/buildall.bat
new file mode 100755
index 0000000..40e098f
--- /dev/null
+++ b/buildall.bat
@@ -0,0 +1,2 @@
+javac -sourcepath src -d classes -classpath classes src/com/ibm/math/*.java src/com/ibm/util/*.java src/com/ibm/util/resources/*.java src/com/ibm/text/*.java src/com/ibm/text/resources/*.java src/com/ibm/text/components/*.java src/com/ibm/test/*.java src/com/ibm/test/bnf/*.java src/com/ibm/test/calendar/*.java src/com/ibm/test/compression/*.java src/com/ibm/test/normalizer/*.java src/com/ibm/test/rbbi/*.java src/com/ibm/test/rbnf/*.java src/com/ibm/test/search/*.java src/com/ibm/test/topleveltest/*.java src/com/ibm/test/translit/*.java src/com/ibm/demo/*.java src/com/ibm/demo/calendar/*.java src/com/ibm/demo/holiday/*.java src/com/ibm/demo/rbbi/*.java src/com/ibm/demo/rbnf/*.java src/com/ibm/demo/translit/*.java src/com/ibm/tools/compression/*.java src/com/ibm/tools/normalizer/*.java src/com/ibm/tools/RuleBasedBreakIterator/*.java
+javadoc -sourcepath src -d docs -classpath classes src/com/ibm/math/*.java src/com/ibm/util/*.java src/com/ibm/util/resources/*.java src/com/ibm/text/*.java src/com/ibm/text/resources/*.java src/com/ibm/text/components/*.java src/com/ibm/test/*.java src/com/ibm/test/bnf/*.java src/com/ibm/test/calendar/*.java src/com/ibm/test/compression/*.java src/com/ibm/test/normalizer/*.java src/com/ibm/test/rbbi/*.java src/com/ibm/test/rbnf/*.java src/com/ibm/test/search/*.java src/com/ibm/test/topleveltest/*.java src/com/ibm/test/translit/*.java src/com/ibm/demo/*.java src/com/ibm/demo/calendar/*.java src/com/ibm/demo/holiday/*.java src/com/ibm/demo/rbbi/*.java src/com/ibm/demo/rbnf/*.java src/com/ibm/demo/translit/*.java src/com/ibm/tools/compression/*.java src/com/ibm/tools/normalizer/*.java src/com/ibm/tools/RuleBasedBreakIterator/*.java
diff --git a/license.html b/license.html
new file mode 100644
index 0000000..8ab076a
--- /dev/null
+++ b/license.html
@@ -0,0 +1,34 @@
+<html>
+
+<head>
+<title>ICU4J license - ICU4J 1.3.1 and later</title>
+</head>
+
+<body BGCOLOR="#ffffff">
+<h2>ICU4J license - ICU4J 1.3.1 and later</h2>
+
+<p>COPYRIGHT AND PERMISSION NOTICE</p>
+
+<p>
+Copyright (c) 1995-2001 International Business Machines Corporation and others
+</p>
+<p>
+All rights reserved.
+</p>
+<p>
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons
+to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation.
+</p>
+<p>
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+</p>
+<p>
+Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder.
+</p>
+
+<hr>
+<small>
+All trademarks and registered trademarks mentioned herein are the property of their respective owners.
+</small>
+</body>
+</html>
diff --git a/readme.html b/readme.html
new file mode 100644
index 0000000..d46defd
--- /dev/null
+++ b/readme.html
@@ -0,0 +1,414 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>ReadMe for ICU4J</title>
+</head>
+
+<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080" lang="EN-US">
+
+<h2>ReadMe: International Components for Unicode for Java</h2>
+
+<p>Version: 1.3.1 June 12 2001 </p>
+
+<hr size="2" width="100%" align="center">
+
+<p>COPYRIGHT: <br>
+Copyright (c) 2001 International Business Machines Corporation and others. All Rights
+Reserved. </p>
+
+<hr size="2" width="100%" align="center">
+
+<h3><u>Contents</u></h3>
+
+<ul type="disc">
+  <li><a href="#introduction">Introduction</a></li>
+  <li><a href="#license">License Information</a></li>
+  <li><a href="#WhatContain">What the International Components for Unicode for Java Contains</a></li>
+  <li><a href="#API">API overview</a></li>
+  <li><a href="#PlatformDependencies">Platform Dependencies</a></li>
+  <li><a href="#HowToInstallJavac">How to Install and Build</a></li>
+  <li><a href="#WhereToFindMore">Where to Find More Information</a></li>
+  <li><a href="#SubmittingComments">Submitting Comments, Requesting Features and Reporting
+    Bugs</a></li>
+</ul>
+
+<h3><a NAME="introduction"></a><u>Introduction</u></h3>
+
+<p>
+    In today's global market, it is crucial to develop and maintain programs that support a wide variety of national languages. Customers prefer software and web pages in their own languages.  Studies confirm that this leads to increased sales. Java provides a very strong foundation for global
+programs (IBM and the ICU4J team played a key role in providing such technology into Sun's standard Java version).
+    </p>
+    <p>
+    However, Java does not yet provide some features that are required in some products. The ICU4J library is an add-on to the regular JVM that provides the following tools:
+    <ul> 
+    <li> 
+    Unicode Normalization – NFC, NFD, NFKD, NFKC
+    	<blockquote>Produces canonical text representations, needed for XML and the net</blockquote>
+    <li>
+    International Calendars – Arabic, Buddhist, Hebrew, and Japanese
+              <blockquote>Required for correct presentation of dates in some countries.</blockquote>
+    <li> 
+    Number Format Enhancements – Scientific Notation, Spelled-out, etc.
+              <blockquote>Enhances the normal Java number formatting. The spell-out format is used
+for checks and similar documents.</blockquote>
+
+    <li>Enhanced word-break detection – Rule-based, supports Thai
+              <blockquote>Required for correct support of Thai.</blockquote>
+
+    <li>Unicode Text Compression – Standard compression of Unicode text
+              <blockquote>Suitable for large numbers of small fields, where LZW and similar schemes
+do not apply</blockquote>
+    </ul>
+In some cases, the above support has been rolled into a later release of
+Java. For example, the Thai word-break is now in Java 1.4. However, if you
+are using Java 1.2, you can use the ICU4J package until you upgrade to 1.4.
+</p>
+
+<h3><a name=license></a><u>License Information</u></h3>
+<p>
+The ICU projects (ICU4C and ICU4J) have changed their licenses from the IPL (IBM Public License) to the X license. The X license is a non-viral and recommended free software license that is compatible with the GNU GPL license. This is effective starting with release 1.8.1 of ICU4C and release 1.3.1 of ICU4J. All previous ICU releases will continue to utilize the IPL. New ICU releases will adopt the X license. The users of previous releases of ICU will need to accept the terms and conditions of the X license in order to adopt the new ICU releases.
+</p>
+<p>
+The main effect of the change is to provide GPL compatibility.  The X license is listed as GPL compatible, see the gnu page at <a href=http://www.gnu.org/philosophy/license-list.html#GPLCompatibleLicenses>
+http://www.gnu.org/philosophy/license-list.html#GPLCompatibleLicenses
+</a>
+</p>
+<p>
+The text of the X license is available at <a href=http://www.x.org/terms.htm>http://www.x.org/terms.htm</a>. The IBM version contains the essential text of the license, omitting the X-specific trademarks and copyright notices.
+</p>
+<p>
+For more details please see the <a href=http://oss.software.ibm.com/icu/press.html>press announcement</a> and the <a href=http://oss.software.ibm.com/icu/project_faq.html#license>Project FAQ</a>.
+</p>
+
+<h3><a NAME="WhatContain"></a><u>What the International Components for Unicode for Java
+Contains</u></h3>
+
+<p>There are two ways to download the ICU4J releases, 
+
+<ul type="disc">
+  <li><b>Official Release Snapshot:</b><br>
+    If you want to use ICU4J (as opposed to developing it), your best bet is to download an
+    official, packaged ICU4J version of the ICU4J source code.&nbsp; These versions are tested
+    more thoroughly than day-to-day development builds, and they are packaged in zip files for 
+    convenient download.&nbsp; These packaged files can be found at <a href="http://oss.software.ibm.com/icu4j/download/index.html">http://oss.software.ibm.com/icu4j/download/index.html</a>.
+    <br>
+    If packaged snapshot is named <b>ICU4JXXXXXX.zip </b>, XXXXXX is the release version
+    number. <br>
+    Please unzip this file.&nbsp; It will re-construct the source directory. </li>
+</ul>
+
+<ul type="disc">
+  <li><b>CVS Source Repository:</b><br>
+    If you are interested in developing features, patches, or bug fixes for ICU4J, you should
+    probably be working with the latest version of the ICU4J source code. You will need to
+    check the code out of our CVS repository to ensure that you have the most recent version
+    of all of the files. There are several ways to do this: <br>
+    <ul type="circle">
+      <li>WebCVS:<br>
+        If you want to browse the code and only make occasional downloads, you may want to use
+        WebCVS. It provides a convenient, web-based interface for browsing and downloading the
+        latest version of the ICU4J source code and documentation. You can also view each file's
+        revision history, display the differences between individual revisions, determine which
+        revisions were part of which official release, and so on. <br>
+      </li>
+      <li>WinCVS:<br>
+        If you will be doing serious work on ICU4J, you should probably install a CVS client on
+        your own machine so that you can do batch operations without going through the WebCVS
+        interface. On Windows, we suggest the WinCVS client. The following is the example
+        instruction on how to download ICU4J via WinCVS: <ol>
+          <li>Install the WinCVS client, which you can download from the <a
+            href="http://www.wincvs.org">http://www.wincvs.org</a>.</li>
+          <li>Select <strong>Preferences</strong> from the <strong>Admin</strong> menu.<ol type="a">
+              <li>On the <strong>General</strong> tab panel: Set your <strong>CVSROOT</strong> to &quot;<strong>:pserver:anoncvs@oss.software.ibm.com:/usr/cvs/icu4j</strong>&quot;.<br>
+                Leave other options on this page at their default.</li>
+              <li>On the <strong>Ports</strong> tab panel: Check the <strong>pserver</strong> checkbox and
+                enter port <strong>2401</strong>.</li>
+            </ol>
+          </li>
+          <li>Click on the Login menu button (<strong>Admin</strong> menu). Enter in  &quot;<strong>anoncvs</strong>&quot; when requested.</li>
+          <li>To extract the most recent version of ICU4J, select <strong>Checkout module</strong>
+            from the <strong>Create</strong> menu. Specify &quot;<strong>icu4j</strong>&quot; for the
+            module name. This will create a new copy of the workspace on your local hard drive.</li>
+          <li>In the future, you can download updated files from the repository to your hard drive
+            using the <strong>Update selection</strong> item in the <strong>Modify</strong> menu.<br>
+          </li>
+        </ol>
+      </li>
+      <li>CVS command line:<br>
+        You can also check out the repository anonymously on UNIX using the following commands,
+        after first setting your CVSROOT to point to the ICU4J repository: <pre><code>export CVSROOT=:pserver:anoncvs@oss.software.ibm.com:/usr/cvs/icu4j 
+cvs login CVS password: anoncvs 
+cvs checkout icu4j 
+cvs logout</code></pre>
+      </li>
+    </ul>
+  </li>
+</ul>
+
+<p>For more details on how to download ICU4J directly from the web site, please also see <a
+href="http://oss.software.ibm.com/icu4j/download/index.html">http://oss.software.ibm.com/icu4j/download/index.html</a>
+</p>
+
+<p>Below, <b>$Root</b> is the placement of the icu directory in your file system, like
+&quot;drive:\...\icu4j&quot; in your environment. &quot;drive:\...&quot; stands for any
+drive and any directory on that drive that you chose to install icu4j into. </p>
+
+<p><b>The following files describe the code drop:</b></p>
+
+<table BORDER="1" CELLPADDING="0">
+  <tr>
+    <td>readme.html (this file)</td>
+    <td>describes the International Components for Unicode for Java</td>
+  </tr>
+  <tr>
+    <td>license.html</td>
+    <td>contains the X license</td>
+  </tr>
+</table>
+
+<p><b>The source directories mirror package structure of the code.&nbsp; The following
+directories contain source code and data files:</b> </p>
+
+<table BORDER="1" CELLPADDING="0" WIDTH="623">
+  <tr>
+    <td WIDTH="20%">$Root/src/data/</td>
+    <td WIDTH="80%">Various data files used to generate ICU4J classes.&nbsp; Most of the files
+    contain Unicode information that is available from <a href="http://www.unicode.org/">http://www.unicode.org/</a>.&nbsp;
+    Used only by tools in the src/com/ibm/tools.</td>
+  </tr>
+  <tr>
+    <td WIDTH="20%">$Root/src/com/ibm/demo</td>
+    <td WIDTH="80%">Demonstration applications and Applets.</td>
+  </tr>
+  <tr>
+    <td WIDTH="20%">$Root/src/com/ibm/test</td>
+    <td WIDTH="80%">Tests for various ICU4J components.. For information about running the
+    tests, see $Root/src/com/ibm/test/TestAll.java.</td>
+  </tr>
+  <tr>
+    <td WIDTH="20%">$Root/src/com/ibm/tools</td>
+    <td WIDTH="80%">Various tools used to generate ICU4J classes.</td>
+  </tr>
+  <tr>
+    <td WIDTH="20%">$Root/src/com/ibm/text</td>
+    <td WIDTH="80%">The following components:&nbsp; <ul>
+      <li>RuleBasedBreakIterator</li>
+      <li>DictionaryBasedBreakIterator</li>
+      <li>Transliterator</li>
+      <li>Normalizer</li>
+      <li>BigNumberFormat</li>
+      <li>StringSearch</li>
+      <li>Unicode compression</li>
+    </ul>
+    </td>
+  </tr>
+  <tr>
+    <td WIDTH="20%">$Root/src/com/ibm/util</td>
+    <td WIDTH="80%">Calendars and Holidays</td>
+  </tr>
+  <tr>
+    <td WIDTH="20%">$Root/build</td>
+    <td WIDTH="80%">Additional classes needed to build using Ant</td>
+  </tr>
+</table>
+
+<p><b>The following directories are populated when you've built everything:</b> </p>
+
+<table BORDER="1" CELLPADDING="0">
+  <tr>
+    <td>$Root/classes/</td>
+    <td>contains all class files</td>
+  </tr>
+  <tr>
+    <td>$Root/doc</td>
+    <td>contains JavaDoc for all packages</td>
+  </tr>
+</table>
+
+<p><b>Data organization:</b> </p>
+
+<p>Data is stored in various locations in ICU4J:
+
+<ul>
+  <li>Data that is &quot;raw&quot; data goes into <strong>$Root/src/data</strong>. This
+    includes things like the raw Unicode database. <strong>$Root/src/data</strong> does <em>not</em>
+    contain <strong>.java</strong> source files.</li>
+  <li>Data that is in the form of a Java class, typically a ResourceBundle, but not
+    necessarily, goes into one of the packages <code>com.ibm.util.resources</code> or <code>com.ibm.text.resources</code>,
+    depending on whether the associated code lives in <code>com.ibm.util</code> or <code>com.ibm.text</code>.</li>
+  <li>Data that is not part of ICU4J proper (or its base tool set), but rather part of a test,
+    sample, or demo, should go near the source code of its owner. This makes it easy to ship a
+    core ICU4J release without optional components.</li>
+</ul>
+
+<h3><u><a name="API"></a>API Overview</u></h3>
+
+<p>The complete API documentation is available on the ICU4J web site: 
+
+<ul>
+  <li><a href="http://oss.software.ibm.com/icu4j/doc/index.html">Complete index</a></li>
+  <li>International Calendars &#150; <a href="http://oss.software.ibm.com/icu4j/doc/com/ibm/util/IslamicCalendar.html">Islamic</a>,
+    <a href="http://oss.software.ibm.com/icu4j/doc/com/ibm/util/BuddhistCalendar.html">Buddhist</a>, <a
+    href="http://oss.software.ibm.com/icu4j/doc/com/ibm/util/HebrewCalendar.html">Hebrew</a>, <a
+    href="http://oss.software.ibm.com/icu4j/doc/com/ibm/util/JapaneseCalendar.html">Japanese</a></li>
+  <li><a href="http://oss.software.ibm.com/icu4j/doc/com/ibm/text/Normalizer.html">Unicode Normalization</a> &#150;
+    Canonical text representation for W3C</li>
+  <li><a href="http://oss.software.ibm.com/icu4j/doc/com/ibm/text/NumberFormat.html">Number Format Enhancements</a> &#150;
+    Scientific Notation, Spelled-out, ...</li>
+  <li><a href="http://oss.software.ibm.com/icu4j/doc/com/ibm/text/BreakIterator.html">Enhanced word-break detection</a>
+    &#150; Rule-based, supports Thai</li>
+  <li><a href="http://oss.software.ibm.com/icu4j/doc/com/ibm/text/StringSearch.html">Unicode Text Searching</a> &#150;
+    Efficient multi-lingual searching</li>
+  <li>Unicode Text <a href="http://oss.software.ibm.com/icu4j/doc/com/ibm/text/UnicodeCompressor.html">Compression</a> &amp;
+    <a href="http://oss.software.ibm.com/icu4j/doc/com/ibm/text/UnicodeDecompressor.html">Decompression</a> &#150; 2:1
+    compression on English Unicode text</li>
+</ul>
+
+<h3><a NAME="PlatformDependencies"></a><u>Platform Dependencies</u></h3>
+
+<p>Parts of ICU4J depend on functionality that is only available in Java2 (JDk1.2) or
+later, although some components work under 1.1.&nbsp; However, all components should be
+compiled using a Java2 compiler as even components that run using a 1.1.x JVM may require
+language features that are only present in 1.2.&nbsp; Currently 1.1.x is unsupported and
+untested and you use the components on a 1.1.x system at your own risk. </p>
+
+<h3><a NAME="HowToInstallJavac"></a><u>How to Install and Build</u></h3>
+
+<p>To install ICU4J, simply place the prebuilt jar file <strong>icu4j.jar</strong> on your
+Java CLASSPATH.&nbsp; No other files are needed.</p>
+
+<p>The prerequisites for building ICU4J are a working JDK and the Ant build system: 
+
+<ul>
+  <li>First install a recent JDK, at least version 1.2.</li>
+  <li>Next install the <a href="http://jakarta.apache.org/ant/"><strong>Ant</strong></a> build
+    system, part of the Apache Software Foundation's <a href="http://jakarta.apache.org/"><strong>Jakarta</strong></a>
+    project. Ant is a portable, Java-based build system similar to make. ICU4J uses Ant
+    because it introduces no other dependencies, it's portable, and it's easier to manage than
+    a collection of makefiles. We currently build ICU4J using a single makefile on both
+    Windows 9x and Linux using Ant.</li>
+  <li>Installing Ant is straightforward. Download it (see <a
+    href="http://jakarta.apache.org/downloads/binindex.html">http://jakarta.apache.org/downloads/binindex.html</a>),
+    extract it onto your system, set some environment variables, and add its bin directory to
+    your path. For example:<pre>    set JAVA_HOME=C:\jdk1.2.2
+    set ANT_HOME=C:\jakarta-ant
+    set PATH=%PATH%;%ANT_HOME%\bin
+    call antsetup</pre>
+    <p>See the current Ant documentation for details.</p>
+  </li>
+  <li>It's recommended to install both the JDK and Ant somewhere <em>outside</em> the ICU4J
+    directory, to keep them out of CVS's hair. For example, on Linux you might install these
+    in /usr/local.</li>
+</ul>
+
+<p>Once Ant is installed, building is just a matter of typing <strong>ant</strong> in the
+ICU4J root directory. This causes the Ant build system to perform a build as specified by
+the file <strong>build.xml</strong>, located in the ICU4J root directory. You can give Ant
+options like -verbose, and you can specify targets. Ant will only build what's been
+changed and will resolve dependencies properly.</p>
+
+<blockquote>
+  <pre>F:\icu4j&gt;ant tests
+Buildfile: build.xml
+Project base dir set to: F:\icu4j
+Executing Target: core
+Compiling 71 source files to F:\icu4j\classes
+Executing Target: tests
+Compiling 24 source files to F:\icu4j\classes
+Completed in 19 seconds</pre>
+</blockquote>
+
+<p>Current targets that you can give after <strong>ant</strong>:</p>
+<div align="left">
+
+<table border="1" cellpadding="0">
+  <tr>
+    <td>all</td>
+    <td>Build all targets.</td>
+  </tr>
+  <tr>
+    <td>core</td>
+    <td>Build the main class files in the subdirectory <strong>classes</strong>. If no target
+    is specified, core is assumed.</td>
+  </tr>
+  <tr>
+    <td>tests</td>
+    <td>Build the test class files.</td>
+  </tr>
+  <tr>
+    <td>demos</td>
+    <td>Build the demos.</td>
+  </tr>
+  <tr>
+    <td>tools</td>
+    <td>Build the tools.</td>
+  </tr>
+  <tr>
+    <td>docs</td>
+    <td>Run javadoc over the main class files, generating an HTML documentation tree in the
+    subdirectory <strong>doc</strong>.</td>
+  </tr>
+  <tr>
+    <td>jar</td>
+    <td>Create a jar archive <strong>icu4j.jar</strong> in the root ICU4J directory containing
+    the main class files.</td>
+  </tr>
+  <tr>
+    <td>zip</td>
+    <td>Create a zip archive of the source, docs, and jar file for distribution, excluding
+    unwanted things like CVS directories and emacs backup files. The zip file <strong>icu4jYYYYMMDD.zip</strong>
+    will be created in the directory <em>above</em> the root ICU4J directory, where YYYYMMDD
+    is today's date. Any existing file of that name will be overwritten.</td>
+  </tr>
+  <tr>
+    <td>zipsrc</td>
+    <td>Like the <strong>zip</strong> target, without the docs and the jar file. The zip file <strong>icu4jsrcYYYYMMDD.zip</strong>
+    will be created in the directory <em>above</em> the root ICU4J directory.</td>
+  </tr>
+  <tr>
+    <td>clean</td>
+    <td>Remove all built targets, leaving the source.</td>
+  </tr>
+</table>
+</div>
+
+<p>For more information, read the Ant documentation and the <strong>build.xml</strong>
+file.</p>
+
+<p>After doing a build it is a good idea to run all the tests by typing <br>&quot;java
+-classpath $Root/classes -DUnicodeData=$Root/src/data/unicode/UnicodeData.txt com.ibm.test.TestAll&quot;. </p>
+
+<p>(As an alternative to using Ant, you can build simply by running javac and javadoc
+directly. This is not recommended, but a Windows batch file &quot;buildall.bat&quot;
+exists to get you started if you're really allergic to build systems. You may have to
+create destination directories.)</p>
+
+<h3><a name="WhereToFindMore"></a><u>Where to Find More Information</u></h3>
+
+<p><a href="http://oss.software.ibm.com/icu4j">http://oss.software.ibm.com/icu4j</a> is a
+pointer to general information about the International Components for Unicode in Java </p>
+
+<p><a href="http://www.ibm.com/developer/unicode">http://www.ibm.com/developer/unicode</a> is a pointer to
+information on how to make applications global. </p>
+
+<h3><a NAME="SubmittingComments"></a><u>Submitting Comments, Requesting Features and
+Reporting Bugs</u></h3>
+
+<p>Your comments are important to making this release successful.&nbsp; We are committed
+to fixing any bugs, and will also use your feedback to help plan future releases. </p>
+
+<p>To submit comments, request features and report bugs, contact us through the <a href=http://oss.software.ibm.com/icu4j/archives/index.html>ICU4J mailing list</a>.<br>
+While we are not able to respond individually to each comment, we do review all comments. </p>
+
+<hr size="2" width="100%" align="center">
+
+<p>Copyright © 2001 International Business Machines Corporation and others. All Rights
+Reserved. <br>
+10275 N De Anza Blvd., Cupertino, CA 95014 <br>
+All rights reserved. </p>
+
+<hr size="2" width="100%" align="center">
+</body>
+</html>
diff --git a/src/com/ibm/data/misc/english.dict b/src/com/ibm/data/misc/english.dict
new file mode 100755
index 0000000..10f430b
--- /dev/null
+++ b/src/com/ibm/data/misc/english.dict
Binary files differ
diff --git a/src/com/ibm/data/misc/words.txt b/src/com/ibm/data/misc/words.txt
new file mode 100755
index 0000000..a7e06ac
--- /dev/null
+++ b/src/com/ibm/data/misc/words.txt
@@ -0,0 +1,2990 @@
+--
+--such
+a
+a'bel-mizraim
+a'iah
+abate
+abated
+abdicated
+abel
+abi'da
+abide
+abim'a-el
+abim'elech
+abim'elech's
+able
+abolish
+abolishing
+abomination
+about
+above
+abraham
+abraham's
+abram
+abram's
+abroad
+absent
+absolute
+absolved
+abundance
+abundantly
+abuses
+accad
+accept
+accepted
+accommodation
+according
+accordingly
+account
+accustomed
+achbor
+acknowledged
+acquiesce
+acquired
+across
+act
+acts
+adah
+adam
+adbeel
+add
+added
+admah
+administration
+adullamite
+advanced
+adviser
+afar
+affected
+afflicted
+affliction
+afraid
+after
+afterward
+afterwards
+again
+against
+age
+ages
+agile
+agree
+agreed
+ahuz'zath
+ai
+aid
+air
+akan
+al'lon-bacuth
+alighted
+alive
+all
+allegiance
+alliances
+allies
+allow
+allowance
+almighty
+almo'dad
+almond
+almonds
+alone
+along
+aloud
+already
+also
+altar
+alter
+altering
+although
+altogether
+alvah
+alvan
+am
+am'alek
+am'raphel
+amal'ekites
+amazement
+america
+ammonites
+among
+amongst
+amorite
+amorites
+amount
+an
+an'amim
+anah
+and
+aner
+angel
+angels
+anger
+angry
+animal
+animals
+annihilation
+anointed
+another
+another's
+answer
+answered
+any
+anything
+anywhere
+apart
+appealed
+appealing
+appear
+appeared
+appease
+appoint
+appointed
+approached
+approaching
+appropriations
+aprons
+ar'arat
+ar'ioch
+ar'vadites
+aram
+aramean
+aran
+arbitrary
+archers
+ard
+are
+are'li
+area
+arise
+ark
+arkites
+armed
+armies
+arms
+army
+aro'di
+arose
+around
+arpach'shad
+arrayed
+arrive
+art
+as
+as'enath
+ascending
+ash'kenaz
+ash'teroth-karna'im
+ashamed
+ashbel
+asher
+asher's
+ashes
+aside
+ask
+asked
+asks
+asleep
+ass
+ass's
+assemble
+assembled
+assent
+asses
+asshu'rim
+asshur
+assume
+assured
+assyria
+at
+atad
+ate
+attack
+attacked
+attained
+attempts
+attend
+attended
+attention
+authority
+avenged
+avith
+away
+awesome
+awoke
+ba'al-ha'nan
+ba'bel
+back
+backward
+bad
+bade
+bags
+baked
+baker
+balm
+bank
+banks
+barbarous
+barren
+bas'emath
+basket
+baskets
+battle
+bdellium
+be
+be'or
+be-e'ri
+bear
+bearing
+bears
+beast
+beasts
+beautiful
+became
+because
+becher
+become
+becomes
+bed
+bedad
+been
+beer-la'hai-roi
+beer-sheba
+befall
+befallen
+befalls
+before
+beg
+began
+beginning
+beguiled
+begun
+beheld
+behind
+behold
+being
+bela
+believe
+believed
+belly
+belong
+belonging
+belongs
+below
+ben-ammi
+ben-o'ni
+beneath
+benefits
+benjamin
+benjamin's
+bera
+bereaved
+bered
+bereft
+beri'ah
+beside
+besides
+besought
+best
+bethel
+bethlehem
+bethu'el
+better
+between
+beyond
+bilhah
+bilhan
+binding
+bird
+birds
+birsha
+birth
+birthday
+birthright
+bites
+bitter
+bitumen
+black
+blame
+blameless
+bless
+blessed
+blesses
+blessing
+blessings
+blighted
+blindness
+blood
+blossoms
+blot
+blotted
+blow
+bodies
+body
+boiling
+bonds
+bone
+bones
+book
+booths
+border
+bore
+born
+borne
+both
+bough
+bought
+bound
+boundaries
+bounties
+bow
+bowed
+bowing
+bowshot
+boys
+bozrah
+bracelets
+branches
+breach
+bread
+breadth
+break
+breaking
+breasts
+breath
+breathed
+bred
+breed
+breeding
+brethren
+brick
+bricks
+brimstone
+bring
+britain
+british
+broken
+bronze
+brother
+brother's
+brother-in-law
+brothers
+brought
+brow
+bruise
+budded
+build
+building
+built
+bulls
+bundle
+bundles
+buried
+burn
+burned
+burnt
+burst
+bury
+burying
+bushes
+but
+butler
+butlership
+buy
+buz
+by
+cain
+cake
+cakes
+calah
+calf
+call
+called
+calls
+came
+camel
+camel's
+camels
+camp
+camped
+can
+canaan
+canaan'
+canaanite
+canaanites
+canaanitish
+candid
+cannot
+caph'torim
+captain
+captive
+captives
+captured
+caravan
+carcasses
+care
+carefully
+carmi
+carried
+carry
+cases
+caslu'him
+cast
+cattle
+caught
+cause
+caused
+causes
+cave
+cease
+ceased
+certain
+chain
+chalde'ans
+chamber
+change
+changed
+character
+charge
+charged
+charging
+chariot
+chariots
+charters
+cheat
+cheated
+ched-or-lao'mer
+cheran
+cherubim
+chesed
+chezib
+chief
+chiefs
+child
+childbearing
+childless
+children
+children's
+choice
+choicest
+chose
+chosen
+circumcised
+circumstances
+cities
+citizens
+city
+civil
+civilized
+clans
+clean
+clear
+cleaves
+close
+closed
+clothed
+clothes
+clothing
+cloud
+clouds
+clusters
+coastland
+coasts
+coffin
+cold
+colonies
+colonies:
+colt
+colts
+combined
+come
+comely
+comes
+comfort
+comforted
+comforts
+coming
+command
+commanded
+commander
+commandments
+commerce
+commit
+committed
+common
+companies
+company
+complained
+complete
+completed
+compliance
+conceal
+conceived
+concern
+concerning
+conclude
+concubine
+concubines
+condition
+conditions
+confined
+confuse
+confused
+congress
+conjured
+connected
+connection
+connections
+consent
+consent:
+conspired
+constitution
+constrained
+constrains
+consume
+consumed
+contempt
+contended
+continually
+continue
+continued
+contract
+control
+controlling
+convulsions
+cool
+cord
+correspondence
+corrupt
+corrupted
+costly
+couch
+couched
+couches
+couching
+could
+council
+count
+counted
+countenance
+country
+course
+covenant
+cover
+covered
+covering
+cows
+created
+creation
+creator
+creature
+creatures
+creeping
+creeps
+cried
+crossed
+crossing
+crouching
+crown
+cruel
+cruelty
+cry
+crying
+cubit
+cubits
+cup
+curds
+current
+curse
+cursed
+curses
+cush
+custody
+cut
+cutting
+dainties
+damascus
+dan
+dangers
+dares
+dark
+darkness
+daughter
+daughter-in-law
+daughters
+dawned
+day
+days
+dead
+deal
+dealt
+death
+deb'orah
+deceitfully
+deceived
+decent
+decide
+decks
+declaration
+declare
+declaring
+dedan
+deed
+deep
+defeat
+defeated
+defiled
+define
+delay
+delayed
+delight
+deliver
+delivered
+delivery
+denied
+denounces
+depart
+departed
+departing
+dependent
+dependents
+depository
+depriving
+deriving
+descendants
+descending
+design
+desire
+desired
+desolate
+desolation
+despised
+despotism
+destroy
+destroyed
+destroys
+destruction
+destructive
+determined
+devoured
+devouring
+dew
+dictate
+did
+didst
+die
+died
+dies
+diklah
+dim
+din'habah
+dinah
+dinah's
+dine
+dipped
+direct
+direction
+disaster
+disavow
+discreet
+disgrace
+dishan
+dishon
+dismayed
+displeased
+displeasing
+disposed
+dissolutions
+dissolve
+dissolved
+distance
+distant
+distress
+distressed
+districts
+divide
+divided
+dividing
+divination
+divine
+divines
+do
+do'danim
+doer
+does
+doing
+domestic
+dominion
+done
+door
+dothan
+double
+doubling
+doubt
+dove
+down
+downcast
+dowry
+drank
+draw
+drawn
+dread
+dream
+dreamed
+dreamer
+dreams
+drew
+dried
+drink
+drinking
+drinks
+driven
+drove
+droves
+drunk
+dry
+dug
+dumah
+dungeon
+during
+dust
+duty
+dwell
+dwelling
+dwelt
+e'domites
+e'phraim
+e'phraim's
+each
+early
+ears
+earth
+easily
+east
+eastward
+eat
+eaten
+eating
+ebal
+eber
+eden
+eder
+edom
+effect
+egypt
+egyptian
+egyptian's
+egyptians
+ehi
+eight
+eighteen
+eighty
+eighty-seven
+eighty-six
+eighty-two
+either
+el'iphaz
+el-bethel
+el-el'ohe-israel
+el-paran
+elah
+elam
+elda'ah
+elder
+elders
+eldest
+elected
+eleven
+eli'shah
+elie'zer
+ella'sar
+elon
+else
+embalm
+embalmed
+embalming
+embrace
+embraced
+emigration
+emim
+emptied
+empty
+empty-handed
+enaim
+encamped
+encampments
+encourage
+end
+endeavored
+ended
+ending
+endowed
+ends
+enemies
+enemy
+english
+enlarge
+enlarging
+enmish'pat
+enmity
+enoch
+enosh
+enough
+enter
+entered
+entitle
+entrance
+entreat
+envied
+ephah
+epher
+ephrath
+ephron
+equal
+er
+erech
+erected
+eri
+errand
+esau
+esau's
+escape
+escaped
+esek
+eshban
+eshcol
+establish
+established
+establishing
+establishment
+eternal
+euphra'tes
+euphrates
+eve
+even
+evening
+events
+ever
+everlasting
+every
+everything
+everywhere
+evil
+evils
+evinces
+ewe
+ewes
+example
+exceedingly
+except
+exchange
+excited
+executioners
+exercise
+experience
+expert
+explain
+exposed
+exposing
+extend
+extended
+eyes
+ezbon
+ezer
+face
+faces
+facts
+failed
+fainted
+fair
+faithfulness
+fall
+fallen
+falls
+falsely
+families
+family
+famine
+famished
+far
+fare
+fared
+farewell
+fast
+fat
+father
+father's
+father-in-law
+fathers
+fatiguing
+fatness
+faults
+favor
+favorable
+fawns
+fear
+feared
+feast
+fed
+feebler
+feed
+feel
+feet
+fell
+fellow
+felt
+female
+festal
+fetch
+few
+field
+fields
+fierce
+fiercely
+fifteen
+fifth
+fifths
+fifty
+fig
+fill
+filled
+find
+finds
+fine
+finish
+finished
+fire
+firm
+firmament
+firmness
+first
+first-
+first-born
+firstlings
+fish
+fit
+five
+fixed
+flaming
+fled
+flee
+fleeing
+flesh
+floated
+flock
+flocks
+flood
+floor
+flowed
+flows
+fly
+foal
+follow
+followed
+following
+follows
+folly
+fondling
+food
+foolishly
+foot
+for
+forbidden
+force
+forced
+forces
+ford
+foreign
+foreigner
+foreigners
+foremost
+foreskin
+foreskins
+forger
+forget
+forgets
+forgive
+forgot
+forgotten
+form
+formed
+former
+formerly
+formidable
+forms
+forsaken
+forth
+fortune
+fortunes
+forty
+forty-five
+forty-seven
+found
+foundation
+fountains
+four
+fourteen
+fourteenth
+fourth
+frail
+free
+freely
+fresh
+freshly
+friend
+friendly
+friends
+fro
+from
+front
+frontiers
+fruit
+fruitful
+fruits
+fugitive
+fulfil
+fulfilled
+full
+fundamentally
+furnace
+fury
+future
+gad
+gaham
+gained
+galeed
+game
+garden
+garment
+garments
+gatam
+gate
+gather
+gathered
+gaunt
+gave
+gavest
+gaza
+gazed
+genealogies
+general
+generation
+generations
+gera
+gerar
+gershon
+get
+gether
+gift
+gifts
+gihon
+gilead
+gir'gashites
+give
+given
+givest
+giving
+go
+goat
+goats
+god
+god's
+gods
+goes
+goi'im
+going
+gold
+gomer
+gomor'rah
+gone
+good
+good-looking
+goods
+gopher
+goshen
+got
+gotten
+governed
+government
+governments
+governments:
+governor
+governors
+gracious
+graciously
+grain
+grandchildren
+grandson
+grant
+granted
+grapes
+grass
+grave
+gray
+great
+greater
+greatly
+green
+grew
+grieved
+grievous
+groping
+ground
+grow
+growing
+grown
+grows
+guard
+guards
+guile
+guilt
+guilty
+gum
+guni
+ha'mathites
+had
+hadad
+hadar
+hador'am
+hagar
+haggi
+hairs
+hairy
+half
+hallowed
+ham
+hamor
+hamor's
+hamstring
+hamul
+hand
+hands
+handsome
+hang
+hanged
+hanoch
+happened
+happiness
+happy
+haran
+harass
+harassed
+hard
+hardship
+harlot
+harlotry
+harm
+harshly
+harvest
+harvests
+has
+hast
+haste
+hastened
+hastily
+hate
+hated
+hath
+hav'ilah
+have
+haven
+havilah
+having
+haz'azon-ta'mar
+hazarma'veth
+hazo
+he
+he-asses
+he-goats
+head
+heads
+healed
+heap
+hear
+heard
+hearing
+hearken
+hearkened
+hears
+heart
+hearts
+heat
+heaven
+heavens
+heber
+hebrew
+hebrews
+hebron
+heed
+heeded
+heel
+heels
+heifer
+height
+heir
+held
+help
+helper
+heman
+hemdan
+her
+herb
+herd
+herds
+herdsmen
+here
+herself
+heth
+hewed
+hezron
+hid
+hidden
+hide
+high
+hill
+hills
+him
+himself
+hind
+hinder
+hip
+hirah
+hire
+hired
+his
+history
+hither
+hittite
+hittites
+hivite
+hivites
+hobah
+hold
+hollow
+home
+honest
+honesty
+honey
+honor
+honored
+hori
+horite
+horites
+horns
+horse's
+horsemen
+horses
+host
+hot
+hotly
+house
+household
+households
+houses
+how
+hul
+human
+humane
+humble
+humbled
+hundred
+hundredfold
+hundredth
+hunt
+hunted
+hunter
+hunting
+huppim
+husband
+husham
+hushim
+i
+if
+ill
+ill-treat
+image
+imagination
+immediate
+imnah
+impel
+importance
+imposing
+impossible
+in
+inasmuch
+incapable
+including
+increased
+indeed
+independent
+indian
+indignant
+inestimable
+inevitably
+inhabitants
+inheritance
+iniquity
+injuries
+injury
+innocence
+innocent
+inquire
+inquired
+inside
+instead
+institute
+instituted
+instructed
+instructing
+instrument
+instruments
+insult
+insurrections
+integrity
+intended
+intentions
+interpret
+interpretation
+interpretations
+interpreted
+interpreter
+interrupt
+into
+introducing
+invariably
+invasion
+invasions
+invested
+iob
+irad
+iram
+iron
+is
+is'sachar
+isaac
+isaac's
+iscah
+ish'mael
+ish'mael's
+ish'maelites
+ishbak
+ishvah
+ishvi
+israel
+israel's
+israelites
+it
+ithran
+its
+itself
+jabal
+jabbok
+jachin
+jacob
+jacob's
+jah'leel
+jahzeel
+jalam
+jamin
+japheth
+jar
+jared
+javan
+je'gar-sahadu'tha
+je'ush
+jealous
+jeb'usites
+jemu'el
+jerah
+jesting
+jetheth
+jetur
+jewelry
+jezer
+jidlaph
+jobab
+joined
+joint
+jokshan
+joktan
+jordan
+joseph
+joseph's
+journey
+journeyed
+jubal
+judah
+judah's
+judge
+judged
+judges
+judgment
+judiciary
+judith
+jurisdiction
+jury:
+just
+justice
+kad'monites
+kadesh
+ked'emah
+kedar
+keep
+keeper
+keepers
+kemu'el
+ken'ites
+ken'izzites
+kenan
+kenaz
+kept
+ketu'rah
+kid
+kids
+kill
+killed
+kind
+kindled
+kindness
+kindred
+kinds
+king
+king's
+kingdom
+kings
+kinsman
+kinsmen
+kir'iath-ar'ba
+kiss
+kissed
+kittim
+knead
+knee
+kneel
+knees
+knew
+knife
+know
+knowing
+knowledge
+known
+knows
+kohath
+korah
+laban
+laban's
+labor
+lack
+lacking
+lad
+lad's
+ladder
+lads
+laid
+lain
+lamb
+lambs
+lamech
+lamentation
+lamented
+land
+lands
+language
+languages
+languished
+large
+lasha
+last
+later
+laugh
+laughed
+laughter
+laws
+lay
+laying
+le-um'mim
+lead
+leaf
+leah
+leah's
+lean
+leap
+leaped
+learn
+learned
+least
+leave
+leaves
+led
+left
+legislate
+legislation:
+legislative
+legislature
+legislatures
+leha'bim
+length
+lentils
+lesser
+lest
+let
+letu'shim
+levey
+levi
+liberty
+lie
+lies
+life
+lifeblood
+lift
+lifted
+light
+lights
+like
+likely
+likeness
+likewise
+limping
+linen
+lingered
+lion
+lion's
+lioness
+listen
+listened
+listening
+little
+live
+lived
+lives
+livestock
+living
+lo
+load
+loaded
+lodge
+lodged
+lodging
+loins
+long
+longed
+longer
+longs
+look
+looked
+looking
+loose
+lord
+lord's
+lords
+loss
+lot
+lot's
+lotan
+lotan's
+loud
+love
+loved
+lovely
+loves
+lower
+lowered
+loyally
+lud
+ludim
+luz
+lying
+lyre
+ma'acah
+ma'halath
+ma-hal'alel
+mach-
+mach-pe'lah
+machir
+madai
+made
+mag'diel
+magicians
+magnanimity
+magog
+mahana'im
+maid
+maiden
+maids
+maidservants
+make
+maker
+making
+mal'chi-el
+male
+males
+mamre
+man
+man'ahath
+man's
+manas'seh
+manas'seh's
+mandrakes
+mankind
+manly
+manner
+mantle
+many
+mark
+marked
+marriage
+marriages
+married
+marries
+marry
+mash
+masre'kah
+massa
+master
+master's
+mate
+mating
+matred
+matter
+may
+me
+me'zahab
+me-hu'ja-el
+me-thu'sha-el
+meal
+mean
+meaning
+means
+meant
+meantime
+meanwhile
+measure
+measured
+measures
+medan
+meditate
+meet
+meets
+mehet'abel
+mel-chiz'edek
+members
+men
+men's
+mend
+mended
+menservants
+mention
+merar'i
+mercenaries
+merchants
+merciful
+merciless
+mercy
+merry
+mesha
+meshech
+mesopota'mia
+message
+messengers
+met
+methu'selah
+mibsam
+mibzar
+mid'ian
+mid'ianite
+mid'ianites
+midst
+midwife
+might
+mightier
+mightily
+mighty
+migrated
+migration
+milcah
+milch
+military
+milk
+mind
+mine
+mirth
+miscarried
+mishma
+mist
+mistress
+mizpah
+mizzah
+moab
+moabites
+mock
+mocking
+money
+monsters
+month
+months
+moon
+more
+moreh
+moreover
+mori'ah
+morning
+morsel
+mortar
+most
+mother
+mother's
+mothers
+mottled
+mount
+mountain
+mountains
+mourn
+mourned
+mourning
+mouth
+moved
+moves
+moving
+much
+multiplied
+multiply
+multitude
+muppim
+murders
+must
+mutually
+my
+myrrh
+myself
+na'amah
+na'aman
+nahath
+nahor
+nahor's
+naked
+nakedness
+name
+named
+names
+naph'tali
+naph-tu'him
+naphish
+nation
+nations
+native
+naturalization
+nature
+nature's
+near
+neba'ioth
+necessary
+necessity
+neck
+need
+negeb
+neglected
+neighboring
+neither
+nephilim
+never
+nevertheless
+new
+next
+night
+nights
+nile
+nimrod
+nin'eveh
+nine
+nineteen
+ninety
+ninety-five
+ninety-nine
+no
+noah
+noah's
+nod
+none
+noon
+nor
+north
+northward
+nose
+nostrils
+not
+nothing
+now
+number
+numbered
+numbers
+nurse
+nuts
+o
+oak
+oaks
+oath
+obal
+obedience
+obeisance
+obey
+obeyed
+object
+obstructed
+obstructing
+obtain
+obtained
+occasion
+occupation
+odious
+odor
+of
+off
+offended
+offense
+offenses:
+offer
+offered
+offering
+offerings
+office
+officer
+officers
+offices
+offspring
+oh
+ohad
+oholiba'mah
+oil
+old
+older
+oldest
+olive
+omar
+on
+onam
+onan
+once
+one
+ones
+only
+onyx
+open
+opened
+operation
+ophir
+opinions
+opposing
+opposite
+oppressed
+oppressions
+or
+order
+orders
+organizing
+ornaments
+other
+others
+ought
+our
+ours
+ourselves
+out
+outcry
+outside
+outwitted
+over
+overdriven
+overseer
+overseers
+oversight
+overtake
+overthrew
+overthrow
+overtook
+own
+owns
+oxen
+pace
+paddan
+paddan-aram
+paid
+pain
+pair
+pairs
+pallu
+paralleled
+paran
+part
+parts
+pass
+passed
+past
+pasture
+pastured
+pasturing
+path
+pathru'sim
+patient
+pau
+pay
+payment
+pe'lah
+peace
+peaceably
+peeled
+peleg
+peni'el
+penu'el
+people
+peopled
+peoples
+per'izzites
+perez
+perfidy
+perform
+perhaps
+perish
+permit
+perpetuated
+persons
+petitioned
+petitions
+pharaoh
+pharaoh's
+phicol
+philistines
+physicians
+piece
+pieces
+pigeon
+pildash
+pillar
+pinon
+pipe
+pishon
+pistachio
+pit
+pitch
+pitched
+pits
+place
+placed
+places
+plagues
+plain
+plainly
+plane
+planning
+plant
+planted
+plants
+play
+played
+playing
+pleasant
+please
+pleased
+pleases
+pleasing
+pleasure
+pledge
+plenteous
+plenty
+plowing
+plucked
+plump
+plundered
+point
+political
+poor
+poplar
+population
+portion
+portions
+possess
+possession
+possessions
+posterity
+pot
+pot'i-phar
+poti'phera
+pottage
+poured
+poverty
+power
+powers
+praise
+praised
+pray
+prayed
+prayer
+pre-eminence
+pre-eminent
+prepare
+prepared
+presence
+present
+presented
+preserve
+preserved
+pressed
+pressing
+pretended
+prevail
+prevailed
+prevent
+prevented
+prey
+price
+pride
+priest
+priests
+prince
+princes
+principles
+prison
+prisoners
+proceed
+produce
+profit
+promise
+promised
+pronounce
+property
+prophet
+proposal
+propose
+prosper
+prospered
+protecting
+protection
+prove
+provender
+provide
+provided
+providence
+province
+provision
+provisions
+prudence
+public
+publish
+punishment
+purchased
+purify
+purpose
+pursue
+pursued
+pursuing
+pursuit
+put
+putting
+puvah
+quarrel
+quarreled
+quartering
+questioned
+questions
+quickly
+quiet
+quiver
+ra'amah
+rachel
+rachel's
+raid
+raiders
+raiment
+rain
+rained
+raise
+raised
+raising
+ram
+ram'eses
+rams
+ran
+rather
+ravaged
+raven
+ravenous
+re'u
+reached
+ready
+really
+reaped
+reason
+reassured
+rebekah
+rebekah's
+rebelled
+rebuked
+receded
+receive
+received
+reckoned
+reckoning
+recognize
+recognized
+records
+rectitude
+red
+redeemed
+redress
+reduce
+reed
+refresh
+refused
+refusing
+regard
+regarded
+regards
+reho'both
+reho'both-ir
+reign
+reigned
+reliance
+relief
+relinquish
+remain
+remained
+remaining
+remains
+remember
+remembered
+reminded
+remnant
+remove
+removed
+removing
+render
+renown
+rent
+repeated
+repeatedly
+reph'aim
+replace
+replaced
+replied
+report
+representation
+representative
+representatives
+reproach
+require
+required
+requires
+rescue
+resen
+reserve
+reserved
+respect
+rest
+rested
+resting
+restore
+restored
+restrained
+return
+returned
+reu'el
+reuben
+reumah
+revealed
+revived
+reward
+rib
+ribs
+rich
+ride
+rider
+right
+righted
+righteous
+righteousness
+rightly
+rights
+ring
+rings
+ripened
+riphath
+rise
+risen
+river
+rivers
+road
+robe
+rock
+rode
+rods
+roll
+rolled
+roof
+room
+rooms
+rose
+rosh
+roughly
+round
+rouse
+routed
+royal
+rule
+ruler
+ruler's
+run
+runnels
+sab'teca
+sabtah
+sack
+sackcloth
+sacks
+sacred
+sacrifice
+sacrifices
+saddle
+saddled
+safely
+safety
+said
+sake
+salaries
+salem
+salt
+salvation
+same
+samlah
+sand
+sandal-thong
+sar'ai
+sarah
+sarah's
+sat
+savages
+saved
+saving
+savory
+saw
+say
+saying
+says
+scarcely
+scarlet
+scatter
+scattered
+scepter
+se'ir
+sea
+searched
+seas
+seashore
+season
+seasons
+seba
+second
+secretly
+secure
+security
+see
+seed
+seedtime
+seeing
+seek
+seeking
+seem
+seemed
+seen
+sees
+seize
+seized
+select
+self-evident
+sell
+semen
+send
+sent
+separate
+separated
+separation
+sephar
+sepulchre
+sepulchres
+serah
+sered
+serpent
+serug
+servant
+servant's
+servants
+serve
+served
+service
+serving
+set
+seth
+settle
+settled
+settlement
+seven
+sevenfold
+seventeen
+seventeenth
+seventh
+seventy
+seventy-five
+seventy-seven
+seventy-sevenfold
+severe
+sewed
+sexes
+sha'veh-kiriatha'im
+shall
+shammah
+share
+shaul
+shaved
+shaveh
+she
+she-asses
+she-goat
+she-goats
+sheaf
+shear
+sheaves
+sheba
+shechem
+shechem's
+shed
+sheds
+sheep
+sheepfolds
+sheepshearers
+shekel
+shekels
+shelah
+sheleph
+shelter
+shem
+sheme'ber
+sheol
+shepherd
+shepherding
+shepherds
+shepho
+shibah
+shield
+shillem
+shimron
+shinab
+shinar
+ships
+shobal
+shore
+short
+shortly
+shot
+should
+shoulder
+shoulders
+show
+showed
+shown
+shua
+shua's
+shuah
+shuni
+shur
+shut
+siddim
+side
+sidon
+sight
+sign
+signet
+signs
+silence
+silver
+simeon
+sin
+since
+sinew
+sinites
+sinned
+sinners
+sinning
+sister
+sister's
+sit
+sitnah
+sitting
+six
+sixteen
+sixth
+sixty
+sixty-five
+sixty-nine
+sixty-six
+sixty-two
+skilful
+skin
+skins
+slain
+slaughter
+slave
+slaves
+slay
+slays
+sleek
+sleep
+sleeves
+slept
+slew
+slope
+slowly
+small
+smell
+smelled
+smoke
+smoking
+smooth
+so
+sodom
+soil
+sojourn
+sojourned
+sojourner
+sojourners
+sojourning
+sojournings
+sold
+sole
+solemnly
+some
+son
+son's
+songs
+sons
+sons'
+sons-in-law
+soon
+sore
+sorely
+sorrow
+sorrowful
+sorry
+sort
+sorts
+sought
+soul
+sound
+south
+southward
+sow
+sowed
+space
+spare
+spared
+speak
+speaking
+speaks
+speckled
+speech
+spend
+spent
+spies
+spilled
+spirit
+splendor
+spoil
+spoke
+spoken
+spotted
+spread
+spring
+springing
+springs
+sprouted
+sprung
+staff
+stage
+stalk
+stand
+standing
+stands
+stars
+state
+states
+states:
+station
+statute
+statutes
+stay
+stayed
+stead
+steadfast
+steal
+steward
+still
+stole
+stolen
+stone
+stones
+stood
+stooped
+stop
+stopped
+store
+stored
+storehouses
+story
+stranger
+strangers
+straw
+streaks
+stream
+street
+strength
+stretched
+strife
+striking
+striped
+stripped
+striven
+strong
+stronger
+strongly
+struck
+struggled
+subdue
+subdued
+subject
+submit
+submitted
+subsided
+substance
+subtle
+success
+successful
+succoth
+such
+suck
+suckle
+suffer
+sufferable
+sufferance
+suitable
+summer
+summoned
+sun
+superior
+supplanted
+supplied
+support
+suppose
+supreme
+surely
+surety
+surrounded
+survivors
+suspended
+suspending
+sustained
+swallowed
+swarm
+swarming
+swarms
+swear
+sweat
+sword
+swords
+swore
+sworn
+system
+systems
+table
+tahash
+take
+taken
+taking
+talked
+talking
+tamar
+tamarisk
+tambourine
+tarried
+tarry
+tarshish
+taxes
+te'manites
+tebah
+teeth
+tell
+tells
+tema
+teman
+ten
+tender
+tenderly
+tent
+tenth
+tents
+tenure
+terah
+terms:
+territory
+terror
+tested
+than
+that
+the
+thee
+their
+theirs
+them
+themselves
+then
+thence
+there
+therefore
+therein
+these
+they
+thicket
+thigh
+thin
+thing
+things
+thinking
+third
+thirteen
+thirteenth
+thirty
+thirty-five
+thirty-four
+thirty-seven
+thirty-three
+thirty-two
+this
+thistles
+thorns
+thoroughly
+those
+thou
+thought
+thoughts
+thousand
+thousands
+thread
+three
+threshing
+throne
+through
+throughout
+throw
+thus
+thy
+tidal
+tidings
+ties
+tigris
+till
+tiller
+time
+times
+timna
+timnah
+tiras
+to
+today
+togar'mah
+together
+toil
+tola
+told
+tomb
+tonight
+too
+took
+top
+tops
+torch
+torn
+totally
+totaly
+touch
+touched
+touches
+toward
+tower
+towns
+trade
+traders
+train
+trained
+transgression
+transient
+transporting
+travailed
+treasure
+treat
+treated
+tree
+trees
+trembled
+trembling
+trial
+tribes
+tried
+troops
+trouble
+troubled
+troubles
+trough
+troughs
+truly
+truth
+truths
+tubal
+tubal-
+tubal-cain
+turn
+turned
+turns
+turtledove
+twelve
+twenty
+twenty-nine
+twenty-seven
+twenty-seventh
+twice
+twins
+two
+tyranny
+tyrant
+tyrants
+unacknowledged
+unalienable
+unawares
+uncircumcised
+uncomfortable
+uncovered
+under
+understand
+understood
+undistinguished
+unfit
+ungirded
+united
+unknown
+unleavened
+unless
+unmoved
+unstable
+until
+unusual
+unwarrantable
+unworth
+up
+upbraided
+upon
+uppermost
+upright
+ur
+urged
+us
+us:
+use
+using
+usurpations
+utterly
+uz
+uzal
+valley
+valuable
+vegetation
+veil
+vengeance
+vent
+vents
+verified
+very
+vesture
+villages
+vindication
+vine
+vineyard
+violence
+violently
+viper
+virgin
+vision
+visions
+visit
+visited
+voice
+void
+vow
+wages
+waging
+wagons
+wait
+waited
+walk
+walked
+walking
+wall
+wander
+wandered
+wanderer
+wandering
+wanting
+wantonness
+war
+warfare
+warned
+was
+wash
+washed
+washes
+watch
+water
+watered
+watering
+waters
+way
+wayside
+we
+weak
+weakness
+wealth
+wealthy
+weaned
+weapons
+wear
+wearied
+weary
+week
+weep
+weeping
+weighed
+weighing
+weight
+weights
+welfare
+well
+well's
+wells
+went
+wept
+were
+west
+westward
+what
+whatever
+whatsoever
+wheat
+whelp
+when
+whence
+whenever
+where
+whereby
+wherever
+whether
+which
+while
+white
+who
+whoever
+whole
+wholesome
+whom
+whomever
+whose
+why
+wicked
+wickedly
+wickedness
+widow
+widow's
+widowhood
+wife
+wife's
+wild
+wilderness
+will
+willing
+wilt
+wind
+window
+windows
+wine
+winged
+winter
+wise
+with
+withered
+withheld
+withhold
+within
+without
+witness
+wives
+wolf
+woman
+woman's
+womb
+wombs
+women
+wood
+word
+words
+wore
+work
+works
+world
+world:
+worse
+worship
+worshiped
+worth
+worthy
+would
+wounding
+wrapping
+wrath
+wrestled
+wrestlings
+wrong
+wrought
+year
+yearned
+years
+yes
+yet
+yield
+yielding
+yoke
+yonder
+you
+young
+younger
+youngest
+your
+yours
+yourself
+yourselves
+youth
+za'avan
+zaph'enath-pane'ah
+zeb'ulun
+zeboi'im
+zem'arites
+zepho
+zerah
+zib'eon
+zillah
+zilpah
+zimran
+ziph'ion
+zo'ar
+zohar
+zuzim
diff --git a/src/com/ibm/demo/DemoApplet.java b/src/com/ibm/demo/DemoApplet.java
new file mode 100755
index 0000000..cc9cd52
--- /dev/null
+++ b/src/com/ibm/demo/DemoApplet.java
@@ -0,0 +1,80 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/Attic/DemoApplet.java,v $ 
+ * $Date: 2001/10/30 02:42:50 $ 
+ * $Revision: 1.4 $
+ *
+ *****************************************************************************************
+ */
+
+package com.ibm.demo;
+
+import java.applet.Applet;
+import java.util.Locale;
+import java.awt.*;
+import java.awt.event.*;
+
+public abstract class DemoApplet extends java.applet.Applet {
+    private Button   demoButton;
+    private Frame    demoFrame;
+	private static int demoFrameCount = 0;
+
+    protected abstract Frame createDemoFrame(DemoApplet applet);
+    protected Dimension getDefaultFrameSize(DemoApplet applet, Frame f) {
+    	return new Dimension(700, 550);
+    }
+
+    //Create a button that will display the demo
+    public void init()
+    {
+        setBackground(Color.white);
+        demoButton = new Button("Demo");
+        demoButton.setBackground(Color.yellow);
+        add( demoButton );
+
+        demoButton.addActionListener( new ActionListener() {
+             public void actionPerformed(ActionEvent e) {
+                if (e.getID() == ActionEvent.ACTION_PERFORMED) {
+                    demoButton.setLabel("loading");
+
+                    if (demoFrame == null) {
+                       demoFrame = createDemoFrame(DemoApplet.this);
+                       showDemo();
+                    }
+
+                    demoButton.setLabel("Demo");
+                }
+             }
+        } );
+    }
+
+    public void showDemo()
+    {
+    	demoFrame = createDemoFrame(this);
+        demoFrame.doLayout();
+        Dimension d = getDefaultFrameSize(this, demoFrame);
+        demoFrame.setSize(d.width, d.height);
+        demoFrame.show();
+		demoFrameOpened();
+    }
+
+    public void demoClosed()
+    {
+        demoFrame = null;
+		demoFrameClosed();
+    }
+
+	protected static void demoFrameOpened() {
+		demoFrameCount++;
+    }
+	protected static void demoFrameClosed() {
+		if (--demoFrameCount == 0) {
+			System.exit(0);
+		}
+    }
+}
+
diff --git a/src/com/ibm/demo/DemoTextBox.java b/src/com/ibm/demo/DemoTextBox.java
new file mode 100755
index 0000000..3d11497
--- /dev/null
+++ b/src/com/ibm/demo/DemoTextBox.java
@@ -0,0 +1,101 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/Attic/DemoTextBox.java,v $ 
+ * $Date: 2000/03/10 03:47:42 $ 
+ * $Revision: 1.2 $
+ *
+ *****************************************************************************************
+ */
+package com.ibm.demo;
+
+
+import java.text.BreakIterator;
+import java.awt.*;
+
+public class DemoTextBox {
+
+    public DemoTextBox(Graphics g, String text, int width)
+    {
+        this.text = text;
+        this.chars = new char[text.length()];
+        text.getChars(0, text.length(), chars, 0);
+
+        this.width = width;
+        this.port = g;
+        this.metrics = g.getFontMetrics();
+
+        breakText();
+    }
+
+    public  int getHeight() {
+        return (nbreaks + 1) * metrics.getHeight();
+    }
+
+    public  void draw(Graphics g, int x, int y)
+    {
+        int index = 0;
+
+        y += metrics.getAscent();
+
+        for (int i = 0; i < nbreaks; i++)
+        {
+            g.drawChars(chars, index, breakPos[i] - index, x, y);
+            index = breakPos[i];
+            y += metrics.getHeight();
+        }
+
+        g.drawChars(chars, index, chars.length - index, x, y);
+    }
+
+
+    private void breakText()
+    {
+        if (metrics.charsWidth(chars, 0, chars.length) > width)
+        {
+            BreakIterator iter = BreakIterator.getWordInstance();
+            iter.setText(text);
+
+            int start = iter.first();
+            int end = start;
+            int pos;
+
+            while ( (pos = iter.next()) != BreakIterator.DONE )
+            {
+                int w = metrics.charsWidth(chars, start, pos - start);
+                if (w > width)
+                {
+                    // We've gone past the maximum width, so break the line
+                    if (end > start) {
+                        // There was at least one break position before this point
+                        breakPos[nbreaks++] = end;
+                        start = end;
+                        end = pos;
+                    } else {
+                        // There weren't any break positions before this one, so
+                        // let this word overflow the margin (yuck)
+                        breakPos[nbreaks++] = pos;
+                        start = end = pos;
+                    }
+                } else {
+                    // the current position still fits on the line; it's the best
+                    // tentative break position we have so far.
+                    end = pos;
+                }
+
+            }
+        }
+    }
+
+    private String          text;
+    private char[]          chars;
+    private Graphics        port;
+    private FontMetrics     metrics;
+    private int             width;
+
+    private int[]           breakPos = new int[10]; // TODO: get real
+    private int             nbreaks = 0;
+}
\ No newline at end of file
diff --git a/src/com/ibm/demo/DemoUtility.java b/src/com/ibm/demo/DemoUtility.java
new file mode 100755
index 0000000..8a2c9e3
--- /dev/null
+++ b/src/com/ibm/demo/DemoUtility.java
@@ -0,0 +1,136 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/Attic/DemoUtility.java,v $ 
+ * $Date: 2001/10/30 02:42:50 $ 
+ * $Revision: 1.5 $
+ *
+ *****************************************************************************************
+ */
+package com.ibm.demo;
+
+import java.awt.*;
+import java.lang.*;
+import java.util.*;
+
+public class DemoUtility
+{
+    public static final Font titleFont = new Font("TimesRoman",Font.BOLD,18);
+    public static final Font labelFont = new Font("TimesRoman",Font.BOLD,14);
+    public static final Font choiceFont = new Font("Helvetica",Font.BOLD,12);
+    public static final Font editFont = new Font("Helvetica",Font.PLAIN,14);
+    public static final Font creditFont = new Font("Helvetica",Font.PLAIN,10);
+    public static final Font numberFont = new Font("sansserif", Font.PLAIN, 14);
+
+    public static final Color bgColor = Color.lightGray;
+    public static final Color choiceColor = Color.white;
+
+    public static final String copyright1 =
+        "(C) Copyright Taligent, Inc. 1996-1998.  Copyright (C) IBM, Inc. 1998 - All Rights Reserved";
+    public static final String copyright2 =
+        "Portions copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.";
+
+    /**
+    Provides easy way to use basic functions of GridBagLayout, without
+    the complications. After building a panel, and inserting all the
+    * subcomponents, call this to lay it out in the desired number of columns.
+    */
+    public static void fixGrid(Container cont, int columns) {
+        GridBagLayout gridbag = new GridBagLayout();
+        cont.setLayout(gridbag);
+
+        GridBagConstraints c = new GridBagConstraints();
+        c.fill = GridBagConstraints.VERTICAL;
+        c.weightx = 1.0;
+        c.insets = new Insets(2,2,2,2);
+
+        Component[] components = cont.getComponents();
+        for (int i = 0; i < components.length; ++i) {
+            // not used int colNumber = i%columns;
+            c.gridwidth = 1;    // default
+            if ((i%columns) == columns - 1)
+                c.gridwidth = GridBagConstraints.REMAINDER;    // last in grid
+            if (components[i] instanceof Label) {
+                switch (((Label)components[i]).getAlignment()) {
+                case Label.CENTER: c.anchor = GridBagConstraints.CENTER; break;
+                case Label.LEFT: c.anchor = GridBagConstraints.WEST; break;
+                case Label.RIGHT: c.anchor = GridBagConstraints.EAST; break;
+                }
+            }
+            gridbag.setConstraints(components[i], c);
+        }
+
+    }
+
+    /**
+    Provides easy way to change the spacing around an object in a GridBagLayout.
+    Call AFTER fixGridBag, passing in the container, the component, and the
+    new insets.
+    */
+    public static void setInsets(Container cont, Component comp, Insets insets) {
+        GridBagLayout gbl = (GridBagLayout)cont.getLayout();
+        GridBagConstraints g = gbl.getConstraints(comp);
+        g.insets = insets;
+        gbl.setConstraints(comp,g);
+    }
+
+    public static Panel createSpacer() {
+        Panel spacer = new Panel();
+        spacer.setLayout(null);
+        spacer.setSize(1000, 1);
+        return spacer;
+    }
+
+    // to avoid goofy updates and misplaced cursors
+    public static void setText(TextComponent area, String newText) {
+        String foo = area.getText();
+        if (foo.equals(newText)) return;
+        area.setText(newText);
+    }
+    
+    /**
+     * Compares two locals. Return value is negative
+     * if they're different, and more positive the more
+     * fields that match.
+     */
+     
+    public static int compareLocales(Locale l1, Locale l2)
+    {
+        int result = -1;
+        
+        if (l1.getLanguage().equals(l2.getLanguage())) {
+            result += 1;
+            
+            if (l1.getCountry().equals(l2.getCountry())) {
+                result += 1;
+                
+                if (l1.getVariant().equals(l2.getVariant())) {
+                    result += 1;
+                }
+            }
+        }
+        
+        return result;
+    }
+    
+    /**
+     * Get the G7 locale list for demos.
+     */
+    public static Locale[] getG7Locales() {
+        return localeList;
+    }
+    private static Locale[] localeList = {
+        new Locale("DA", "DK", ""),
+        new Locale("EN", "US", ""),
+        new Locale("EN", "GB", ""),
+        new Locale("EN", "CA", ""),
+        new Locale("FR", "FR", ""),
+        new Locale("FR", "CA", ""),
+        new Locale("DE", "DE", ""),
+        new Locale("IT", "IT", ""),
+    //new Locale("JA", "JP", ""),
+    };
+}
diff --git a/src/com/ibm/demo/calendar/CalendarApp.java b/src/com/ibm/demo/calendar/CalendarApp.java
new file mode 100755
index 0000000..4ff0d48
--- /dev/null
+++ b/src/com/ibm/demo/calendar/CalendarApp.java
@@ -0,0 +1,45 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/calendar/Attic/CalendarApp.java,v $ 
+ * $Date: 2000/05/12 23:21:23 $ 
+ * $Revision: 1.5 $
+ *
+ *****************************************************************************************
+ */
+
+package com.ibm.demo.calendar;
+
+import com.ibm.demo.*;
+
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.*;
+import java.net.*;
+import java.io.*;
+
+import com.ibm.util.*;
+import com.ibm.text.*;
+
+/**
+ * CalendarApp demonstrates how Calendar works.
+ */
+public class CalendarApp extends DemoApplet
+{
+    /**
+     * The main function which defines the behavior of the CalendarDemo
+     * applet when an applet is started.
+     */
+    public static void main(String argv[]) {
+
+        new CalendarApp().showDemo();
+    }
+
+    /* This creates a CalendarFrame for the demo applet. */
+    public Frame createDemoFrame(DemoApplet applet) {
+        return new CalendarFrame(applet);
+    }
+}
diff --git a/src/com/ibm/demo/calendar/CalendarCalc.java b/src/com/ibm/demo/calendar/CalendarCalc.java
new file mode 100755
index 0000000..18e7c1c
--- /dev/null
+++ b/src/com/ibm/demo/calendar/CalendarCalc.java
@@ -0,0 +1,584 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/calendar/Attic/CalendarCalc.java,v $ 
+ * $Date: 2001/10/30 02:42:50 $ 
+ * $Revision: 1.9 $
+ *
+ *****************************************************************************************
+ */
+
+package com.ibm.demo.calendar;
+
+import com.ibm.demo.*;
+
+import java.applet.Applet;
+import java.util.Date;
+import java.awt.*;
+import java.awt.event.*;
+
+//import java.text.DateFormat;
+import com.ibm.text.DateFormat;
+import java.text.ParsePosition;
+
+//import java.util.Calendar;
+import com.ibm.util.Calendar;
+//import java.util.GregorianCalendar;
+import com.ibm.util.GregorianCalendar;
+//import java.util.TimeZone;
+import com.ibm.util.TimeZone;
+import java.util.Locale;
+
+import com.ibm.util.*;
+import com.ibm.text.*;
+
+import javax.swing.*;
+
+/**
+ * CalendarCalc demonstrates how Date/Time formatter works.
+ */
+public class CalendarCalc extends DemoApplet
+{
+    /**
+     * The main function which defines the behavior of the MultiCalendarDemo
+     * applet when an applet is started.
+     */
+    public static void main(String argv[]) {
+        new CalendarCalc().showDemo();
+    }
+
+    /**
+     * This creates a CalendarCalcFrame for the demo applet.
+     */
+    public Frame createDemoFrame(DemoApplet applet) {
+        return new CalendarCalcFrame(applet);
+    }
+}
+
+/**
+ * A Frame is a top-level window with a title. The default layout for a frame
+ * is BorderLayout.  The CalendarCalcFrame class defines the window layout of
+ * MultiCalendarDemo.
+ */
+class CalendarCalcFrame extends Frame implements ActionListener
+{
+    private static final String     creditString = "";
+
+    static final Locale[] locales = DemoUtility.getG7Locales();
+
+    private static final boolean    DEBUG = false;
+
+    private DemoApplet              applet;
+    private long                    time = System.currentTimeMillis();
+
+    private static final RollAddField kRollAddFields[] = {
+        new RollAddField(Calendar.YEAR,                 "Year" ),
+        new RollAddField(Calendar.MONTH,                "Month" ),
+        new RollAddField(Calendar.WEEK_OF_MONTH,        "Week of Month" ),
+        new RollAddField(Calendar.WEEK_OF_YEAR,         "Week of Year" ),
+        new RollAddField(Calendar.DAY_OF_MONTH,         "Day of Month" ),
+        new RollAddField(Calendar.DAY_OF_WEEK,          "Day of Week" ),
+        new RollAddField(Calendar.DAY_OF_WEEK_IN_MONTH, "Day of Week in Month" ),
+        new RollAddField(Calendar.DAY_OF_YEAR,          "Day of Year" ),
+        new RollAddField(Calendar.AM_PM,                "AM/PM" ),
+        new RollAddField(Calendar.HOUR_OF_DAY,          "Hour of day" ),
+        new RollAddField(Calendar.HOUR,                 "Hour" ),
+        new RollAddField(Calendar.MINUTE,               "Minute" ),
+        new RollAddField(Calendar.SECOND,               "Second" ),
+    };
+
+    /**
+     * Constructs a new CalendarCalcFrame that is initially invisible.
+     */
+    public CalendarCalcFrame(DemoApplet applet)
+    {
+        super("Multiple Calendar Demo");
+        this.applet = applet;
+        init();
+        start();
+    }
+
+    /**
+     * Initializes the applet. You never need to call this directly, it
+     * is called automatically by the system once the applet is created.
+     */
+    public void init()
+    {
+        buildGUI();
+
+        patternText.setText( calendars[0].toPattern() );
+
+        // Force an update of the display
+        cityChanged();
+        millisFormat();
+        enableEvents(KeyEvent.KEY_RELEASED);
+        enableEvents(WindowEvent.WINDOW_CLOSING);
+    }
+
+    //------------------------------------------------------------
+    // package private
+    //------------------------------------------------------------
+    void addWithFont(Container container, Component foo, Font font) {
+        if (font != null)
+            foo.setFont(font);
+        container.add(foo);
+    }
+
+    /**
+     * Called to start the applet. You never need to call this method
+     * directly, it is called when the applet's document is visited.
+     */
+    public void start()
+    {
+        // do nothing
+    }
+
+    TextField patternText;
+
+    Choice dateMenu;
+    Choice localeMenu;
+
+    Button up;
+    Button down;
+
+    Checkbox getRoll;
+    Checkbox getAdd;
+
+    public void buildGUI()
+    {
+        setBackground(DemoUtility.bgColor);
+        setLayout(new FlowLayout()); // shouldn't be necessary, but it is.
+
+// TITLE
+        Label label1=new Label("Calendar Converter", Label.CENTER);
+        label1.setFont(DemoUtility.titleFont);
+        add(label1);
+        add(DemoUtility.createSpacer());
+
+// IO Panel
+        Panel topPanel = new Panel();
+        topPanel.setLayout(new FlowLayout());
+
+        CheckboxGroup group1= new CheckboxGroup();
+
+        // Set up the controls for each calendar we're demonstrating
+        for (int i = 0; i < calendars.length; i++)
+        {
+            Label label = new Label(calendars[i].name, Label.RIGHT);
+            label.setFont(DemoUtility.labelFont);
+            topPanel.add(label);
+
+            topPanel.add(calendars[i].text);
+
+            final int j = i;
+            calendars[i].text.addActionListener( new ActionListener() {
+                public void actionPerformed(ActionEvent e) {
+                    textChanged(j);
+                }
+            } );
+
+            calendars[i].rollAdd.setCheckboxGroup(group1);
+            topPanel.add(calendars[i].rollAdd);
+        }
+        calendars[0].rollAdd.setState(true);    // Make the first one selected
+
+        Label label4=new Label("Pattern", Label.RIGHT);
+        label4.setFont(DemoUtility.labelFont);
+        topPanel.add(label4);
+
+        patternText=new TextField(FIELD_COLUMNS);
+        patternText.setFont(DemoUtility.editFont);
+        topPanel.add(patternText);
+        topPanel.add(new Label(""));
+
+        DemoUtility.fixGrid(topPanel,3);
+        add(topPanel);
+        add(DemoUtility.createSpacer());
+
+// ROLL / ADD
+        Panel rollAddPanel=new Panel();
+        {
+            rollAddPanel.setLayout(new FlowLayout());
+
+            Panel rollAddBoxes = new Panel();
+            {
+                rollAddBoxes.setLayout(new GridLayout(2,1));
+                CheckboxGroup group2= new CheckboxGroup();
+                getRoll = new Checkbox("Roll",group2, false);
+                getAdd = new Checkbox("Add",group2, true);
+
+                rollAddBoxes.add(getRoll);
+                rollAddBoxes.add(getAdd);
+            }
+
+            Label dateLabel=new Label("Date Fields");
+            dateLabel.setFont(DemoUtility.labelFont);
+
+            dateMenu= new Choice();
+            dateMenu.setBackground(DemoUtility.choiceColor);
+            for (int i = 0; i < kRollAddFields.length; i++) {
+                dateMenu.addItem(kRollAddFields[i].name);
+                if (kRollAddFields[i].field == Calendar.MONTH) {
+                    dateMenu.select(i);
+                }
+            }
+
+            Panel upDown = new Panel();
+            {
+                upDown.setLayout(new GridLayout(2,1));
+
+                // *** If the images are not found, we use the label.
+                up = new Button("^");
+                down = new Button("v");
+                up.setBackground(DemoUtility.bgColor);
+                down.setBackground(DemoUtility.bgColor);
+                upDown.add(up);
+                upDown.add(down);
+                up.addActionListener(this);
+                down.addActionListener(this);
+            }
+
+            rollAddPanel.add(dateLabel);
+            rollAddPanel.add(dateMenu);
+            rollAddPanel.add(rollAddBoxes);
+            rollAddPanel.add(upDown);
+
+        }
+        Panel localePanel = new Panel();
+        {
+            // Make the locale popup menus
+            localeMenu= new Choice();
+            Locale defaultLocale = Locale.getDefault();
+            int bestMatch = -1, thisMatch = -1;
+            int selectMe = 0;
+            
+            for (int i = 0; i < locales.length; i++) {
+                if (i > 0 && locales[i].getLanguage().equals(locales[i-1].getLanguage()) ||
+                    i < locales.length - 1 &&
+                        locales[i].getLanguage().equals(locales[i+1].getLanguage()))
+                {
+                    localeMenu.addItem( locales[i].getDisplayName() );
+                } else {
+                    localeMenu.addItem( locales[i].getDisplayLanguage());
+                }
+                
+                thisMatch = DemoUtility.compareLocales(locales[i], defaultLocale);
+                
+                if (thisMatch >= bestMatch) {
+                    bestMatch = thisMatch;
+                    selectMe = i;
+                }
+            }
+            
+            localeMenu.setBackground(DemoUtility.choiceColor);
+            localeMenu.select(selectMe);
+
+            Label localeLabel =new Label("Display Locale");
+            localeLabel.setFont(DemoUtility.labelFont);
+
+            localePanel.add(localeLabel);
+            localePanel.add(localeMenu);
+            DemoUtility.fixGrid(localePanel,2);
+
+            localeMenu.addItemListener( new ItemListener() {
+                public void itemStateChanged(ItemEvent e) {
+                    Locale loc = locales[localeMenu.getSelectedIndex()];
+                    System.out.println("Change locale to " + loc.getDisplayName());
+
+                    for (int i = 0; i < calendars.length; i++) {
+                        calendars[i].setLocale(loc);
+                    }
+                    millisFormat();
+                }
+            } );
+        }
+        add(rollAddPanel);
+        add(DemoUtility.createSpacer());
+        add(localePanel);
+        add(DemoUtility.createSpacer());
+
+// COPYRIGHT
+        Panel copyrightPanel = new Panel();
+        addWithFont (copyrightPanel,new Label(DemoUtility.copyright1, Label.LEFT),
+            DemoUtility.creditFont);
+        DemoUtility.fixGrid(copyrightPanel,1);
+        add(copyrightPanel);
+    }
+
+    /**
+     * This function is called when users change the pattern text.
+     */
+    public void setFormatFromPattern() {
+        String timePattern = patternText.getText();
+
+        for (int i = 0; i < calendars.length; i++) {
+            calendars[i].applyPattern(timePattern);
+        }
+
+        millisFormat();
+    }
+
+    /**
+     * This function is called when it is necessary to parse the time
+     * string in one of the formatted date fields
+     */
+    public void textChanged(int index) {
+        String rightString = calendars[index].text.getText();
+
+        ParsePosition status = new ParsePosition(0);
+
+        if (rightString.length() == 0)
+        {
+            errorText("Error: no input to parse!");
+            return;
+        }
+
+        try {
+            Date date = calendars[index].format.parse(rightString, status);
+            time = date.getTime();
+        }
+        catch (Exception e) {
+            for (int i = 0; i < calendars.length; i++) {
+                if (i != index) {
+                    calendars[i].text.setText("ERROR");
+                }
+            }
+            errorText("Exception: " + e.getClass().toString() + " parsing: "+rightString);
+            return;
+        }
+
+        int start = calendars[index].text.getSelectionStart();
+        int end = calendars[index].text.getSelectionEnd();
+
+        millisFormat();
+
+        calendars[index].text.select(start,end);
+    }
+
+    /**
+     * This function is called when it is necessary to format the time
+     * in the "Millis" text field.
+     */
+    public void millisFormat() {
+        String out = "";
+
+        for (int i = 0; i < calendars.length; i++) {
+            try {
+                out = calendars[i].format.format(new Date(time));
+                calendars[i].text.setText(out);
+            }
+            catch (Exception e) {
+                calendars[i].text.setText("ERROR");
+                errorText("Exception: " + e.getClass().toString() + " formatting "
+                            + calendars[i].name + " " + time);
+            }
+        }
+    }
+
+
+    /**
+     * This function is called when users change the pattern text.
+     */
+    public void patternTextChanged() {
+        setFormatFromPattern();
+    }
+
+    /**
+     * This function is called when users select a new representative city.
+     */
+    public void cityChanged() {
+        TimeZone timeZone = TimeZone.getDefault();
+
+        for (int i = 0; i < calendars.length; i++) {
+            calendars[i].format.setTimeZone(timeZone);
+        }
+        millisFormat();
+    }
+
+    /**
+     * This function is called when users select a new time field
+     * to add or roll its value.
+     */
+    public void dateFieldChanged(boolean up) {
+        int field = kRollAddFields[dateMenu.getSelectedIndex()].field;
+
+        for (int i = 0; i < calendars.length; i++)
+        {
+            if (calendars[i].rollAdd.getState())
+            {
+                Calendar c = calendars[i].calendar;
+                c.setTime(new Date(time));
+
+                if (getAdd.getState()) {
+                    c.add(field, up ? 1 : -1);
+                } else {
+                    c.roll(field, up);
+                }
+
+                time = c.getTime().getTime();
+                millisFormat();
+                break;
+            }
+        }
+    }
+
+    /**
+     * Print out the error message while debugging this program.
+     */
+    public void errorText(String s)
+    {
+        if (true) {
+            System.out.println(s);
+        }
+    }
+    
+    /**
+     * Called if an action occurs in the CalendarCalcFrame object.
+     */
+    public void actionPerformed(ActionEvent evt)
+    {
+        // *** Button events are handled here.
+        Object obj = evt.getSource();
+        System.out.println("action " + obj);
+        if (obj instanceof Button) {
+            if (evt.getSource() == up) {
+                dateFieldChanged(false);
+            } else
+                if (evt.getSource() == down) {
+                    dateFieldChanged(true);
+            }
+        }
+    }
+    
+    /**
+     * Handles the event. Returns true if the event is handled and should not
+     * be passed to the parent of this component. The default event handler
+     * calls some helper methods to make life easier on the programmer.
+     */
+    protected void processKeyEvent(KeyEvent evt)
+    {
+        System.out.println("key " + evt);
+        if (evt.getID() == KeyEvent.KEY_RELEASED) { 
+            if (evt.getSource() == patternText) {
+                patternTextChanged();
+            }
+            else {
+                for (int i = 0; i < calendars.length; i++) {
+                    if (evt.getSource() == calendars[i].text) {
+                        textChanged(i);
+                    }
+                }
+            }
+        }
+    }
+    
+    protected void processWindowEvent(WindowEvent evt) 
+    {
+        System.out.println("window " + evt);
+        if (evt.getID() == WindowEvent.WINDOW_CLOSING && 
+            evt.getSource() == this) {
+            this.hide();
+            this.dispose();
+
+            if (applet != null) {
+               applet.demoClosed();
+            } else System.exit(0);
+        }
+    }
+    
+    /*
+    protected void processEvent(AWTEvent evt)
+    {
+        if (evt.getID() == AWTEvent. Event.ACTION_EVENT && evt.target == up) {
+            dateFieldChanged(true);
+            return true;
+        }
+        else if (evt.id == Event.ACTION_EVENT && evt.target == down) {
+            dateFieldChanged(false);
+            return true;
+        }
+    }
+    */
+
+    private static final int        FIELD_COLUMNS = 35;
+    private static final String     DEFAULT_FORMAT = "EEEE MMMM d, yyyy G";
+
+
+    class CalendarRec {
+        public CalendarRec(String nameStr, Calendar cal)
+        {
+            name = nameStr;
+            calendar = cal;
+            rollAdd = new Checkbox();
+
+            text = new JTextField("",FIELD_COLUMNS);
+            text.setFont(DemoUtility.editFont);
+
+            format = DateFormat.getDateInstance(cal, DateFormat.FULL,
+                                                Locale.getDefault());
+            //format.applyPattern(DEFAULT_FORMAT);
+        }
+
+        public void setLocale(Locale loc) {
+            String pattern = toPattern();
+
+            format = DateFormat.getDateInstance(calendar, DateFormat.FULL,
+                                                loc);
+            applyPattern(pattern);
+        }
+
+        public void applyPattern(String pattern) {
+            if (format instanceof SimpleDateFormat) {
+                ((SimpleDateFormat)format).applyPattern(pattern);
+//hey {al} - 
+//            } else if (format instanceof java.text.SimpleDateFormat) {
+//                ((java.text.SimpleDateFormat)format).applyPattern(pattern);
+            }
+        }
+        
+        private String toPattern() {
+            if (format instanceof SimpleDateFormat) {
+                return ((SimpleDateFormat)format).toPattern();
+//hey {al} - 
+//            } else if (format instanceof java.text.SimpleDateFormat) {
+//                return ((java.text.SimpleDateFormat)format).toPattern();
+            } else {
+                return "";
+            }
+        }
+
+        Calendar  calendar;
+        DateFormat          format;
+        String              name;
+        JTextField           text;
+        Checkbox            rollAdd;
+    };
+
+    private final CalendarRec[] calendars = {
+        new CalendarRec("Gregorian",        new GregorianCalendar()),
+        new CalendarRec("Hebrew",           new HebrewCalendar()),
+        new CalendarRec("Islamic (civil)",  makeIslamic(true)),
+        new CalendarRec("Islamic (true)",   makeIslamic(false)),
+        new CalendarRec("Buddhist",         new BuddhistCalendar()),
+        new CalendarRec("Japanese",         new JapaneseCalendar()),
+//        new CalendarRec("Chinese",          new ChineseCalendar()),
+    };
+
+    static private final Calendar makeIslamic(boolean civil) {
+        IslamicCalendar cal = new IslamicCalendar();
+        cal.setCivil(civil);
+        return cal;
+    };
+};
+
+class RollAddField {
+    RollAddField(int field, String name) {
+        this.field = field;
+        this.name = name;
+    }
+    int field;
+    String name;
+};
diff --git a/src/com/ibm/demo/calendar/CalendarFrame.java b/src/com/ibm/demo/calendar/CalendarFrame.java
new file mode 100755
index 0000000..9b400fe
--- /dev/null
+++ b/src/com/ibm/demo/calendar/CalendarFrame.java
@@ -0,0 +1,435 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/calendar/Attic/CalendarFrame.java,v $ 
+ * $Date: 2000/10/19 00:27:16 $ 
+ * $Revision: 1.8 $
+ *
+ *****************************************************************************************
+ */
+
+package com.ibm.demo.calendar;
+
+import com.ibm.demo.*;
+import com.ibm.util.Calendar;
+import com.ibm.util.HebrewCalendar;
+import com.ibm.util.BuddhistCalendar;
+import com.ibm.util.JapaneseCalendar;
+import com.ibm.util.IslamicCalendar;
+import com.ibm.text.SimpleDateFormat;
+//import java.util.SimpleTimeZone;
+import com.ibm.util.SimpleTimeZone;
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.*;
+import java.net.*;
+import java.io.*;
+//import java.text.DateFormat;
+import com.ibm.text.DateFormat;
+import java.text.MessageFormat;
+//import java.util.Calendar;
+import com.ibm.util.Calendar;
+import java.util.Date;
+//import java.util.GregorianCalendar;
+import com.ibm.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+//import java.util.TimeZone;
+import com.ibm.util.TimeZone;
+
+/**
+ * A Frame is a top-level window with a title. The default layout for a frame
+ * is BorderLayout.  The CalendarFrame class defines the window layout of
+ * CalendarDemo.
+ */
+class CalendarFrame extends Frame
+{
+    private static final boolean DEBUG = false;
+
+    private DemoApplet applet;
+
+    /**
+     * Constructs a new CalendarFrame that is initially invisible.
+     */
+    public CalendarFrame(DemoApplet myApplet)
+    {
+        super("Calendar Demo");
+        this.applet = myApplet;
+        init();
+
+        // When the window is closed, we want to shut down the applet or application
+        addWindowListener(
+            new WindowAdapter() {
+                public void windowClosing(WindowEvent e) {
+                    setVisible(false);
+                    dispose();
+
+                    if (applet != null) {
+                        applet.demoClosed();
+                    } else System.exit(0);
+                }
+            } );
+    }
+
+    private Choice          displayMenu;
+    private Locale[]        locales = DemoUtility.getG7Locales();
+
+    private Calendar        calendars[]   = new Calendar[2];
+    private Choice          calMenu[]     = new Choice[2];
+    private ColoredLabel    monthLabel[]  = new ColoredLabel[2];
+    private DateFormat      monthFormat[] = new DateFormat[2];
+
+    private Button          prevYear;
+    private Button          prevMonth;
+    private Button          gotoToday;
+    private Button          nextMonth;
+    private Button          nextYear;
+    private CalendarPanel   calendarPanel;
+
+    private static void add(Container container, Component component,
+                            GridBagLayout g, GridBagConstraints c,
+                            int gridwidth, int weightx)
+    {
+        c.gridwidth = gridwidth;
+        c.weightx = weightx;
+        g.setConstraints(component, c);
+        container.add(component);
+    }
+
+    /**
+     * Initializes the applet. You never need to call this directly, it
+     * is called automatically by the system once the applet is created.
+     */
+    public void init() {
+        setBackground(DemoUtility.bgColor);
+        setLayout(new BorderLayout(10,10));
+
+        Panel topPanel = new Panel();
+        GridBagLayout g = new GridBagLayout();
+        topPanel.setLayout(g);
+        GridBagConstraints c = new GridBagConstraints();
+        c.fill = GridBagConstraints.HORIZONTAL;
+
+        // Build the two menus for selecting which calendar is displayed,
+        // plus the month/year label for each calendar
+        for (int i = 0; i < 2; i++) {
+            calMenu[i] = new Choice();
+            for (int j = 0; j < CALENDARS.length; j++) {
+                calMenu[i].addItem(CALENDARS[j].name);
+            }
+            calMenu[i].setBackground(DemoUtility.choiceColor);
+            calMenu[i].select(i);
+            calMenu[i].addItemListener(new CalMenuListener());
+
+            // Label for the current month name
+            monthLabel[i] = new ColoredLabel("", COLORS[i]);
+            monthLabel[i].setFont(DemoUtility.titleFont);
+
+            // And the default calendar to use for this slot
+            calendars[i] = CALENDARS[i].calendar;
+
+            add(topPanel, calMenu[i], g, c, 5, 0);
+            add(topPanel, monthLabel[i], g, c, GridBagConstraints.REMAINDER, 1);
+        }
+
+        // Now add the next/previous year/month buttons:
+        prevYear = new Button("<<");
+        prevYear.addActionListener(new AddAction(Calendar.YEAR, -1));
+
+        prevMonth = new Button("<");
+        prevMonth.addActionListener(new AddAction(Calendar.MONTH, -1));
+
+        gotoToday = new Button("Today");
+        gotoToday.addActionListener( new ActionListener()
+        {
+            public void actionPerformed(ActionEvent e) {
+                calendarPanel.setDate( new Date() );
+                updateMonthName();
+            }
+        } );
+
+        nextMonth = new Button(">");
+        nextMonth.addActionListener(new AddAction(Calendar.MONTH, 1));
+
+        nextYear = new Button(">>");
+        nextYear.addActionListener(new AddAction(Calendar.YEAR, 1));
+
+        c.fill = GridBagConstraints.NONE;
+        add(topPanel, prevYear,  g, c, 1, 0);
+        add(topPanel, prevMonth, g, c, 1, 0);
+        add(topPanel, gotoToday, g, c, 1, 0);
+        add(topPanel, nextMonth, g, c, 1, 0);
+        add(topPanel, nextYear,  g, c, 1, 0);
+
+        // Now add the menu for selecting the display language
+        Panel displayPanel = new Panel();
+        {
+            displayMenu = new Choice();
+            Locale defaultLocale = Locale.getDefault();
+            int bestMatch = -1, thisMatch = -1;
+            int selectMe = 0;
+            
+            for (int i = 0; i < locales.length; i++) {
+                if (i > 0 &&
+                        locales[i].getLanguage().equals(locales[i-1].getLanguage()) ||
+                    i < locales.length - 1 &&
+                        locales[i].getLanguage().equals(locales[i+1].getLanguage()))
+                {
+                    displayMenu.addItem( locales[i].getDisplayName() );
+                } else {
+                    displayMenu.addItem( locales[i].getDisplayLanguage());
+                }
+
+                thisMatch = DemoUtility.compareLocales(locales[i], defaultLocale);
+                
+                if (thisMatch >= bestMatch) {
+                    bestMatch = thisMatch;
+                    selectMe = i;
+                }
+            }
+            
+            displayMenu.setBackground(DemoUtility.choiceColor);
+            displayMenu.select(selectMe);
+
+            displayMenu.addItemListener( new ItemListener()
+            {
+                 public void itemStateChanged(ItemEvent e) {
+                    Locale loc = locales[displayMenu.getSelectedIndex()];
+                    calendarPanel.setLocale( loc );
+                    monthFormat[0] = monthFormat[1] = null;
+                    updateMonthName();
+                    repaint();
+                }
+            } );
+
+            Label l1 = new Label("Display Language:", Label.RIGHT);
+            l1.setFont(DemoUtility.labelFont);
+
+            displayPanel.setLayout(new FlowLayout());
+            displayPanel.add(l1);
+            displayPanel.add(displayMenu);
+
+        }
+        c.fill = GridBagConstraints.NONE;
+        c.anchor = GridBagConstraints.EAST;
+
+        add(topPanel, displayPanel, g, c, GridBagConstraints.REMAINDER, 0);
+
+        // The title, buttons, etc. go in a panel at the top of the window
+        add("North", topPanel);
+
+        // The copyright notice goes at the bottom of the window
+        Label copyright = new Label(DemoUtility.copyright1, Label.LEFT);
+        copyright.setFont(DemoUtility.creditFont);
+        add("South", copyright);
+
+        // Now create the big calendar panel and stick it in the middle
+        calendarPanel = new CalendarPanel( locales[displayMenu.getSelectedIndex()] );
+        add("Center", calendarPanel);
+
+        for (int i = 0; i < 2; i++) {
+            calendarPanel.setCalendar(i, calendars[i]);
+            calendarPanel.setColor(i, COLORS[i]);
+        }
+
+        updateMonthName();
+    };
+
+
+    private void updateMonthName()
+    {
+            for (int i = 0; i < 2; i++) {
+                try {
+                    if (monthFormat[i] == null) {     // TODO: optimize
+                        DateFormat f = DateFormat.getDateTimeInstance(
+                                                calendars[i], DateFormat.MEDIUM, -1,
+                                                locales[displayMenu.getSelectedIndex()]);
+                        if (f instanceof com.ibm.text.SimpleDateFormat) {
+                            com.ibm.text.SimpleDateFormat f1 = (com.ibm.text.SimpleDateFormat) f;
+                            f1.applyPattern("MMMM, yyyy G");
+                            f1.setTimeZone(new SimpleTimeZone(0, "UTC"));
+//hey {al} -
+//                        } else if (f instanceof java.text.SimpleDateFormat) {
+//                            java.text.SimpleDateFormat f1 = (java.text.SimpleDateFormat) f;
+//                            f1.applyPattern("MMMM, yyyy G");
+//                            f1.setTimeZone(new SimpleTimeZone(0, "UTC"));
+                        }
+                        monthFormat[i] = f;
+                    }
+                } catch (ClassCastException e) {
+                    //hey {lw} - there's something wrong in this routine that cuases exceptions.
+                    System.out.println(e);
+                }
+
+                monthLabel[i].setText( monthFormat[i].format( calendarPanel.firstOfMonth() ));
+            }
+    }
+
+    /**
+     * CalMenuListener responds to events in the two popup menus that select
+     * the calendar systems to be used in the display.  It figures out which
+     * of the two menus the event occurred in and updates the corresponding
+     * element of the calendars[] array to match the new selection.
+     */
+    private class CalMenuListener implements ItemListener
+    {
+         public void itemStateChanged(ItemEvent e)
+         {
+            for (int i = 0; i < calMenu.length; i++)
+            {
+                if (e.getItemSelectable() == calMenu[i])
+                {
+                    // We found the menu that the event happened in.
+                    // Figure out which new calendar they selected.
+                    Calendar newCal = CALENDARS[ calMenu[i].getSelectedIndex() ].calendar;
+
+                    if (newCal != calendars[i])
+                    {
+                        // If any of the other menus are set to the same new calendar
+                        // we're about to use for this menu, set them to the current
+                        // calendar from *this* menu so we won't have two the same
+                        for (int j = 0; j < calendars.length; j++) {
+                            if (j != i && calendars[j] == newCal) {
+                                calendars[j] = calendars[i];
+                                calendarPanel.setCalendar(j, calendars[j]);
+                                monthFormat[j] = null;
+
+                                for (int k = 0; k < CALENDARS.length; k++) {
+                                    if (calendars[j] == CALENDARS[k].calendar) {
+                                        calMenu[j].select(k);
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                        // Now update this menu to use the new calendar the user selected
+                        calendars[i] = newCal;
+                        calendarPanel.setCalendar(i, newCal);
+                        monthFormat[i] = null;
+
+                        updateMonthName();
+                    }
+                    break;
+                }
+            }
+         }
+    };
+
+    /**
+     * AddAction handles the next/previous year/month buttons...
+     */
+    private class AddAction implements ActionListener {
+        AddAction(int field, int amount) {
+            this.field = field;
+            this.amount = amount;
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            calendarPanel.add(field, amount);
+            updateMonthName();
+        }
+
+        private int field, amount;
+    }
+
+    /**
+     * ColoredLabel is similar to java.awt.Label, with two differences:
+     *
+     *  - You can set its text color
+     *
+     *  - It draws text using drawString rather than using a host-specific
+     *    "Peer" object like AWT does.  On 1.2, using drawString gives
+     *    us Bidi reordering for free.
+     */
+    static private class ColoredLabel extends Component {
+        public ColoredLabel(String label) {
+            text = label;
+        }
+
+        public ColoredLabel(String label, Color c) {
+            text = label;
+            color = c;
+        }
+
+        public void setText(String label) {
+            text = label;
+            repaint();
+        }
+
+        public void setFont(Font f) {
+            font = f;
+            repaint();
+        }
+
+        public void paint(Graphics g) {
+            FontMetrics fm = g.getFontMetrics(font);
+
+            Rectangle bounds = getBounds();
+
+            g.setColor(color);
+            g.setFont(font);
+            g.drawString(text, fm.stringWidth("\u00a0"),
+                         bounds.height/2 + fm.getHeight()
+                         - fm.getAscent() + fm.getLeading()/2);
+        }
+
+        public Dimension getPreferredSize() {
+            return getMinimumSize();
+        }
+
+        public Dimension getMinimumSize() {
+            FontMetrics fm = getFontMetrics(font);
+
+            return new Dimension( fm.stringWidth(text) + 2*fm.stringWidth("\u00a0"),
+                                  fm.getHeight() + fm.getLeading()*2);
+        }
+
+        String text;
+        Color color = Color.black;
+        Font font = DemoUtility.labelFont;
+    }
+
+    /**
+     * Print out the error message while debugging this program.
+     */
+    public void errorText(String s)
+    {
+        if (DEBUG)
+        {
+            System.out.println(s);
+        }
+    }
+
+    class CalendarRec {
+        public CalendarRec(String nameStr, Calendar cal)
+        {
+            name = nameStr;
+            calendar = cal;
+        }
+
+        Calendar  calendar;
+        String              name;
+    };
+
+    private final CalendarRec[] CALENDARS = {
+        new CalendarRec("Gregorian Calendar",       new GregorianCalendar()),
+        new CalendarRec("Hebrew Calendar",          new HebrewCalendar()),
+        new CalendarRec("Islamic Calendar",         makeIslamic(false)),
+        new CalendarRec("Islamic Civil Calendar ",  makeIslamic(true)),
+        new CalendarRec("Buddhist Calendar",        new BuddhistCalendar()),
+        new CalendarRec("Japanese Calendar",        new JapaneseCalendar()),
+    };
+
+    static private final Calendar makeIslamic(boolean civil) {
+        IslamicCalendar cal = new IslamicCalendar();
+        cal.setCivil(civil);
+        return cal;
+    };
+
+    static final Color[] COLORS = { Color.blue, Color.black };
+}
+
diff --git a/src/com/ibm/demo/calendar/CalendarPanel.java b/src/com/ibm/demo/calendar/CalendarPanel.java
new file mode 100755
index 0000000..7ce6db6
--- /dev/null
+++ b/src/com/ibm/demo/calendar/CalendarPanel.java
@@ -0,0 +1,369 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/calendar/Attic/CalendarPanel.java,v $ 
+ * $Date: 2001/09/08 01:38:55 $ 
+ * $Revision: 1.7 $
+ *
+ *****************************************************************************************
+ */
+
+package com.ibm.demo.calendar;
+
+import com.ibm.demo.*;
+
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.*;
+//import java.util.*;
+import java.net.*;
+import java.io.*;
+
+//import java.text.DateFormat;
+import com.ibm.text.DateFormat;
+//import java.util.SimpleTimeZone;
+import com.ibm.util.SimpleTimeZone;
+//import java.util.*;
+import java.util.Date;
+import java.util.Locale;
+
+import com.ibm.util.*;
+import com.ibm.text.*;
+
+class CalendarPanel extends Canvas {
+
+    public CalendarPanel( Locale locale ) {
+        setLocale(locale);
+    }
+
+    public void setLocale(Locale locale) {
+        if (fDisplayLocale == null || !fDisplayLocale.equals(locale)) {
+            fDisplayLocale = locale;
+            dirty = true;
+
+            for (int i = 0; i < fCalendar.length; i++) {
+                if (fCalendar[i] != null) {
+                    fSymbols[i] = new DateFormatSymbols(fCalendar[i],
+                                                        fDisplayLocale);
+                }
+            }
+            String lang = locale.getLanguage();
+            leftToRight = !(lang.equals("iw") || lang.equals("ar"));
+
+            repaint();
+        }
+    }
+
+    public void setDate(Date date) {
+        fStartOfMonth = date;
+        dirty = true;
+        repaint();
+    }
+
+    public void add(int field, int delta)
+    {
+        synchronized(fCalendar) {
+            fCalendar[0].setTime(fStartOfMonth);
+            fCalendar[0].add(field, delta);
+            fStartOfMonth = fCalendar[0].getTime();
+        }
+        dirty = true;
+        repaint();
+    }
+
+    public void setColor(int index, Color c) {
+        fColor[index] = c;
+        repaint();
+    }
+
+    public void setCalendar(int index, Calendar c) {
+        Date date = (fCalendar[index] == null) ? new Date()
+                                               : fCalendar[index].getTime();
+
+        fCalendar[index] = c;
+        fCalendar[index].setTime(date);
+
+        fSymbols[index] = new DateFormatSymbols(c, fDisplayLocale);
+        dirty = true;
+        repaint();
+    }
+
+    public Calendar getCalendar(int index) {
+        return fCalendar[index];
+    }
+
+    public Locale getDisplayLocale() {
+        return fDisplayLocale;
+    }
+
+    public Date firstOfMonth() {
+        return fStartOfMonth;
+    }
+
+    private Date startOfMonth(Date dateInMonth)
+    {
+        synchronized(fCalendar) {
+            fCalendar[0].setTime(dateInMonth);
+
+            int era = fCalendar[0].get(Calendar.ERA);
+            int year = fCalendar[0].get(Calendar.YEAR);
+            int month = fCalendar[0].get(Calendar.MONTH);
+
+            fCalendar[0].clear();
+            fCalendar[0].set(Calendar.ERA, era);
+            fCalendar[0].set(Calendar.YEAR, year);
+            fCalendar[0].set(Calendar.MONTH, month);
+            fCalendar[0].set(Calendar.DATE, 1);
+
+            return fCalendar[0].getTime();
+        }
+    }
+
+    private void calculate()
+    {
+        //
+        // As a workaround for JDK 1.1.3 and below, where Calendars and time
+        // zones are a bit goofy, always set my calendar's time zone to UTC.
+        // You would think I would want to do this in the "set" function above,
+        // but if I do that, the program hangs when this class is loaded,
+        // perhaps due to some sort of static initialization ordering problem.
+        // So I do it here instead.
+        //
+        fCalendar[0].setTimeZone(new SimpleTimeZone(0, "UTC"));
+
+        Calendar c = (Calendar)fCalendar[0].clone(); // Temporary copy
+
+        fStartOfMonth = startOfMonth(fStartOfMonth);
+
+        // Stash away a few useful constants for this calendar and display
+        minDay = c.getMinimum(Calendar.DAY_OF_WEEK);
+        daysInWeek = c.getMaximum(Calendar.DAY_OF_WEEK) - minDay + 1;
+
+        firstDayOfWeek = Calendar.getInstance(fDisplayLocale).getFirstDayOfWeek();
+
+        // Stash away a Date for the start of this month
+
+        // Find the day of week of the first day in this month
+        c.setTime(fStartOfMonth);
+        firstDayInMonth = c.get(Calendar.DAY_OF_WEEK);
+        int firstWeek = c.get(Calendar.WEEK_OF_MONTH);
+
+        // Now find the # of days in the month
+        c.roll(Calendar.DATE, false);
+        daysInMonth = c.get(Calendar.DATE);
+
+        // Finally, find the end of the month, i.e. the start of the next one
+        c.roll(Calendar.DATE, true);
+        c.add(Calendar.MONTH, 1);
+        c.getTime();        // JDK 1.1.2 bug workaround
+        c.add(Calendar.SECOND, -1);
+        Date endOfMonth = c.getTime();
+        endOfMonth = null;
+        int lastWeek = c.get(Calendar.WEEK_OF_MONTH);
+
+        // Calculate the number of full or partial weeks in this month.
+        numWeeks = lastWeek - firstWeek + 1;
+
+        dirty = false;
+    }
+
+    static final int XINSET = 4;
+    static final int YINSET = 2;
+
+    /*
+     * Convert from the day number within a month (1-based)
+     * to the cell coordinates on the calendar (0-based)
+     */
+    private void dateToCell(int date, Point pos)
+    {
+        int cell = (date + firstDayInMonth - firstDayOfWeek - minDay);
+        if (firstDayInMonth < firstDayOfWeek) {
+            cell += daysInWeek;
+        }
+
+        pos.x = cell % daysInWeek;
+        pos.y = cell / daysInWeek;
+    }
+    private Point dateToCell(int date) {
+        Point p = new Point(0,0);
+        dateToCell(date, p);
+        return p;
+    }
+
+    public void paint(Graphics g) {
+
+        if (dirty) {
+            calculate();
+        }
+
+        Point cellPos = new Point(0,0);     // Temporary variable
+        Dimension d = this.getSize();
+
+        g.setColor(Color.lightGray);
+        g.fillRect(0,0,d.width,d.height);
+
+        // Draw the day names at the top
+        g.setColor(Color.black);
+        g.setFont(DemoUtility.labelFont);
+        FontMetrics fm = g.getFontMetrics();
+        int labelHeight = fm.getHeight() + YINSET * 2;
+
+        int v = fm.getAscent() + YINSET;
+        for (int i = 0; i < daysInWeek; i++) {
+            int dayNum = (i + minDay + firstDayOfWeek - 2) % daysInWeek + 1;
+            String dayName = fSymbols[0].getWeekdays()[dayNum];
+
+
+            double h;
+            if (leftToRight) {
+                h = d.width*(i + 0.5) / daysInWeek;
+            } else {
+                h = d.width*(daysInWeek - i - 0.5) / daysInWeek;
+            }
+            h -= fm.stringWidth(dayName) / 2;
+
+            g.drawString(dayName, (int)h, v);
+        }
+
+        double cellHeight = (d.height - labelHeight - 1) / numWeeks;
+        double cellWidth = (double)(d.width - 1) / daysInWeek;
+
+        // Draw a white background in the part of the calendar
+        // that displays this month.
+        // First figure out how much of the first week should be shaded.
+        {
+            g.setColor(Color.white);
+            dateToCell(1, cellPos);
+            int width = (int)(cellPos.x*cellWidth);  // Width of unshaded area
+
+            if (leftToRight) {
+                g.fillRect((int)(width), labelHeight ,
+                           d.width - width, (int)cellHeight);
+            } else {
+                g.fillRect(0, labelHeight ,
+                           d.width - width, (int)cellHeight);
+            }
+
+            // All of the intermediate weeks get shaded completely
+            g.fillRect(0, (int)(labelHeight + cellHeight),
+                        d.width, (int)(cellHeight * (numWeeks - 2)));
+
+            // Now figure out the last week.
+            dateToCell(daysInMonth, cellPos);
+            width = (int)((cellPos.x+1)*cellWidth);  // Width of shaded area
+
+            if (leftToRight) {
+                g.fillRect(0, (int)(labelHeight + (numWeeks-1) * cellHeight),
+                           width, (int)cellHeight);
+            } else {
+                g.fillRect(d.width - width, (int)(labelHeight + (numWeeks-1) * cellHeight),
+                           width, (int)cellHeight);
+            }
+
+        }
+        // Draw the X/Y grid lines
+        g.setColor(Color.black);
+        for (int i = 0; i <= numWeeks; i++) {
+            int y = (int)(labelHeight + i * cellHeight);
+            g.drawLine(0, y, d.width - 1, y);
+        }
+        for (int i = 0; i <= daysInWeek; i++) {
+            int x = (int)(i * cellWidth);
+            g.drawLine(x, labelHeight, x, d.height - 1);
+        }
+
+        // Now loop through all of the days in the month, figure out where
+        // they go in the grid, and draw the day # for each one
+
+        // Figure out the date of the first cell in the calendar display
+        int cell = (1 + firstDayInMonth - firstDayOfWeek - minDay);
+        if (firstDayInMonth < firstDayOfWeek) {
+            cell += daysInWeek;
+        }
+
+        Calendar c = (Calendar)fCalendar[0].clone();
+        c.setTime(fStartOfMonth);
+        c.add(Calendar.DATE, -cell);
+
+        StringBuffer buffer = new StringBuffer();
+
+        for (int row = 0; row < numWeeks; row++) {
+            for (int col = 0; col < daysInWeek; col++) {
+
+                g.setFont(DemoUtility.numberFont);
+                g.setColor(Color.black);
+                fm = g.getFontMetrics();
+
+                int cellx;
+                if (leftToRight) {
+                    cellx = (int)((col) * cellWidth);
+                } else {
+                    cellx = (int)((daysInWeek - col - 1) * cellWidth);
+                }
+
+                int celly = (int)(row * cellHeight + labelHeight);
+
+                for (int i = 0; i < 2; i++) {
+                    fCalendar[i].setTime(c.getTime());
+
+                    int date = fCalendar[i].get(Calendar.DATE);
+                    buffer.setLength(0);
+                    buffer.append(date);
+                    String dayNum = buffer.toString();
+
+                    int x;
+
+                    if (leftToRight) {
+                        x = cellx + (int)cellWidth - XINSET - fm.stringWidth(dayNum);
+                    } else {
+                        x = cellx + XINSET;
+                    }
+                    int y = celly + + fm.getAscent() + YINSET + i * fm.getHeight();
+
+                    if (fColor[i] != null) {
+                        g.setColor(fColor[i]);
+                    }
+                    g.drawString(dayNum, x, y);
+
+                    if (date == 1 || row == 0 && col == 0) {
+                        g.setFont(DemoUtility.numberFont);
+                        String month = fSymbols[i].getMonths()[
+                                            fCalendar[i].get(Calendar.MONTH)];
+
+                        if (leftToRight) {
+                            x = cellx + XINSET;
+                        } else {
+                            x = cellx + (int)cellWidth - XINSET - fm.stringWidth(month);
+                        }
+                        g.drawString(month, x, y);
+                    }
+                }
+
+                c.add(Calendar.DATE, 1);
+            }
+        }
+    }
+
+    // Important state variables
+    private Calendar[]          fCalendar = new Calendar[4];
+    private Color[]             fColor = new Color[4];
+
+    private Locale              fDisplayLocale;
+    private DateFormatSymbols[] fSymbols = new DateFormatSymbols[4];
+
+    private Date                fStartOfMonth = new Date();     // 00:00:00 on first day of month
+
+    // Cached calculations to make drawing faster.
+    private transient int       minDay;           // Minimum legal day #
+    private transient int       daysInWeek;       // # of days in a week
+    private transient int       firstDayOfWeek;   // First day to display in week
+    private transient int       numWeeks;         // # full or partial weeks in month
+    private transient int       daysInMonth;      // # days in this month
+    private transient int       firstDayInMonth;  // Day of week of first day in month
+    private transient boolean   leftToRight;
+
+    private transient boolean dirty = true;
+}
diff --git a/src/com/ibm/demo/calendar/package.html b/src/com/ibm/demo/calendar/package.html
new file mode 100755
index 0000000..5275b89
--- /dev/null
+++ b/src/com/ibm/demo/calendar/package.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--  Copyright (C) 2000, International Business Machines Corporation and
+  others. All Rights Reserved.
+
+  $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/calendar/Attic/package.html,v $
+  $Revision: 1.1 $
+  $Date: 2000/03/15 06:28:48 $
+-->
+</head>
+<body bgcolor="white">
+Calendar demo applications including date/time arithmetic.
+</body>
+</html>
\ No newline at end of file
diff --git a/src/com/ibm/demo/holiday/HolidayBorderPanel.java b/src/com/ibm/demo/holiday/HolidayBorderPanel.java
new file mode 100755
index 0000000..4bc478b
--- /dev/null
+++ b/src/com/ibm/demo/holiday/HolidayBorderPanel.java
@@ -0,0 +1,551 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/holiday/Attic/HolidayBorderPanel.java,v $ 
+ * $Date: 2001/10/30 02:42:50 $ 
+ * $Revision: 1.4 $
+ *
+ *****************************************************************************************
+ */
+package com.ibm.demo.holiday;
+
+import com.ibm.demo.*;
+import java.awt.*;
+
+/**
+ * Various graphical borders. The border itself is a Panel so that it can
+ * contain other Components (i.e. it borders something). You use the
+ * HolidayBorderPanel like any other Panel: you set the layout that you prefer and
+ * add Components to it. Beware that a null layout does not obey the insets
+ * of the panel so if you use null layouts, adjust your measurements to
+ * handle the border by calling insets().
+ *
+ * @author  Andy Clark, Taligent Inc.
+ * @version 1.0
+ */
+public class HolidayBorderPanel extends Panel {
+    // Constants
+
+    /** Solid border. */
+    public final static int SOLID = 0;
+    /** A raised border. */
+    public final static int RAISED = 1;
+    /** A lowered border. */
+    public final static int LOWERED = 2;
+    /** An etched in border. */
+    public final static int IN = 3;
+    /** An etched out border. */
+    public final static int OUT = 4;
+
+    /** Left alignment. */
+    public final static int LEFT = 0;
+    /** Center alignment. */
+    public final static int CENTER = 1;
+    /** Right alignment. */
+    public final static int RIGHT = 2;
+
+    /** Default style (IN). */
+    public final static int DEFAULT_STYLE = IN;
+    /** Default thickness (10). */
+    public final static int DEFAULT_THICKNESS = 10;
+    /** Default thickness for solid borders (4). */
+    public final static int DEFAULT_SOLID_THICKNESS = 4;
+    /** Default thickness for raised borders (2). */
+    public final static int DEFAULT_RAISED_THICKNESS = 2;
+    /** Default thickness for lowered borders (2). */
+    public final static int DEFAULT_LOWERED_THICKNESS = 2;
+    /** Default thickness for etched-in borders (10). */
+    public final static int DEFAULT_IN_THICKNESS = 10;
+    /** Default thickness for etched-out borders (10). */
+    public final static int DEFAULT_OUT_THICKNESS = 10;
+    /** Default gap between border and contained component (5). */
+    public final static int DEFAULT_GAP = 5;
+    /** Default color (black). Applies to SOLID and etched borders. */
+    public final static Color DEFAULT_COLOR = Color.black;
+
+    /** Default font (TimesRoman,PLAIN,14). Only applies to etched borders. */
+    public final static Font DEFAULT_FONT = new Font("TimesRoman", Font.PLAIN, 14);
+    /** Default alignment (LEFT). Only applies to etched borders. */
+    public final static int DEFAULT_ALIGNMENT = LEFT;
+
+    // Data
+    private int style;
+    private int thickness;
+    private int gap;
+    private Color color;
+
+    private Font font;
+    private String text;
+    private int alignment;
+
+    /**
+     * Constructor. Makes default border.
+     */
+    public HolidayBorderPanel() {
+
+        // initialize data
+        style       = DEFAULT_STYLE;
+        thickness   = DEFAULT_THICKNESS;
+        gap         = DEFAULT_GAP;
+        color       = DEFAULT_COLOR;
+
+        text        = null;
+        font        = DEFAULT_FONT;
+        alignment   = DEFAULT_ALIGNMENT;
+
+        }
+
+    /**
+     * Constructor. Makes an etched IN border with given text caption.
+     *
+     * @param text  Text caption
+     */
+    public HolidayBorderPanel(String text) {
+        this();
+
+        style = IN;
+        this.text = text;
+        }
+
+    /**
+     * Constructor. Makes SOLID border with color and thickness given.
+     *
+     * @param color     The color for the border.
+     * @param thickness The thickness of the border.
+     */
+    public HolidayBorderPanel(Color color, int thickness) {
+        this();
+
+        style = SOLID;
+        this.color = color;
+        this.thickness = thickness;
+        }
+
+    /**
+     * Constructor. Makes a border of the given style with the default
+     * thickness for that style.
+     *
+     * @param style The style for this border.
+     */
+    public HolidayBorderPanel(int style) {
+        this();
+
+        // set thickness appropriate to this style
+        int thickness;
+        switch (style) {
+            case SOLID: thickness = DEFAULT_SOLID_THICKNESS; break;
+            case RAISED: thickness = DEFAULT_RAISED_THICKNESS; break;
+            case LOWERED: thickness = DEFAULT_LOWERED_THICKNESS; break;
+            case IN: thickness = DEFAULT_IN_THICKNESS; break;
+            case OUT: thickness = DEFAULT_OUT_THICKNESS; break;
+            default:
+                thickness = DEFAULT_THICKNESS;
+            }
+
+        this.style = style;
+        this.thickness = thickness;
+        }
+
+    /**
+     * Constructor. Makes border with given style and thickness.
+     *
+     * @param style     The style for this border.
+     * @param thickness The thickness for this border.
+     */
+    public HolidayBorderPanel(int style, int thickness) {
+        this();
+
+        this.style = style;
+        this.thickness = thickness;
+        }
+
+    /**
+     * Returns the insets of this panel..
+     */
+    public Insets getInsets() {
+        int adjustment = 0;
+
+        // adjust for text string
+        if (style == IN || style == OUT) {
+            if (text != null && text.length() > 0) {
+                try {
+                    // set font and get info
+                    int height = getGraphics().getFontMetrics(font).getHeight();
+                    if (height > thickness)
+                        adjustment = height - thickness;
+                    }
+                catch (Exception e) {
+                    // nothing: just in case there is no graphics context
+                    //   at the beginning.
+                    System.out.print("");
+                    }
+                }
+            }
+
+        // return appropriate insets
+        int dist = thickness + gap;
+        return new Insets(dist + adjustment, dist, dist, dist);
+        }
+
+    /**
+     * Sets the style of the border
+     *
+     * @param style The new style.
+     */
+    public HolidayBorderPanel setStyle(int style) {
+
+        // set the style and re-layout the panel
+        this.style = style;
+        doLayout();
+        repaint();
+
+        return this;
+        }
+
+    /**
+     * Gets the style of the border
+     */
+    public int getStyle() {
+
+        return style;
+        }
+
+    /**
+     * Sets the thickness of the border.
+     *
+     * @param thickness The new thickness
+     */
+    public HolidayBorderPanel setThickness(int thickness) {
+
+        if (thickness > 0) {
+            this.thickness = thickness;
+            doLayout();
+            repaint();
+            }
+
+        return this;
+        }
+
+    /**
+     * Gets the thickness of the border.
+     */
+    public int getThickness() {
+
+        return thickness;
+        }
+
+    /**
+     * Sets the gap between the border and the contained Component.
+     *
+     * @param gap The new gap, in pixels.
+     */
+    public HolidayBorderPanel setGap(int gap) {
+
+        if (gap > -1) {
+            this.gap = gap;
+            doLayout();
+            repaint();
+            }
+
+        return this;
+        }
+
+    /**
+     * Gets the gap between the border and the contained Component.
+     */
+    public int getGap() {
+
+        return gap;
+        }
+
+    /**
+     * Sets the current color for SOLID borders and the caption text
+     * color for etched borders.
+     *
+     * @param color The new color.
+     */
+    public HolidayBorderPanel setColor(Color color) {
+
+        this.color = color;
+        if (style == SOLID || style == IN || style == OUT)
+            repaint();
+
+        return this;
+        }
+
+    /**
+     * Gets the current color for SOLID borders and the caption
+     * text color for etched borders.
+     */
+    public Color getColor() {
+
+        return color;
+        }
+
+    /**
+     * Sets the font. Only applies to etched borders.
+     */
+    public HolidayBorderPanel setTextFont(Font font) {
+
+        // set font
+        if (font != null) {
+            this.font = font;
+            if (style == IN || style == OUT) {
+                doLayout();
+                repaint();
+                }
+            }
+
+        return this;
+        }
+
+    /**
+     * Gets the font of the text. Only applies to etched borders.
+     */
+    public Font getTextFont() {
+
+        return font;
+        }
+
+    /**
+     * Sets the text. Only applies to etched borders.
+     *
+     * @param text  The new text.
+     */
+    public HolidayBorderPanel setText(String text) {
+
+        this.text = text;
+        if (style == IN || style == OUT) {
+            doLayout();
+            repaint();
+            }
+
+        return this;
+        }
+
+    /**
+     * Gets the text. Only applies to etched borders.
+     */
+    public String getText() {
+
+        return text;
+        }
+
+    /**
+     * Sets the text alignment. Only applies to etched borders.
+     *
+     * @param alignment The new alignment.
+     */
+    public HolidayBorderPanel setAlignment(int alignment) {
+
+        this.alignment = alignment;
+        if (style == IN || style == OUT) {
+            doLayout();
+            repaint();
+            }
+
+        return this;
+        }
+
+    /**
+     * Gets the text alignment.
+     */
+    public int getAlignment() {
+
+        return alignment;
+        }
+
+    /**
+     * Repaints the border.
+     *
+     * @param g The graphics context.
+     */
+    public void paint(Graphics g) {
+
+        // get current dimensions
+        Dimension size = getSize();
+        int width = size.width;
+        int height = size.height;
+
+        // set colors
+        Color light = getBackground().brighter().brighter().brighter();
+        Color dark = getBackground().darker().darker().darker();
+
+        // Draw border
+        switch (style) {
+            case RAISED:    // 3D Border (in or out)
+            case LOWERED:
+                Color topleft = null;
+                Color bottomright = null;
+
+                // set colors
+                if (style == RAISED) {
+                    topleft = light;
+                    bottomright = dark;
+                    }
+                else {
+                    topleft = dark;
+                    bottomright = light;
+                    }
+
+                // draw border
+                g.setColor(topleft);
+                for (int i = 0; i < thickness; i++) {
+                    g.drawLine(i, i, width - i - 2, i);
+                    g.drawLine(i, i + 1, i, height - i - 1);
+                    }
+                g.setColor(bottomright);
+                for (int i = 0; i < thickness; i++) {
+                    g.drawLine(i + 1, height - i - 1, width - i - 1, height - i - 1);
+                    g.drawLine(width - i - 1, i, width - i - 1, height - i - 2);
+                    }
+                break;
+
+            case IN:    // Etched Border (in or out)
+            case OUT:
+                int adjust1 = 0;
+                int adjust2 = 0;
+
+                // set font and get info
+                Font oldfont = g.getFont();
+                g.setFont(font);
+                FontMetrics fm = g.getFontMetrics();
+                int ascent = fm.getAscent();
+
+                // set adjustment
+                if (style == IN)
+                    adjust1 = 1;
+                else
+                    adjust2 = 1;
+
+                // Calculate adjustment for text
+                int adjustment = 0;
+                if (text != null && text.length() > 0) {
+                    if (ascent > thickness)
+                        adjustment = (ascent - thickness) / 2;
+                    }
+
+                // The adjustment is there so that we always draw the
+                // light rectangle first. Otherwise, your eye picks up
+                // the discrepancy where the light rect. passes over
+                // the darker rect.
+                int x = thickness / 2;
+                int y = thickness / 2 + adjustment;
+                int w = width - thickness - 1;
+                int h = height - thickness - 1 - adjustment;
+
+                // draw rectangles
+                g.setColor(light);
+                g.drawRect(x + adjust1, y + adjust1, w, h);
+                g.setColor(dark);
+                g.drawRect(x + adjust2, y + adjust2, w, h);
+
+                // draw text, if applicable
+                if (text != null && text.length() > 0) {
+                    // calculate drawing area
+                    int fontheight = fm.getHeight();
+                    int strwidth = fm.stringWidth(text);
+
+                    int textwidth = width - 2 * (thickness + 5);
+                    if (strwidth > textwidth)
+                        strwidth = textwidth;
+
+                    // calculate offset for alignment
+                    int offset;
+                    switch (alignment) {
+                        case CENTER:
+                            offset = (width - strwidth) / 2;
+                            break;
+                        case RIGHT:
+                            offset = width - strwidth - thickness - 5;
+                            break;
+                        case LEFT:
+                        default: // assume left alignment if invalid
+                            offset = thickness + 5;
+                            break;
+                        }
+
+                    // clear drawing area and set clipping region
+                    g.clearRect(offset - 5, 0, strwidth  + 10, fontheight);
+                    g.clipRect(offset, 0, strwidth, fontheight);
+
+                    // draw text
+                    g.setColor(color);
+                    g.drawString(text, offset, ascent);
+
+                    // restore old clipping area
+                    g.clipRect(0, 0, width, height);
+                    }
+
+                g.setFont(oldfont);
+                break;
+
+            case SOLID:
+            default: // assume SOLID
+                g.setColor(color);
+                for (int i = 0; i < thickness; i++)
+                    g.drawRect(i, i, width - 2 * i - 1, height - 2 * i - 1);
+            }
+
+        }
+
+    /**
+     * Returns the settings of this HolidayBorderPanel instance as a string.
+     */
+    public String toString() {
+        StringBuffer str = new StringBuffer("HolidayBorderPanel[");
+
+        // style
+        str.append("style=");
+        switch (style) {
+            case SOLID: str.append("SOLID"); break;
+            case RAISED: str.append("RAISED"); break;
+            case LOWERED: str.append("LOWERED"); break;
+            case IN: str.append("IN"); break;
+            case OUT: str.append("OUT"); break;
+            default: str.append("unknown");
+            }
+        str.append(",");
+
+        // thickness
+        str.append("thickness=");
+        str.append(thickness);
+        str.append(",");
+
+        // gap
+        str.append("gap=");
+        str.append(gap);
+        str.append(",");
+
+        // color
+        str.append(color);
+        str.append(",");
+
+        // font
+        str.append(font);
+        str.append(",");
+
+        // text
+        str.append("text=");
+        str.append(text);
+        str.append(",");
+
+        // alignment
+        str.append("alignment=");
+        switch (alignment) {
+            case LEFT: str.append("LEFT"); break;
+            case CENTER: str.append("CENTER"); break;
+            case RIGHT: str.append("RIGHT"); break;
+            default: str.append("unknown");
+            }
+
+        str.append("]");
+
+        return str.toString();
+        }
+
+    }
+
diff --git a/src/com/ibm/demo/holiday/HolidayCalendarDemo.java b/src/com/ibm/demo/holiday/HolidayCalendarDemo.java
new file mode 100755
index 0000000..bb7f390
--- /dev/null
+++ b/src/com/ibm/demo/holiday/HolidayCalendarDemo.java
@@ -0,0 +1,721 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/holiday/Attic/HolidayCalendarDemo.java,v $ 
+ * $Date: 2001/10/30 02:42:49 $ 
+ * $Revision: 1.7 $
+ *
+ *****************************************************************************************
+ */
+
+package com.ibm.demo.holiday;
+
+import com.ibm.demo.*;
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.*;
+//import java.util.*;
+import java.net.*;
+import java.io.*;
+
+//import java.text.SimpleDateFormat;
+import com.ibm.text.SimpleDateFormat;
+import java.text.DateFormatSymbols;
+//import java.util.SimpleTimeZone;
+import com.ibm.util.SimpleTimeZone;
+import java.util.Locale;
+import java.util.Vector;
+import java.util.Date;
+
+import com.ibm.util.*;
+
+/**
+ * CalendarDemo demonstrates how Calendar works.
+ */
+public class HolidayCalendarDemo extends DemoApplet 
+{
+    /**
+     * The main function which defines the behavior of the CalendarDemo
+     * applet when an applet is started.
+     */
+    public static void main(String argv[]) {
+
+        new HolidayCalendarDemo().showDemo();
+    }
+
+    /* This creates a CalendarFrame for the demo applet. */
+    public Frame createDemoFrame(DemoApplet applet) {
+        return new CalendarFrame(applet);
+    }
+
+	/**
+	* A Frame is a top-level window with a title. The default layout for a frame
+	* is BorderLayout.  The CalendarFrame class defines the window layout of
+	* CalendarDemo.
+	*/
+	private static class CalendarFrame extends Frame implements ActionListener,
+                                                                ItemListener
+	{
+    	private static final String creditString = "";
+
+    	private static final boolean DEBUG = false;
+
+    	private Locale curLocale = Locale.US;
+
+    	private DemoApplet applet;
+
+    	private static final Locale[] calendars = {
+        	//new Locale("de","AT"),
+        	Locale.CANADA,
+        	Locale.CANADA_FRENCH,
+        	Locale.FRANCE,
+        	Locale.GERMANY,
+        	new Locale("iw","IL"),
+        	new Locale("el","GR"),
+        	//new Locale("es","MX"),
+        	Locale.UK,
+        	Locale.US,
+    	};
+    	private static final Locale[] displays = {
+        	Locale.CANADA,
+        	Locale.UK,
+        	Locale.US,
+        	Locale.FRANCE,
+        	Locale.CANADA_FRENCH,
+        	//new Locale("de","AT"),
+        	Locale.GERMAN,
+        	new Locale("el","GR"),
+        	//new Locale("iw","IL"),
+        	new Locale("es","MX"),
+    	};
+
+    	/**
+    	* Constructs a new CalendarFrame that is initially invisible.
+    	*/
+    	public CalendarFrame(DemoApplet applet)
+    	{
+        	super("Calendar Demo");
+        	this.applet = applet;
+        	init();
+        	start();
+        	enableEvents(WindowEvent.WINDOW_CLOSING);
+    	}
+
+    	/**
+    	* Initializes the applet. You never need to call this directly, it
+    	* is called automatically by the system once the applet is created.
+    	*/
+    	public void init()
+    	{
+        	// Get G7 locales only for demo purpose. To get all the locales
+        	// supported, switch to calling Calendar.getAvailableLocales().
+        	// commented
+        	locales = displays;
+
+        	buildGUI();
+    	}
+
+    	//------------------------------------------------------------
+    	// package private
+    	//------------------------------------------------------------
+    	void addWithFont(Container container, Component foo, Font font) {
+        	if (font != null)
+            	foo.setFont(font);
+        	container.add(foo);
+    	}
+
+    	/**
+    	* Called to start the applet. You never need to call this method
+    	* directly, it is called when the applet's document is visited.
+    	*/
+    	public void start()
+    	{
+        	// do nothing
+    	}
+
+    	private Choice          localeMenu;
+    	private Choice          displayMenu;
+    	private Locale[]        locales;
+
+    	private Label           monthLabel;
+    	private Button          prevYear;
+    	private Button          prevMonth;
+    	private Button          gotoToday;
+    	private Button          nextMonth;
+    	private Button          nextYear;
+    	private CalendarPanel   calendarPanel;
+
+    	private static final Locale kFirstLocale = Locale.US;
+
+    	private static void add(Container container, Component component,
+                            	GridBagLayout g, GridBagConstraints c)
+    	{
+        	g.setConstraints(component, c);
+        	container.add(component);
+    	}
+
+    	public void buildGUI()
+    	{
+        	setBackground(DemoUtility.bgColor);
+        	setLayout(new BorderLayout(10,10));
+
+        	// Label for the demo's title
+        	Label titleLabel = new Label("Calendar Demo", Label.CENTER);
+        	titleLabel.setFont(DemoUtility.titleFont);
+
+        	// Label for the current month name
+        	monthLabel = new Label("", Label.LEFT);
+        	monthLabel.setFont(new Font(DemoUtility.titleFont.getName(),
+                                    	DemoUtility.titleFont.getStyle(),
+                                    	(DemoUtility.titleFont.getSize() * 3)/2));
+
+        	// Make the locale popup menus
+        	localeMenu= new Choice();
+        	localeMenu.addItemListener(this);
+        	int selectMe = 0;
+        	
+        	for (int i = 0; i < calendars.length; i++) {
+            	if (i > 0 &&
+                    	calendars[i].getCountry().equals(calendars[i-1].getCountry()) ||
+                	i < calendars.length - 1 &&
+                    	calendars[i].getCountry().equals(calendars[i+1].getCountry()))
+            	{
+                	localeMenu.addItem(calendars[i].getDisplayCountry() + " (" +
+                                	calendars[i].getDisplayLanguage() + ")");
+            	} else {
+                	localeMenu.addItem( calendars[i].getDisplayCountry() );
+            	}
+            	
+            	if (calendars[i].equals(kFirstLocale)) {
+                	selectMe = i;
+            	}
+        	}
+        	
+        	localeMenu.setBackground(DemoUtility.choiceColor);
+        	localeMenu.select(selectMe);
+
+        	displayMenu = new Choice();
+        	displayMenu.addItemListener(this);
+        	
+        	selectMe = 0;
+        	for (int i = 0; i < locales.length; i++) {
+            	if (i > 0 &&
+                    	locales[i].getLanguage().equals(locales[i-1].getLanguage()) ||
+                	i < locales.length - 1 &&
+                    	locales[i].getLanguage().equals(locales[i+1].getLanguage()))
+            	{
+                	displayMenu.addItem( locales[i].getDisplayName() );
+            	} else {
+                	displayMenu.addItem( locales[i].getDisplayLanguage());
+            	}
+            	
+            	if (locales[i].equals(kFirstLocale)) {
+            	    selectMe = i;
+            	}
+        	}
+        	
+        	displayMenu.setBackground(DemoUtility.choiceColor);
+        	displayMenu.select(selectMe);
+
+        	// Make all the next/previous/today buttons
+        	prevYear = new Button("<<");
+        	prevYear.addActionListener(this);
+        	prevMonth = new Button("<");
+        	prevMonth.addActionListener(this);
+        	gotoToday = new Button("Today");
+        	gotoToday.addActionListener(this);
+        	nextMonth = new Button(">");
+        	nextMonth.addActionListener(this);
+        	nextYear = new Button(">>");
+        	nextYear.addActionListener(this);
+
+        	// The month name and the control buttons are bunched together
+        	Panel monthPanel = new Panel();
+        	{
+            	GridBagLayout g = new GridBagLayout();
+            	GridBagConstraints c = new GridBagConstraints();
+            	monthPanel.setLayout(g);
+
+            	c.weightx = 1;
+            	c.weighty = 1;
+
+            	c.gridwidth = 1;
+            	c.fill = GridBagConstraints.HORIZONTAL;
+            	c.gridwidth = GridBagConstraints.REMAINDER;
+            	add(monthPanel, monthLabel, g, c);
+
+            	c.gridwidth = 1;
+            	add(monthPanel, prevYear, g, c);
+            	add(monthPanel, prevMonth, g, c);
+            	add(monthPanel, gotoToday, g, c);
+            	add(monthPanel, nextMonth, g, c);
+            	c.gridwidth = GridBagConstraints.REMAINDER;
+            	add(monthPanel, nextYear, g, c);
+        	}
+
+        	// Stick the menu and buttons in a little "control panel"
+        	Panel menuPanel = new Panel();
+        	{
+            	GridBagLayout g = new GridBagLayout();
+            	GridBagConstraints c = new GridBagConstraints();
+            	menuPanel.setLayout(g);
+
+            	c.weightx = 1;
+            	c.weighty = 1;
+
+            	c.fill = GridBagConstraints.HORIZONTAL;
+
+            	c.gridwidth = GridBagConstraints.RELATIVE;
+            	Label l1 = new Label("Holidays");
+            	l1.setFont(DemoUtility.labelFont);
+            	add(menuPanel, l1, g, c);
+
+            	c.gridwidth = GridBagConstraints.REMAINDER;
+            	add(menuPanel, localeMenu, g, c);
+
+            	c.gridwidth = GridBagConstraints.RELATIVE;
+            	Label l2 = new Label("Display:");
+            	l2.setFont(DemoUtility.labelFont);
+            	add(menuPanel, l2, g, c);
+
+            	c.gridwidth = GridBagConstraints.REMAINDER;
+            	add(menuPanel, displayMenu, g, c);
+        	}
+
+        	// The title, buttons, etc. go in a panel at the top of the window
+        	Panel topPanel = new Panel();
+        	{
+            	topPanel.setLayout(new BorderLayout());
+
+            	//topPanel.add("North", titleLabel);
+            	topPanel.add("Center", monthPanel);
+            	topPanel.add("East", menuPanel);
+        	}
+        	add("North", topPanel);
+
+        	// The copyright notice goes at the bottom of the window
+        	Label copyright = new Label(DemoUtility.copyright1, Label.LEFT);
+        	copyright.setFont(DemoUtility.creditFont);
+        	add("South", copyright);
+
+        	// Now create the big calendar panel and stick it in the middle
+        	calendarPanel = new CalendarPanel( kFirstLocale );
+        	add("Center", calendarPanel);
+
+        	updateMonthName();
+    	}
+
+    	private void updateMonthName()
+    	{
+        	SimpleDateFormat f = new SimpleDateFormat("MMMM yyyyy",
+                                                    	calendarPanel.getDisplayLocale());
+        	f.setCalendar(calendarPanel.getCalendar());
+        	f.setTimeZone(new SimpleTimeZone(0, "UTC"));        // JDK 1.1.2 workaround
+        	monthLabel.setText( f.format( calendarPanel.firstOfMonth() ));
+    	}
+    	
+    	/**
+    	* Handles the event. Returns true if the event is handled and should not
+    	* be passed to the parent of this component. The default event handler
+    	* calls some helper methods to make life easier on the programmer.
+    	*/
+    	public void actionPerformed(ActionEvent e)
+    	{
+    	    Object obj = e.getSource();
+    	    
+    	    // *** Button events are handled here.
+        	if (obj instanceof Button) {
+            	if (obj == nextMonth) {
+                	calendarPanel.add(Calendar.MONTH, +1);
+            	}
+            	else
+            	if (obj == prevMonth) {
+                	calendarPanel.add(Calendar.MONTH, -1);
+            	}
+            	else
+            	if (obj == prevYear) {
+                	calendarPanel.add(Calendar.YEAR, -1);
+            	}
+            	else
+            	if (obj == nextYear) {
+                	calendarPanel.add(Calendar.YEAR, +1);
+            	}
+            	else
+            	if (obj == gotoToday) {
+                	calendarPanel.set( new Date() );
+            	}
+            	updateMonthName();
+        	}
+    	}
+    	
+    	public void itemStateChanged(ItemEvent e)
+        {
+            Object obj = e.getSource();
+            if (obj == localeMenu) {
+            	calendarPanel.setCalendarLocale(calendars[localeMenu.getSelectedIndex()]);
+            	updateMonthName();
+        	}
+        	else 
+        	    if (obj == displayMenu) {
+            	    calendarPanel.setDisplayLocale(locales[displayMenu.getSelectedIndex()]);
+            	    updateMonthName();
+            	}
+        }
+        
+        /**
+    	* Print out the error message while debugging this program.
+    	*/
+    	public void errorText(String s)
+    	{
+        	if (DEBUG)
+        	{
+            	System.out.println(s);
+        	}
+    	}
+    	
+    	protected void processWindowEvent(WindowEvent e)
+        {
+            System.out.println("event " + e);
+            if (e.getID() == WindowEvent.WINDOW_CLOSING) {
+            	this.hide();
+            	this.dispose();
+
+            	if (applet != null) {
+            	    applet.demoClosed();
+            	} else {
+                    System.exit(0);
+            	}
+        	}
+        }
+	}
+
+
+	private static class CalendarPanel extends Canvas {
+
+    	public CalendarPanel( Locale locale ) {
+        	set(locale, locale, new Date());
+    	}
+
+    	public void setCalendarLocale(Locale locale) {
+        	set(locale, fDisplayLocale, fCalendar.getTime());
+    	}
+
+    	public void setDisplayLocale(Locale locale) {
+        	set(fCalendarLocale, locale, fCalendar.getTime());
+    	}
+
+    	public void set(Date date) {
+        	set(fCalendarLocale, fDisplayLocale, date);
+    	}
+
+    	public void set(Locale loc, Locale display, Date date)
+    	{
+        	if (fCalendarLocale == null || !loc.equals(fCalendarLocale)) {
+            	fCalendarLocale = loc;
+            	fCalendar = Calendar.getInstance(fCalendarLocale);
+            	fAllHolidays = Holiday.getHolidays(fCalendarLocale);
+        	}
+        	if (fDisplayLocale == null || !display.equals(fDisplayLocale)) {
+            	fDisplayLocale = display;
+            	fSymbols = new DateFormatSymbols(fDisplayLocale);
+        	}
+
+        	fStartOfMonth = date;
+
+        	dirty = true;
+        	repaint();
+    	}
+
+    	public void add(int field, int delta)
+    	{
+        	synchronized(fCalendar) {
+            	fCalendar.setTime(fStartOfMonth);
+            	fCalendar.add(field, delta);
+            	fStartOfMonth = fCalendar.getTime();
+        	}
+        	dirty = true;
+        	repaint();
+    	}
+
+    	public com.ibm.util.Calendar getCalendar() {
+        	return fCalendar;
+    	}
+
+    	public Locale getCalendarLocale() {
+        	return fCalendarLocale;
+    	}
+
+    	public Locale getDisplayLocale() {
+        	return fDisplayLocale;
+    	}
+
+
+    	public Date firstOfMonth() {
+        	return fStartOfMonth;
+    	}
+
+    	private Date startOfMonth(Date dateInMonth)
+    	{
+        	synchronized(fCalendar) {
+            	fCalendar.setTime(dateInMonth);             // TODO: synchronization
+
+            	int era = fCalendar.get(Calendar.ERA);
+            	int year = fCalendar.get(Calendar.YEAR);
+            	int month = fCalendar.get(Calendar.MONTH);
+
+            	fCalendar.clear();
+            	fCalendar.set(Calendar.ERA, era);
+            	fCalendar.set(Calendar.YEAR, year);
+            	fCalendar.set(Calendar.MONTH, month);
+            	fCalendar.set(Calendar.DATE, 1);
+
+            	return fCalendar.getTime();
+        	}
+    	}
+
+    	private void calculate()
+    	{
+        	//
+        	// As a workaround for JDK 1.1.3 and below, where Calendars and time
+        	// zones are a bit goofy, always set my calendar's time zone to UTC.
+        	// You would think I would want to do this in the "set" function above,
+        	// but if I do that, the program hangs when this class is loaded,
+        	// perhaps due to some sort of static initialization ordering problem.
+        	// So I do it here instead.
+        	//
+        	fCalendar.setTimeZone(new SimpleTimeZone(0, "UTC"));
+
+        	Calendar c = (Calendar)fCalendar.clone(); // Temporary copy
+
+        	fStartOfMonth = startOfMonth(fStartOfMonth);
+
+        	// Stash away a few useful constants for this calendar and display
+        	minDay = c.getMinimum(Calendar.DAY_OF_WEEK);
+        	daysInWeek = c.getMaximum(Calendar.DAY_OF_WEEK) - minDay + 1;
+
+        	firstDayOfWeek = Calendar.getInstance(fDisplayLocale).getFirstDayOfWeek();
+
+        	// Stash away a Date for the start of this month
+
+        	// Find the day of week of the first day in this month
+        	c.setTime(fStartOfMonth);
+        	firstDayInMonth = c.get(Calendar.DAY_OF_WEEK);
+
+        	// Now find the # of days in the month
+        	c.roll(Calendar.DATE, false);
+        	daysInMonth = c.get(Calendar.DATE);
+
+        	// Finally, find the end of the month, i.e. the start of the next one
+        	c.roll(Calendar.DATE, true);
+        	c.add(Calendar.MONTH, 1);
+        	c.getTime();        // JDK 1.1.2 bug workaround
+        	c.add(Calendar.SECOND, -1);
+        	Date endOfMonth = c.getTime();
+
+        	//
+        	// Calculate the number of full or partial weeks in this month.
+        	// To do this I can just reuse the code that calculates which
+        	// calendar cell contains a given date.
+        	//
+        	numWeeks = dateToCell(daysInMonth).y - dateToCell(1).y + 1;
+
+        	// Remember which holidays fall on which days in this month,
+        	// to save the trouble of having to do it later
+        	fHolidays.setSize(0);
+
+        	for (int h = 0; h < fAllHolidays.length; h++)
+        	{
+            	Date d = fStartOfMonth;
+            	while ( (d = fAllHolidays[h].firstBetween(d, endOfMonth) ) != null)
+            	{
+                	c.setTime(d);
+                	fHolidays.addElement( new HolidayInfo(c.get(Calendar.DATE),
+                                        	fAllHolidays[h],
+                                        	fAllHolidays[h].getDisplayName(fDisplayLocale) ));
+
+                	d.setTime( d.getTime() + 1000 );    // "d++"
+            	}
+        	}
+        	dirty = false;
+    	}
+
+    	static final int INSET = 2;
+
+    	/*
+    	* Convert from the day number within a month (1-based)
+    	* to the cell coordinates on the calendar (0-based)
+    	*/
+    	private void dateToCell(int date, Point pos)
+    	{
+        	int cell = (date + firstDayInMonth - firstDayOfWeek - minDay);
+        	if (firstDayInMonth < firstDayOfWeek) {
+            	cell += daysInWeek;
+        	}
+
+        	pos.x = cell % daysInWeek;
+        	pos.y = cell / daysInWeek;
+    	}
+    	private Point dateToCell(int date) {
+        	Point p = new Point(0,0);
+        	dateToCell(date, p);
+        	return p;
+    	}
+
+    	public void paint(Graphics g) {
+
+        	if (dirty) {
+            	calculate();
+        	}
+
+        	Point cellPos = new Point(0,0);     // Temporary variable
+        	Dimension d = getSize();
+
+        	g.setColor(DemoUtility.bgColor);
+        	g.fillRect(0,0,d.width,d.height);
+
+        	// Draw the day names at the top
+        	g.setColor(Color.black);
+        	g.setFont(DemoUtility.labelFont);
+        	FontMetrics fm = g.getFontMetrics();
+        	int labelHeight = fm.getHeight() + INSET * 2;
+
+        	int v = fm.getAscent() + INSET;
+        	for (int i = 0; i < daysInWeek; i++) {
+            	int dayNum = (i + minDay + firstDayOfWeek - 2) % daysInWeek + 1;
+            	String dayName = fSymbols.getWeekdays()[dayNum];
+
+            	int h = (int) (d.width * (i + 0.5)) / daysInWeek;
+            	h -= fm.stringWidth(dayName) / 2;
+
+            	g.drawString(dayName, h, v);
+        	}
+
+        	double cellHeight = (d.height - labelHeight - 1) / numWeeks;
+        	double cellWidth = (double)(d.width - 1) / daysInWeek;
+
+        	// Draw a white background in the part of the calendar
+        	// that displays this month.
+        	// First figure out how much of the first week should be shaded.
+        	{
+            	g.setColor(Color.white);
+            	dateToCell(1, cellPos);
+            	int width = (int)(cellPos.x*cellWidth);  // Width of unshaded area
+
+            	g.fillRect((int)(width), labelHeight ,
+                    	(int)(d.width - width), (int)cellHeight);
+
+            	// All of the intermediate weeks get shaded completely
+            	g.fillRect(0, (int)(labelHeight + cellHeight),
+                        	d.width, (int)(cellHeight * (numWeeks - 2)));
+
+            	// Now figure out the last week.
+            	dateToCell(daysInMonth, cellPos);
+            	width = (int)((cellPos.x+1)*cellWidth);  // Width of shaded area
+
+            	g.fillRect(0, (int)(labelHeight + (numWeeks-1) * cellHeight),
+                        	width, (int)(cellHeight));
+
+        	}
+        	// Draw the X/Y grid lines
+        	g.setColor(Color.black);
+        	for (int i = 0; i <= numWeeks; i++) {
+            	int y = (int)(labelHeight + i * cellHeight);
+            	g.drawLine(0, y, d.width - 1, y);
+        	}
+        	for (int i = 0; i <= daysInWeek; i++) {
+            	int x = (int)(i * cellWidth);
+            	g.drawLine(x, labelHeight, x, d.height - 1);
+        	}
+
+        	// Now loop through all of the days in the month, figure out where
+        	// they go in the grid, and draw the day # for each one
+        	Font numberFont = new Font("Helvetica",Font.PLAIN,12);
+        	// not used Font holidayFont = DemoUtility.creditFont;
+
+        	Calendar c = (Calendar)fCalendar.clone();
+        	c.setTime(fStartOfMonth);
+
+        	for (int i = 1, h = 0; i <= daysInMonth; i++) {
+            	g.setFont(numberFont);
+            	g.setColor(Color.black);
+            	fm = g.getFontMetrics();
+
+            	dateToCell(i, cellPos);
+            	int x = (int)((cellPos.x + 1) * cellWidth);
+            	int y = (int)(cellPos.y * cellHeight + labelHeight);
+
+            	StringBuffer buffer = new StringBuffer();
+            	buffer.append(i);
+            	String dayNum = buffer.toString();
+
+            	x = x - INSET - fm.stringWidth(dayNum);
+            	y = y + fm.getAscent() + INSET;
+
+            	g.drawString(dayNum, x, y);
+
+            	// See if any of the holidays land on this day....
+            	HolidayInfo info = null;
+            	int count = 0;
+
+            	// Coordinates of lower-left corner of cell.
+            	x = (int)((cellPos.x) * cellWidth);
+            	y = (int)((cellPos.y+1) * cellHeight) + labelHeight;
+
+            	while (h < fHolidays.size() &&
+                    	(info = (HolidayInfo)fHolidays.elementAt(h)).date <= i)
+            	{
+                	if (info.date == i) {
+                    	// Draw the holiday here.
+                    	g.setFont(numberFont);
+                    	g.setColor(Color.red);
+
+                    	DemoTextBox box = new DemoTextBox(g, info.name, (int)(cellWidth - INSET));
+                    	box.draw(g, x + INSET, y - INSET - box.getHeight());
+
+                    	y -= (box.getHeight() + INSET);
+                    	count++;
+                	}
+                	h++;
+            	}
+        	}
+    	}
+
+    	// Important state variables
+    	private Locale              fCalendarLocale;    // Whose calendar
+    	private Calendar            fCalendar;          // Calendar for calculations
+
+    	private Locale              fDisplayLocale;     // How to display it
+    	private DateFormatSymbols   fSymbols;           // Symbols for drawing
+
+    	private Date                fStartOfMonth;      // 00:00:00 on first day of month
+
+    	// Cached calculations to make drawing faster.
+    	private transient int minDay;           // Minimum legal day #
+    	private transient int daysInWeek;       // # of days in a week
+    	private transient int firstDayOfWeek;   // First day to display in week
+    	private transient int numWeeks;         // # full or partial weeks in month
+    	private transient int daysInMonth;      // # days in this month
+    	private transient int firstDayInMonth;  // Day of week of first day in month
+
+    	private transient Holiday[] fAllHolidays;
+    	private transient Vector    fHolidays = new Vector(5,5);
+
+    	private transient boolean dirty = true;
+	}
+
+	private static class HolidayInfo {
+    	public HolidayInfo(int date, Holiday holiday, String name) {
+        	this.date = date;
+        	this.holiday = holiday;
+        	this.name = name;
+    	}
+
+    	public Holiday holiday;
+    	public int date;
+    	public String name;
+	}
+}
+
diff --git a/src/com/ibm/demo/holiday/package.html b/src/com/ibm/demo/holiday/package.html
new file mode 100755
index 0000000..82ca145
--- /dev/null
+++ b/src/com/ibm/demo/holiday/package.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--  Copyright (C) 2000, International Business Machines Corporation and
+  others. All Rights Reserved.
+
+  $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/holiday/Attic/package.html,v $
+  $Revision: 1.1 $
+  $Date: 2000/03/15 06:54:50 $
+-->
+</head>
+<body bgcolor="white">
+Holiday demo application.
+</body>
+</html>
\ No newline at end of file
diff --git a/src/com/ibm/demo/package.html b/src/com/ibm/demo/package.html
new file mode 100755
index 0000000..045c6c3
--- /dev/null
+++ b/src/com/ibm/demo/package.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--  Copyright (C) 2000, International Business Machines Corporation and
+  others. All Rights Reserved.
+
+  $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/Attic/package.html,v $
+  $Revision: 1.1 $
+  $Date: 2000/03/15 17:43:40 $
+-->
+</head>
+<body bgcolor="white">
+Shared utilities for demo applications and Applets.
+</body>
+</html>
\ No newline at end of file
diff --git a/src/com/ibm/demo/rbbi/BreakIteratorRules_en_US_DEMO.java b/src/com/ibm/demo/rbbi/BreakIteratorRules_en_US_DEMO.java
new file mode 100755
index 0000000..8099ce2
--- /dev/null
+++ b/src/com/ibm/demo/rbbi/BreakIteratorRules_en_US_DEMO.java
@@ -0,0 +1,223 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/rbbi/Attic/BreakIteratorRules_en_US_DEMO.java,v $ 
+ * $Date: 2001/02/20 22:50:12 $ 
+ * $Revision: 1.6 $
+ *
+ *****************************************************************************************
+ */
+package com.ibm.text.resources;
+
+import java.util.ListResourceBundle;
+import java.net.URL;
+
+/**
+ * This resource bundle is included for testing and demonstration purposes only.
+ * It applies the dictionary-based algorithm to English text that has had all the
+ * spaces removed.  Once we have good test cases for Thai, we will replace this
+ * with good resource data (and a good dictionary file) for Thai
+ */
+public class BreakIteratorRules_en_US_DEMO extends ListResourceBundle {
+    
+    private static final URL url =
+        BreakIteratorRules_en_US_DEMO.class.getResource("/com/ibm/data/misc/english.dict");
+    
+    public Object[][] getContents() {
+        return contents;
+    }
+
+    static final Object[][] contents = {
+        // names of classes to instantiate for the different kinds of break
+        // iterator.  Notice we're now using DictionaryBasedBreakIterator
+        // for word and line breaking.
+        { "BreakIteratorClasses",
+            new String[] { "RuleBasedBreakIterator",           // character-break iterator class
+                           "DictionaryBasedBreakIterator",     // word-break iterator class
+                           "DictionaryBasedBreakIterator",     // line-break iterator class
+                           "RuleBasedBreakIterator" }          // sentence-break iterator class
+        },
+        
+        // These are the same word-breaking rules as are specified in the default
+        // resource, except that the Latin letters, apostrophe, and hyphen are
+        // specified as dictionary characters
+        { "WordBreakRules",
+            // ignore non-spacing marks, enclosing marks, and format characters,
+            // all of which should not influence the algorithm
+            "$_ignore_=[[:Mn:][:Me:][:Cf:]];"
+
+            // lower and upper case Roman letters, apostrophy and dash are
+            // in the English dictionary
+            + "$_dictionary_=[a-zA-Z\\'\\-];"
+
+            // Hindi phrase separator, kanji, katakana, hiragana, CJK diacriticals,
+            // other letters, and digits
+            + "$danda=[\u0964\u0965];"
+            + "$kanji=[\u3005\u4e00-\u9fa5\uf900-\ufa2d];"
+            + "$kata=[\u3099-\u309c\u30a1-\u30fe];"
+            + "$hira=[\u3041-\u309e\u30fc];"
+            + "$let=[[[:L:][:Mc:]]-[$kanji$kata$hira]];"
+            + "$dgt=[:N:];"
+
+            // punctuation that can occur in the middle of a word: currently
+            // dashes, apostrophes, and quotation marks
+            + "$mid_word=[[:Pd:]\u00ad\u2027\\\"\\\'];"
+
+            // punctuation that can occur in the middle of a number: currently
+            // apostrophes, qoutation marks, periods, commas, and the Arabic
+            // decimal point
+            + "$mid_num=[\\\"\\\'\\,\u066b\\.];"
+
+            // punctuation that can occur at the beginning of a number: currently
+            // the period, the number sign, and all currency symbols except the cents sign
+            + "$pre_num=[[[:Sc:]-[\u00a2]]\\#\\.];"
+
+            // punctuation that can occur at the end of a number: currently
+            // the percent, per-thousand, per-ten-thousand, and Arabic percent
+            // signs, the cents sign, and the ampersand
+            + "$post_num=[\\%\\&\u00a2\u066a\u2030\u2031];"
+
+            // line separators: currently LF, FF, PS, and LS
+            + "$ls=[\n\u000c\u2028\u2029];"
+
+            // whitespace: all space separators and the tab character
+            + "$ws=[[:Zs:]\t];"
+
+            // a word is a sequence of letters that may contain internal
+            // punctuation, as long as it begins and ends with a letter and
+            // never contains two punctuation marks in a row
+            + "$word=($let+($mid_word$let+)*$danda?);"
+
+            // a number is a sequence of digits that may contain internal
+            // punctuation, as long as it begins and ends with a digit and
+            // never contains two punctuation marks in a row.
+            + "$number=($dgt+($mid_num$dgt+)*);"
+
+            // break after every character, with the following exceptions
+            // (this will cause punctuation marks that aren't considered
+            // part of words or numbers to be treated as words unto themselves)
+            + ".;"
+
+            // keep together any sequence of contiguous words and numbers
+            // (including just one of either), plus an optional trailing
+            // number-suffix character
+            + "$word?($number$word)*($number$post_num?)?;"
+
+            // keep together and sequence of contiguous words and numbers
+            // that starts with a number-prefix character and a number,
+            // and may end with a number-suffix character
+            + "$pre_num($number$word)*($number$post_num?)?;"
+
+            // keep together runs of whitespace (optionally with a single trailing
+            // line separator or CRLF sequence)
+            + "$ws*\r?$ls?;"
+
+            // keep together runs of Katakana
+            + "$kata*;"
+
+            // keep together runs of Hiragana
+            + "$hira*;"
+
+            // keep together runs of Kanji
+            + "$kanji*;"},
+        
+        // These are the same line-breaking rules as are specified in the default
+        // resource, except that the Latin letters, apostrophe, and hyphen are
+        // specified as dictionary characters
+        { "LineBreakRules",
+            // ignore non-spacing marks, enclosing marks, and format characters
+            "$_ignore_=[[:Mn:][:Me:][:Cf:]];"
+
+            // lower and upper case Roman letters, apostrophy and dash
+            // are in the English dictionary
+            + "$_dictionary_=[a-zA-Z\\'\\-];"
+
+            // Hindi phrase separators
+            + "$danda=[\u0964\u0965];"
+
+            // characters that always cause a break: ETX, tab, LF, FF, LS, and PS
+            + "$break=[\u0003\t\n\f\u2028\u2029];"
+
+            // characters that always prevent a break: the non-breaking space
+            // and similar characters
+            + "$nbsp=[\u00a0\u2007\u2011\ufeff];"
+
+            // whitespace: space separators and control characters, except for
+            // CR and the other characters mentioned above
+            + "$space=[[[:Zs:][:Cc:]]-[$nbsp$break\r]];"
+
+            // dashes: dash punctuation and the discretionary hyphen, except for
+            // non-breaking hyphens
+            + "$dash=[[[:Pd:]\u00ad]-[$nbsp]];"
+
+            // characters that stick to a word if they precede it: currency symbols
+            // (except the cents sign) and starting punctuation
+            + "$pre_word=[[[:Sc:]-[\u00a2]][:Ps:]\\\"\\\'];"
+
+            // characters that stick to a word if they follow it: ending punctuation,
+            // other punctuation that usually occurs at the end of a sentence,
+            // small Kana characters, some CJK diacritics, etc.
+            + "$post_word=[[:Pe:]\\!\\\"\\\'\\%\\.\\,\\:\\;\\?\u00a2\u00b0\u066a\u2030-\u2034"
+                    + "\u2103\u2105\u2109\u3001\u3002\u3005\u3041\u3043\u3045\u3047\u3049\u3063"
+                    + "\u3083\u3085\u3087\u308e\u3099-\u309e\u30a1\u30a3\u30a5\u30a7\u30a9"
+                    + "\u30c3\u30e3\u30e5\u30e7\u30ee\u30f5\u30f6\u30fc-\u30fe\uff01\uff0c"
+                    + "\uff0e\uff1f];"
+
+            // Kanji: actually includes both Kanji and Kana, except for small Kana and
+            // CJK diacritics
+            + "$kanji=[[\u4e00-\u9fa5\uf900-\ufa2d\u3041-\u3094\u30a1-\u30fa]-[$post_word$_ignore_]];"
+
+            // digits
+            + "$digit=[[:Nd:][:No:]];"
+
+            // punctuation that can occur in the middle of a number: periods and commas
+            + "$mid_num=[\\.\\,];"
+
+            // everything not mentioned above, plus the quote marks (which are both
+            // <pre-word>, <post-word>, and <char>)
+            + "$char=[^$break$space$dash$kanji$nbsp$_ignore_$pre_word$post_word$mid_num$danda\r\\\"\\\'];"
+
+            // a "number" is a run of prefix characters and dashes, followed by one or
+            // more digits with isolated number-punctuation characters interspersed
+            + "$number=([$pre_word$dash]*$digit+($mid_num$digit+)*);"
+
+            // the basic core of a word can be either a "number" as defined above, a single
+            // "Kanji" character, or a run of any number of not-explicitly-mentioned
+            // characters (this includes Latin letters)
+            + "$word_core=([$pre_word$char]*|$kanji|$number);"
+
+            // a word may end with an optional suffix that be either a run of one or
+            // more dashes or a run of word-suffix characters, followed by an optional
+            // run of whitespace
+            + "$word_suffix=(($dash+|$post_word*)$space*);"
+
+            // a word, thus, is an optional run of word-prefix characters, followed by
+            // a word core and a word suffix (the syntax of <word-core> and <word-suffix>
+            // actually allows either of them to match the empty string, putting a break
+            // between things like ")(" or "aaa(aaa"
+            + "$word=($pre_word*$word_core$word_suffix);"
+
+            // finally, the rule that does the work: Keep together any run of words that
+            // are joined by runs of one of more non-spacing mark.  Also keep a trailing
+            // line-break character or CRLF combination with the word.  (line separators
+            // "win" over nbsp's)
+            + "$word($nbsp+$word)*\r?$break?;" },
+            
+        // these two resources specify the pathnames of the dictionary files to
+        // use for word breaking and line breaking.  Both currently refer to 
+        // a file called english.dict placed in com\ibm\text\resources
+        // somewhere in the class path.  It's important to note that
+        // english.dict was created for testing purposes only, and doesn't
+        // come anywhere close to being an exhaustive dictionary of English
+        // words (basically, it contains all the words in the Declaration of
+        // Independence, and the Revised Standard Version of the book of Genesis,
+        // plus a few other words thrown in to show more interesting cases).
+        // { "WordBreakDictionary", "com\\ibm\\text\\resources\\english.dict" },
+        // { "LineBreakDictionary", "com\\ibm\\text\\resources\\english.dict" }
+        { "WordBreakDictionary", url },
+        { "LineBreakDictionary", url }
+    };
+}
diff --git a/src/com/ibm/demo/rbbi/DBBIDemo.java b/src/com/ibm/demo/rbbi/DBBIDemo.java
new file mode 100755
index 0000000..5eafa3f
--- /dev/null
+++ b/src/com/ibm/demo/rbbi/DBBIDemo.java
@@ -0,0 +1,468 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/rbbi/Attic/DBBIDemo.java,v $ 
+ * $Date: 2001/10/30 02:42:48 $ 
+ * $Revision: 1.8 $
+ *
+ *****************************************************************************************
+ */
+package com.ibm.demo.rbbi;
+
+
+import com.ibm.demo.*;
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.WindowEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.ItemEvent;
+import javax.swing.JTextArea;
+import javax.swing.JScrollPane;
+import javax.swing.BorderFactory;
+import java.util.*;
+
+import com.ibm.text.BreakIterator;
+
+public class DBBIDemo extends DemoApplet
+{
+    public static void main(String argv[]) {
+        Locale.setDefault(new Locale("en", "US", "DEMO"));
+		new DBBIDemo().showDemo();
+    }
+
+    public Frame createDemoFrame(DemoApplet applet) {
+        return new DBBIFrame(applet);
+    }
+}
+
+
+
+class DBBIFrame extends Frame implements ItemListener
+{
+    private static final String creditString =
+        "v1.1a9, Demo";
+
+    private static final int FIELD_COLUMNS = 45;
+    private static final Font choiceFont = null;
+    private static final boolean DEBUG = false;
+    private DemoApplet applet;
+
+    final String right = "-->";
+    final String left = "<--";
+
+    private BreakIterator enum;
+    private static boolean isctrldown_ = false;
+
+JTextArea text;
+//    TextArea text;
+    Choice bound;
+
+    public DBBIFrame(DemoApplet applet)
+    {
+        this.applet = applet;
+        init();
+        start();
+    }
+
+
+
+    public void run()
+    {
+        /*
+        while (true) {
+            try {
+                checkChange();
+                Thread.sleep(250);
+            }
+            catch (InterruptedException e) {
+            }
+            catch (Exception e) {
+            }
+            catch (Throwable e) {
+            }
+        }
+        */
+    }
+
+    int s, e;
+    int ts, te;
+
+    public void checkChange()
+    {
+//        System.out.println("checkChange...");
+        if ((text.getSelectionStart() & 0x7FFF) != ts ||
+            (text.getSelectionEnd() & 0x7FFF) != te) {
+
+            // not used int tempS = text.getSelectionStart() & 0x7FFF;
+            // not used int tempE = text.getSelectionEnd() & 0x7FFF;
+
+//          System.out.println(">");
+//          select(0, 0);
+//          select(tempS, tempE);
+            //select(tempS - (ts - s), tempE - (te - e));
+//          System.out.println("<");
+
+
+//          if (s != ts || e != te) System.out.println("     s("+s+") ts("+ts+") e("+e+") te("+te+")");
+//          if (tempS != ts || tempE != te) System.out.println(">s("+s+") tempS("+tempS+") e("+e+") tempE("+tempE+")");
+//          select(s - (ts - s), e - (te - e));
+//          if (tempS != ts || tempE != te) System.out.println("s("+s+") tempS("+tempS+") e("+e+") tempE("+tempE+")");
+
+//          System.out.println("lkdslksj");
+        }
+    }
+
+    public void select(int sIn, int eIn)
+    {
+        s = sIn;
+        e = eIn;
+        text.select(s, e);
+        ts = text.getSelectionStart() & 0x7FFF;
+        te = text.getSelectionEnd() & 0x7FFF;
+//        if (s != ts || e != te) {
+//            System.out.println(">s("+s+") ts("+ts+") e("+e+") te("+te+")");
+//            System.out.println("   "+(ts-s)+","+(te-e));
+//        }
+    }
+
+    public int getSelectionStart()
+    {
+        checkChange();
+//      return s;
+        return text.getSelectionStart() & 0x7FFF;
+    }
+
+
+    public int getSelectionEnd()
+    {
+        checkChange();
+//      return e;
+        return text.getSelectionEnd() & 0x7FFF;
+    }
+
+    public final synchronized void selectRange(int s, int e)
+    {
+        try {
+            //if (getSelectionStart() != s || getSelectionEnd() != e) {
+                //text.select(s, e);
+                select(s,e);
+            //}
+//          if (getSelectionStart() != s || getSelectionEnd() != e) {
+//              System.out.println("AGH! select("+s+","+e+") -> ("+
+//              getSelectionStart()+","+getSelectionEnd()+")");
+//              text.select(s - (getSelectionStart() - s), e - (getSelectionEnd() - e));
+//          }
+        } catch (Exception exp) {
+            errorText(exp.toString());
+        }
+    }
+
+
+
+    public void init()
+    {
+        buildGUI();
+    }
+
+
+    public void start()
+    {
+    }
+
+
+    void addWithFont(Container container, Component foo, Font font) {
+        if (font != null)
+            foo.setFont(font);
+        container.add(foo);
+    }
+
+
+
+   public void buildGUI()
+    {
+        setBackground(DemoUtility.bgColor);
+        setLayout(new BorderLayout());
+
+       Panel topPanel = new Panel();
+
+            Label titleLabel =
+                new Label("Text Boundary Demo", Label.CENTER);
+            titleLabel.setFont(DemoUtility.titleFont);
+            topPanel.add(titleLabel);
+
+            //Label demo=new Label(creditString, Label.CENTER);
+            //demo.setFont(DemoUtility.creditFont);
+            //topPanel.add(demo);
+
+            Panel choicePanel = new Panel();
+
+            Label demo1=new Label("Boundaries", Label.LEFT);
+            demo1.setFont(DemoUtility.labelFont);
+            choicePanel.add(demo1);
+
+            bound = new Choice();
+                bound.setBackground(DemoUtility.choiceColor);
+            bound.addItem("Sentence");
+            bound.addItem("Line Break");
+            bound.addItem("Word");
+            bound.addItem("Char");
+            
+            bound.addItemListener(this);
+            if (choiceFont != null)
+                bound.setFont(choiceFont);
+
+            choicePanel.add(bound);
+            topPanel.add(choicePanel);
+
+            DemoUtility.fixGrid(topPanel,1);
+
+
+        add("North", topPanel);
+
+
+            int ROWS = 15;
+            int COLUMNS = 50;
+//            text = new TextArea(getInitialText(), ROWS, COLUMNS);
+text = new JTextArea(getInitialText(), ROWS, COLUMNS);
+text.setLineWrap(true);
+text.setWrapStyleWord(true);
+            text.setEditable(true);
+            text.selectAll();
+            text.setFont(DemoUtility.editFont);
+            text.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
+
+        add("Center", new JScrollPane(text, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+                        JScrollPane.HORIZONTAL_SCROLLBAR_NEVER));
+
+        Panel copyrightPanel = new Panel();
+        addWithFont (copyrightPanel,
+            new Label(DemoUtility.copyright1, Label.LEFT),DemoUtility.creditFont);
+        addWithFont (copyrightPanel,
+            new Label(DemoUtility.copyright2, Label.LEFT),DemoUtility.creditFont);
+        DemoUtility.fixGrid(copyrightPanel,1);
+        add("South", copyrightPanel);
+
+        //layout();
+        handleEnumChanged();
+        
+        enableEvents(WindowEvent.WINDOW_CLOSING);
+        enableEvents(KeyEvent.KEY_PRESSED);
+        enableEvents(KeyEvent.KEY_RELEASED);
+
+        // (new Thread(this)).start();
+    }
+
+
+
+    public String getInitialText()
+    {
+        return
+"When,inthecourseofhumanevents,itbecomesnecessaryforonepeopletodissolvethepoliticalbondswhichhave"
++ "connectedthemwithanother,andtoassumeamongthepowersoftheearth,theseparateandequalstationtowhichthelaws"
++ "ofnatureandofnature'sGodentitlethem,adecentrespecttotheopinionsofmankindrequiresthattheyshoulddeclarethe"
++ "causeswhichimpelthemtotheseparation.\n"
++ "Weholdthesetruthstobeself-evident,thatallmenarecreatedequal,thattheyareendowedbytheirCreatorwithcertain"
++ "unalienablerights,thatamongthesearelife,libertyandthepursuitofhappiness.Thattosecuretheserights,governmentsare"
++ "institutedamongmen,derivingtheirjustpowersfromtheconsentofthegoverned.Thatwheneveranyformofgovernment"
++ "becomesdestructivetotheseends,itistherightofthepeopletoalterortoabolishit,andtoinstitutenewgovernment,laying"
++ "itsfoundationonsuchprinciplesandorganizingitspowersinsuchform,astothemshallseemmostlikelytoeffecttheirsafety"
++ "andhappiness.Prudence,indeed,willdictatethatgovernmentslongestablishedshouldnotbechangedforlightandtransient"
++ "causes;andaccordinglyallexperiencehathshownthatmankindaremoredisposedtosuffer,whileevilsaresufferable,than"
++ "torightthemselvesbyabolishingtheformstowhichtheyareaccustomed.Butwhenalongtrainofabusesandusurpations,"
++ "pursuinginvariablythesameobjectevincesadesigntoreducethemunderabsolutedespotism,itistheirright,itistheirduty,"
++ "tothrowoffsuchgovernment,andtoprovidenewguardsfortheirfuturesecurity.--Suchhasbeenthepatientsufferanceof"
++ "thesecolonies;andsuchisnowthenecessitywhichconstrainsthemtoaltertheirformersystemsofgovernment.Thehistory"
++ "ofthepresentKingofGreatBritainisahistoryofrepeatedinjuriesandusurpations,allhavingindirectobjectthe"
++ "establishmentofanabsolutetyrannyoverthesestates.Toprovethis,letfactsbesubmittedtoacandidworld.\n"
++ "Hehasrefusedhisassenttolaws,themostwholesomeandnecessaryforthepublicgood.\n"
++ "Hehasforbiddenhisgovernorstopasslawsofimmediateandpressingimportance,unlesssuspendedintheiroperationtill"
++ "hisassentshouldbeobtained;andwhensosuspended,hehasutterlyneglectedtoattendtothem.\n"
++ "Hehasrefusedtopassotherlawsfortheaccommodationoflargedistrictsofpeople,unlessthosepeoplewouldrelinquish"
++ "therightofrepresentationinthelegislature,arightinestimabletothemandformidabletotyrantsonly.\n"
++ "Hehascalledtogetherlegislativebodiesatplacesunusual,uncomfortable,anddistantfromthedepositoryoftheirpublic"
++ "records,forthesolepurposeoffatiguingthemintocompliancewithhismeasures.\n"
++ "Hehasdissolvedrepresentativehousesrepeatedly,foropposingwithmanlyfirmnesshisinvasionsontherightsofthepeople.\n"
++ "Hehasrefusedforalongtime,aftersuchdissolutions,tocauseotherstobeelected;wherebythelegislativepowers,"
++ "incapableofannihilation,havereturnedtothepeopleatlargefortheirexercise;thestateremaininginthemeantimeexposed"
++ "toallthedangersofinvasionfromwithout,andconvulsionswithin.\n"
++ "Hehasendeavoredtopreventthepopulationofthesestates;forthatpurposeobstructingthelawsfornaturalizationof"
++ "foreigners;refusingtopassotherstoencouragetheirmigrationhither,andraisingtheconditionsofnewappropriationsof"
++ "lands.\n"
++ "Hehasobstructedtheadministrationofjustice,byrefusinghisassenttolawsforestablishingjudiciarypowers.\n"
++ "Hehasmadejudgesdependentonhiswillalone,forthetenureoftheiroffices,andtheamountandpaymentoftheirsalaries.\n"
++ "Hehaserectedamultitudeofnewoffices,andsenthitherswarmsofofficerstoharassourpeople,andeatouttheir"
++ "substance.\n"
++ "Hehaskeptamongus,intimesofpeace,standingarmieswithouttheconsentofourlegislature.\n"
++ "Hehasaffectedtorenderthemilitaryindependentofandsuperiortocivilpower.\n"
++ "Hehascombinedwithotherstosubjectustoajurisdictionforeigntoourconstitution,andunacknowledgedbyourlaws;"
++ "givinghisassenttotheiractsofpretendedlegislation:\n"
++ "Forquarteringlargebodiesofarmedtroopsamongus:\n"
++ "Forprotectingthem,bymocktrial,frompunishmentforanymurderswhichtheyshouldcommitontheinhabitantsofthese"
++ "states:\n"
++ "Forcuttingoffourtradewithallpartsoftheworld:\n"
++ "Forimposingtaxesonuswithoutourconsent:\n"
++ "Fordeprivingusinmanycases,ofthebenefitsoftrialbyjury:\n"
++ "Fortransportingusbeyondseastobetriedforpretendedoffenses:\n"
++ "ForabolishingthefreesystemofEnglishlawsinaneighboringprovince,establishingthereinanarbitrarygovernment,and"
++ "enlargingitsboundariessoastorenderitatonceanexampleandfitinstrumentforintroducingthesameabsoluteruleinthese"
++ "colonies:\n"
++ "Fortakingawayourcharters,abolishingourmostvaluablelaws,andalteringfundamentallytheformsofourgovernments:\n"
++ "Forsuspendingourownlegislatures,anddeclaringthemselvesinvestedwithpowertolegislateforusinallcaseswhatsoever.\n"
++ "Hehasabdicatedgovernmenthere,bydeclaringusoutofhisprotectionandwagingwaragainstus.\n"
++ "Hehasplunderedourseas,ravagedourcoasts,burnedourtowns,anddestroyedthelivesofourpeople.\n"
++ "Heisatthistimetransportinglargearmiesofforeignmercenariestocompletetheworksofdeath,desolationandtyranny,"
++ "alreadybegunwithcircumstancesofcrueltyandperfidyscarcelyparalleledinthemostbarbarousages,andtotallyunworthy"
++ "theheadofacivilizednation.\n"
++ "Hehasconstrainedourfellowcitizenstakencaptiveonthehighseastobeararmsagainsttheircountry,tobecomethe"
++ "executionersoftheirfriendsandbrethren,ortofallthemselvesbytheirhands.\n"
++ "Hehasexciteddomesticinsurrectionsamongstus,andhasendeavoredtobringontheinhabitantsofourfrontiers,the"
++ "mercilessIndiansavages,whoseknownruleofwarfare,isundistinguisheddestructionofallages,sexesandconditions.\n"
++ "Ineverystageoftheseoppressionswehavepetitionedforredressinthemosthumbleterms:ourrepeatedpetitionshave"
++ "beenansweredonlybyrepeatedinjury.Aprince,whosecharacteristhusmarkedbyeveryactwhichmaydefineatyrant,is"
++ "unfittobetherulerofafreepeople.\n"
++ "NorhavewebeenwantinginattentiontoourBritishbrethren.Wehavewarnedthemfromtimetotimeofattemptsbytheir"
++ "legislaturetoextendanunwarrantablejurisdictionoverus.Wehaveremindedthemofthecircumstancesofouremigration"
++ "andsettlementhere.Wehaveappealedtotheirnativejusticeandmagnanimity,andwehaveconjuredthembythetiesofour"
++ "commonkindredtodisavowtheseusurpations,which,wouldinevitablyinterruptourconnectionsandcorrespondence.We"
++ "must,therefore,acquiesceinthenecessity,whichdenouncesourseparation,andholdthem,asweholdtherestofmankind,"
++ "enemiesinwar,inpeacefriends.\n"
++ "We,therefore,therepresentativesoftheUnitedStatesofAmerica,inGeneralCongress,assembled,appealingtothe"
++ "SupremeJudgeoftheworldfortherectitudeofourintentions,do,inthename,andbytheauthorityofthegoodpeopleof"
++ "thesecolonies,solemnlypublishanddeclare,thattheseunitedcoloniesare,andofrightoughttobefreeandindependent"
++ "states;thattheyareabsolvedfromallallegiancetotheBritishCrown,andthatallpoliticalconnectionbetweenthemandthe"
++ "stateofGreatBritain,isandoughttobetotallydissolved;andthatasfreeandindependentstates,theyhavefullpowerto"
++ "leveywar,concludepeace,contractalliances,establishcommerce,andtodoallotheractsandthingswhichindependent"
++ "statesmayofrightdo.Andforthesupportofthisdeclaration,withafirmrelianceontheprotectionofDivineProvidence,we"
++ "mutuallypledgetoeachotherourlives,ourfortunesandoursacredhonor.\n";
+    }
+
+
+    public void handleEnumChanged()
+    {
+        String s = bound.getSelectedItem();
+        if (s.equals("Char")) {
+            errorText("getCharacterInstance");
+            enum = BreakIterator.getCharacterInstance();
+        }
+        else if (s.equals("Word")) {
+            errorText("getWordInstance");
+            enum = BreakIterator.getWordInstance();
+        }
+        else if (s.equals("Line Break")) {
+            errorText("getLineInstance");
+            enum = BreakIterator.getLineInstance();
+        }
+        else /* if (s.equals("Sentence")) */ {
+            errorText("getSentenceInstance");
+            enum = BreakIterator.getSentenceInstance();
+        }
+        enum.setText(text.getText());
+        selectRange(0, 0);
+        //text.select(0,0);
+    }
+
+    public void handleForward()
+    {
+        try {
+//          System.out.println("entering handleForward");
+            enum.setText(text.getText());
+            int oldStart = getSelectionStart();
+            int oldEnd = getSelectionEnd();
+
+//          System.out.println("handleForward: oldStart=" + oldStart + ", oldEnd=" + oldEnd);
+
+            if (oldEnd < 1) {
+                selectRange(0, enum.following(0));
+            }
+            else {
+                int s = enum.following(oldEnd-1);
+                int e = enum.next();
+                if (e == -1) {
+                    e = s;
+                }
+                selectRange(s, e);
+            }
+            //text.select(s, e);
+            errorText("<" + oldStart + "," + oldEnd + "> -> <" +
+                s + "," + e + ">");
+        }
+        catch (Exception exp) {
+            errorText(exp.toString());
+        }
+    }
+
+    public void handleBackward()
+    {
+        try {
+            enum.setText(text.getText());
+            int oldStart = getSelectionStart();
+            int oldEnd = getSelectionEnd();
+            if (oldStart < 1) {
+                selectRange(0, 0);
+            }
+            else {
+                int e = enum.following(oldStart-1);
+                int s = enum.previous();
+                selectRange(s, e);
+            }
+            //text.select(s, e);
+            errorText("<" + oldStart + "," + oldEnd + "> -> <" + s + "," + e + ">");
+        }
+        catch (Exception exp) {
+            errorText(exp.toString());
+        }
+    }
+
+    public void itemStateChanged(ItemEvent evt)
+    {
+        if (evt.getSource() instanceof Choice) {
+            handleEnumChanged();
+        }
+    }
+
+    public void errorText(String s)
+    {
+       if (DEBUG)
+           System.out.println(s);
+    }
+    
+    protected void processWindowEvent(WindowEvent evt)
+    {
+        if (evt.getID() == WindowEvent.WINDOW_CLOSING && 
+            evt.getWindow() == this) {
+            hide();
+            dispose();
+            if (applet != null) {
+                applet.demoClosed();
+            } else System.exit(0);
+        }
+    }
+    
+    protected void processKeyEvent(KeyEvent evt)
+    {
+        switch (evt.getID()) {
+            case KeyEvent.KEY_PRESSED :
+                if (evt.getKeyCode() == KeyEvent.VK_CONTROL) {
+                    isctrldown_ = true;
+                }
+                break;
+            case KeyEvent.KEY_RELEASED :
+                int key = evt.getKeyCode();
+                if (key == KeyEvent.VK_RIGHT || 
+                    (key == KeyEvent.VK_N && isctrldown_)) {
+                    handleForward();
+                }
+                else 
+                if (key == KeyEvent.VK_LEFT || 
+                    (key == KeyEvent.VK_P && isctrldown_)) {
+                    handleBackward();
+                }
+                isctrldown_ = false;
+                break;
+        }
+    }
+}
diff --git a/src/com/ibm/demo/rbbi/RBBIDemo.java b/src/com/ibm/demo/rbbi/RBBIDemo.java
new file mode 100755
index 0000000..2ce7a01
--- /dev/null
+++ b/src/com/ibm/demo/rbbi/RBBIDemo.java
@@ -0,0 +1,453 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/rbbi/Attic/RBBIDemo.java,v $ 
+ * $Date: 2001/10/30 02:42:48 $ 
+ * $Revision: 1.3 $
+ *
+ *****************************************************************************************
+ */
+package com.ibm.demo.rbbi;
+
+import com.ibm.demo.*;
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.WindowEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.ItemEvent;
+import javax.swing.JTextArea;
+import javax.swing.JScrollPane;
+import javax.swing.BorderFactory;
+import java.util.*;
+
+import com.ibm.text.BreakIterator;
+
+public class RBBIDemo extends DemoApplet
+{
+    public static void main(String argv[]) {
+        Locale.setDefault(new Locale("en", "US"));
+		new RBBIDemo().showDemo();
+    }
+
+    public Frame createDemoFrame(DemoApplet applet) {
+        return new RBBIFrame(applet);
+    }
+}
+
+
+
+class RBBIFrame extends Frame implements ItemListener
+{
+    private static final String creditString =
+        "v1.1a9, Demo";
+
+    private static final int FIELD_COLUMNS = 45;
+    private static final Font choiceFont = null;
+    private static final boolean DEBUG = false;
+    private DemoApplet applet;
+
+    final String right = "-->";
+    final String left = "<--";
+
+    private BreakIterator enum;
+    private boolean       isctrldown_ = false;
+
+JTextArea text;
+//    TextArea text;
+    Choice bound;
+
+    public RBBIFrame(DemoApplet applet)
+    {
+        this.applet = applet;
+        init();
+        start();
+    }
+
+
+
+    public void run()
+    {
+        /*
+        while (true) {
+            try {
+                checkChange();
+                Thread.sleep(250);
+            }
+            catch (InterruptedException e) {
+            }
+            catch (Exception e) {
+            }
+            catch (Throwable e) {
+            }
+        }
+        */
+    }
+
+    int s, e;
+    int ts, te;
+
+    public void checkChange()
+    {
+//        System.out.println("checkChange...");
+        if ((text.getSelectionStart() & 0x7FFF) != ts ||
+            (text.getSelectionEnd() & 0x7FFF) != te) {
+
+            // not used int tempS = text.getSelectionStart() & 0x7FFF;
+            // not used int tempE = text.getSelectionEnd() & 0x7FFF;
+
+//          System.out.println(">");
+//          select(0, 0);
+//          select(tempS, tempE);
+            //select(tempS - (ts - s), tempE - (te - e));
+//          System.out.println("<");
+
+
+//          if (s != ts || e != te) System.out.println("     s("+s+") ts("+ts+") e("+e+") te("+te+")");
+//          if (tempS != ts || tempE != te) System.out.println(">s("+s+") tempS("+tempS+") e("+e+") tempE("+tempE+")");
+//          select(s - (ts - s), e - (te - e));
+//          if (tempS != ts || tempE != te) System.out.println("s("+s+") tempS("+tempS+") e("+e+") tempE("+tempE+")");
+
+//          System.out.println("lkdslksj");
+        }
+    }
+
+    public void select(int sIn, int eIn)
+    {
+        s = sIn;
+        e = eIn;
+        text.select(s, e);
+        ts = text.getSelectionStart() & 0x7FFF;
+        te = text.getSelectionEnd() & 0x7FFF;
+//        if (s != ts || e != te) {
+//            System.out.println(">s("+s+") ts("+ts+") e("+e+") te("+te+")");
+//            System.out.println("   "+(ts-s)+","+(te-e));
+//        }
+    }
+
+    public int getSelectionStart()
+    {
+        checkChange();
+//      return s;
+        return text.getSelectionStart() & 0x7FFF;
+    }
+
+
+    public int getSelectionEnd()
+    {
+        checkChange();
+//      return e;
+        return text.getSelectionEnd() & 0x7FFF;
+    }
+
+    public final synchronized void selectRange(int s, int e)
+    {
+        try {
+            //if (getSelectionStart() != s || getSelectionEnd() != e) {
+                //text.select(s, e);
+                select(s,e);
+            //}
+//          if (getSelectionStart() != s || getSelectionEnd() != e) {
+//              System.out.println("AGH! select("+s+","+e+") -> ("+
+//              getSelectionStart()+","+getSelectionEnd()+")");
+//              text.select(s - (getSelectionStart() - s), e - (getSelectionEnd() - e));
+//          }
+        } catch (Exception exp) {
+            errorText(exp.toString());
+        }
+    }
+
+
+
+    public void init()
+    {
+        buildGUI();
+    }
+
+
+    public void start()
+    {
+    }
+
+
+    void addWithFont(Container container, Component foo, Font font) {
+        if (font != null)
+            foo.setFont(font);
+        container.add(foo);
+    }
+
+
+
+   public void buildGUI()
+    {
+        setBackground(DemoUtility.bgColor);
+        setLayout(new BorderLayout());
+
+       Panel topPanel = new Panel();
+
+            Label titleLabel =
+                new Label("Deva Text Boundary Demo", Label.CENTER);
+            titleLabel.setFont(DemoUtility.titleFont);
+            topPanel.add(titleLabel);
+
+            //Label demo=new Label(creditString, Label.CENTER);
+            //demo.setFont(DemoUtility.creditFont);
+            //topPanel.add(demo);
+
+            Panel choicePanel = new Panel();
+
+            Label demo1=new Label("Boundaries", Label.LEFT);
+            demo1.setFont(DemoUtility.labelFont);
+            choicePanel.add(demo1);
+
+            bound = new Choice();
+                bound.setBackground(DemoUtility.choiceColor);
+            bound.addItem("Sentence");
+            bound.addItem("Line Break");
+            bound.addItem("Word");
+            bound.addItem("Char");
+            bound.addItemListener(this);
+            if (choiceFont != null)
+                bound.setFont(choiceFont);
+
+            choicePanel.add(bound);
+            topPanel.add(choicePanel);
+
+            DemoUtility.fixGrid(topPanel,1);
+
+
+        add("North", topPanel);
+
+
+            int ROWS = 15;
+            int COLUMNS = 50;
+//            text = new TextArea(getInitialText(), ROWS, COLUMNS);
+            text = new JTextArea(getInitialText(), ROWS, COLUMNS);
+            text.setLineWrap(true);
+            text.setWrapStyleWord(true);
+            text.setEditable(true);
+            text.selectAll();
+            text.setFont(new Font("Devanagari MT for IBM", Font.PLAIN, 48));
+            text.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
+
+        add("Center", new JScrollPane(text, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+                        JScrollPane.HORIZONTAL_SCROLLBAR_NEVER));
+
+        Panel copyrightPanel = new Panel();
+        addWithFont (copyrightPanel,
+            new Label(DemoUtility.copyright1, Label.LEFT),DemoUtility.creditFont);
+        addWithFont (copyrightPanel,
+            new Label(DemoUtility.copyright2, Label.LEFT),DemoUtility.creditFont);
+        DemoUtility.fixGrid(copyrightPanel,1);
+        add("South", copyrightPanel);
+
+        //layout();
+        handleEnumChanged();
+        
+        enableEvents(WindowEvent.WINDOW_CLOSING);
+        enableEvents(KeyEvent.KEY_PRESSED);
+        enableEvents(KeyEvent.KEY_RELEASED);    
+
+        // (new Thread(this)).start();
+    }
+
+
+
+    public String getInitialText()
+    {
+        return
+            "\u0936\u094d\u0930\u0940\u092e\u0926\u094d " +
+            "\u092d\u0917\u0935\u0926\u094d\u0917\u0940\u0924\u093e " +
+            "\u0905\u0927\u094d\u092f\u093e\u092f " +
+            "\u0905\u0930\u094d\u091c\u0941\u0928 " +
+            "\u0935\u093f\u0937\u093e\u0926 " +
+            "\u092f\u094b\u0917 " +
+            "\u0927\u0943\u0924\u0930\u093e\u0937\u094d\u091f\u094d\u0930 " +
+            "\u0909\u0935\u093E\u091A\u0943 " +
+            "\u0927\u0930\u094d\u092e\u0915\u094d\u0937\u0947\u0924\u094d\u0930\u0947 " +
+            "\u0915\u0941\u0930\u0941\u0915\u094d\u0937\u0947\u0924\u094d\u0930\u0947 " +
+            "\u0938\u092e\u0935\u0947\u0924\u093e " +
+            "\u092f\u0941\u092f\u0941\u0924\u094d\u0938\u0935\u0903 " +
+            "\u092e\u093e\u092e\u0915\u093e\u0903 " +
+            "\u092a\u093e\u0923\u094d\u0921\u0935\u093e\u0936\u094d\u091a\u0948\u0935 " +
+            "\u0915\u093f\u092e\u0915\u0941\u0930\u094d\u0935\u0924 " +
+            "\u0938\u0902\u091c\u0935";
+    }
+
+
+    public void handleEnumChanged()
+    {
+        String s = bound.getSelectedItem();
+        if (s.equals("Char")) {
+            errorText("getCharacterInstance");
+            enum = BreakIterator.getCharacterInstance();
+        }
+        else if (s.equals("Word")) {
+            errorText("tWordBreak");
+            enum = BreakIterator.getWordInstance();
+        }
+        else if (s.equals("Line Break")) {
+            errorText("getLineInstance");
+            enum = BreakIterator.getLineInstance();
+        }
+        else /* if (s.equals("Sentence")) */ {
+            errorText("getSentenceInstance");
+            enum = BreakIterator.getSentenceInstance();
+        }
+        enum.setText(text.getText());
+        selectRange(0, 0);
+        //text.select(0,0);
+    }
+
+    public void handleForward()
+    {
+        try {
+//          System.out.println("entering handleForward");
+            enum.setText(text.getText());
+            int oldStart = getSelectionStart();
+            int oldEnd = getSelectionEnd();
+
+//          System.out.println("handleForward: oldStart=" + oldStart + ", oldEnd=" + oldEnd);
+
+            if (oldEnd < 1) {
+                selectRange(0, enum.following(0));
+            }
+            else {
+                int s = enum.following(oldEnd-1);
+                int e = enum.next();
+                if (e == -1) {
+                    e = s;
+                }
+                selectRange(s, e);
+            }
+            //text.select(s, e);
+            errorText("<" + oldStart + "," + oldEnd + "> -> <" +
+                s + "," + e + ">");
+        }
+        catch (Exception exp) {
+            errorText(exp.toString());
+        }
+    }
+
+    public void handleBackward()
+    {
+        try {
+            enum.setText(text.getText());
+            int oldStart = getSelectionStart();
+            int oldEnd = getSelectionEnd();
+            if (oldStart < 1) {
+                selectRange(0, 0);
+            }
+            else {
+                int e = enum.following(oldStart-1);
+                int s = enum.previous();
+                selectRange(s, e);
+            }
+            //text.select(s, e);
+            errorText("<" + oldStart + "," + oldEnd + "> -> <" + s + "," + e + ">");
+        }
+        catch (Exception exp) {
+            errorText(exp.toString());
+        }
+    }
+
+    /*
+    public boolean action(Event evt, Object obj)
+    {
+
+        if(evt.target instanceof Button && left.equals(obj))
+        {
+            handleBackward();
+            return true;
+        }
+        else if(evt.target instanceof Button && right.equals(obj))
+        {
+            handleForward();
+            return true;
+        }
+        else if(evt.target instanceof Choice)
+        {
+            handleEnumChanged();
+            return true;
+        }
+        return false;
+    }
+
+    public boolean handleEvent(Event evt)
+    {
+        if (evt.id == Event.KEY_PRESS || evt.id == Event.KEY_ACTION) {
+            if (evt.key == Event.RIGHT || (evt.key == 0x0E && evt.controlDown())) {
+                handleForward();
+                return true;
+            }
+            else if (evt.key == Event.LEFT || (evt.key == 0x10 && evt.controlDown())) {
+                handleBackward();
+                return true;
+            }
+        }
+        else
+        if (evt.id == Event.WINDOW_DESTROY && evt.target == this) {
+            this.hide();
+            this.dispose();
+                if (applet != null) {
+                  applet.demoClosed();
+               } else System.exit(0);
+            return true;
+        }
+        return super.handleEvent(evt);
+    }*/
+
+    public void itemStateChanged(ItemEvent evt)
+    {
+        if (evt.getSource() instanceof Choice) {
+            handleEnumChanged();
+        }
+    }
+
+    public void errorText(String s)
+    {
+       if (DEBUG)
+           System.out.println(s);
+    }
+    
+    protected void processWindowEvent(WindowEvent evt)
+    {
+        if (evt.getID() == WindowEvent.WINDOW_CLOSING && 
+            evt.getWindow() == this) {
+            hide();
+            dispose();
+            if (applet != null) {
+                applet.demoClosed();
+            } else System.exit(0);
+        }
+    }
+    
+    protected void processKeyEvent(KeyEvent evt)
+    {
+        switch (evt.getID()) {
+            case KeyEvent.KEY_PRESSED :
+                if (evt.getKeyCode() == KeyEvent.VK_CONTROL) {
+                    isctrldown_ = true;
+                }
+                break;
+            case KeyEvent.KEY_RELEASED :
+                int key = evt.getKeyCode();
+                System.out.println("control down " + isctrldown_);
+                System.out.println("key " + key);
+                if (key == KeyEvent.VK_RIGHT || 
+                    (key == KeyEvent.VK_N && isctrldown_)) {
+                    handleForward();
+                }
+                else 
+                if (key == KeyEvent.VK_LEFT || 
+                    (key == KeyEvent.VK_P && isctrldown_)) {
+                    handleBackward();
+                }
+                isctrldown_ = false;
+                break;
+        }
+    }
+}
diff --git a/src/com/ibm/demo/rbbi/TextBoundDemo.java b/src/com/ibm/demo/rbbi/TextBoundDemo.java
new file mode 100755
index 0000000..4bfdc89
--- /dev/null
+++ b/src/com/ibm/demo/rbbi/TextBoundDemo.java
@@ -0,0 +1,432 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/rbbi/Attic/TextBoundDemo.java,v $ 
+ * $Date: 2001/10/30 02:42:48 $ 
+ * $Revision: 1.5 $
+ *
+ *****************************************************************************************
+ */
+package com.ibm.demo.rbbi;
+
+import com.ibm.demo.*;
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.ItemListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowEvent;
+import javax.swing.JTextArea;
+import javax.swing.JScrollPane;
+import javax.swing.BorderFactory;
+import java.util.*;
+
+import com.ibm.text.BreakIterator;
+
+public class TextBoundDemo extends DemoApplet
+{
+    public static void main(String argv[]) {
+        new TextBoundDemo().showDemo();
+    }
+
+    public Frame createDemoFrame(DemoApplet applet) {
+        return new TextBoundFrame(applet);
+    }
+}
+
+
+
+class TextBoundFrame extends Frame implements ItemListener
+{
+    private static final String creditString =
+        "v1.1a9, Demo";
+
+    private static final int FIELD_COLUMNS = 45;
+    private static final Font choiceFont = null;
+    private static final boolean DEBUG = false;
+    private DemoApplet applet;
+
+    final String right = "-->";
+    final String left = "<--";
+
+    private BreakIterator enum;
+    private boolean isctrldown_ = false;
+
+JTextArea text;
+//    TextArea text;
+    Choice bound;
+
+    public TextBoundFrame(DemoApplet applet)
+    {
+        this.applet = applet;
+        init();
+        start();
+    }
+
+
+
+    public void run()
+    {
+        /*
+        while (true) {
+            try {
+                checkChange();
+                Thread.sleep(250);
+            }
+            catch (InterruptedException e) {
+            }
+            catch (Exception e) {
+            }
+            catch (Throwable e) {
+            }
+        }
+        */
+    }
+
+    int s, e;
+    int ts, te;
+
+    public void checkChange()
+    {
+//        System.out.println("checkChange...");
+        if ((text.getSelectionStart() & 0x7FFF) != ts ||
+            (text.getSelectionEnd() & 0x7FFF) != te) {
+
+            // not used int tempS = text.getSelectionStart() & 0x7FFF;
+            // not used int tempE = text.getSelectionEnd() & 0x7FFF;
+
+//          System.out.println(">");
+//          select(0, 0);
+//          select(tempS, tempE);
+            //select(tempS - (ts - s), tempE - (te - e));
+//          System.out.println("<");
+
+
+//          if (s != ts || e != te) System.out.println("     s("+s+") ts("+ts+") e("+e+") te("+te+")");
+//          if (tempS != ts || tempE != te) System.out.println(">s("+s+") tempS("+tempS+") e("+e+") tempE("+tempE+")");
+//          select(s - (ts - s), e - (te - e));
+//          if (tempS != ts || tempE != te) System.out.println("s("+s+") tempS("+tempS+") e("+e+") tempE("+tempE+")");
+
+//          System.out.println("lkdslksj");
+        }
+    }
+
+    public void select(int sIn, int eIn)
+    {
+        s = sIn;
+        e = eIn;
+        text.select(s, e);
+        ts = text.getSelectionStart() & 0x7FFF;
+        te = text.getSelectionEnd() & 0x7FFF;
+//        if (s != ts || e != te) {
+//            System.out.println(">s("+s+") ts("+ts+") e("+e+") te("+te+")");
+//            System.out.println("   "+(ts-s)+","+(te-e));
+//        }
+    }
+
+    public int getSelectionStart()
+    {
+        checkChange();
+//      return s;
+        return text.getSelectionStart() & 0x7FFF;
+    }
+
+
+    public int getSelectionEnd()
+    {
+        checkChange();
+//      return e;
+        return text.getSelectionEnd() & 0x7FFF;
+    }
+
+    public final synchronized void selectRange(int s, int e)
+    {
+        try {
+            //if (getSelectionStart() != s || getSelectionEnd() != e) {
+                //text.select(s, e);
+                select(s,e);
+            //}
+//          if (getSelectionStart() != s || getSelectionEnd() != e) {
+//              System.out.println("AGH! select("+s+","+e+") -> ("+
+//              getSelectionStart()+","+getSelectionEnd()+")");
+//              text.select(s - (getSelectionStart() - s), e - (getSelectionEnd() - e));
+//          }
+        } catch (Exception exp) {
+            errorText(exp.toString());
+        }
+    }
+
+
+
+    public void init()
+    {
+        buildGUI();
+    }
+
+
+    public void start()
+    {
+    }
+
+
+    void addWithFont(Container container, Component foo, Font font) {
+        if (font != null)
+            foo.setFont(font);
+        container.add(foo);
+    }
+
+
+
+   public void buildGUI()
+    {
+        setBackground(DemoUtility.bgColor);
+        setLayout(new BorderLayout());
+
+       Panel topPanel = new Panel();
+
+            Label titleLabel =
+                new Label("Text Boundary Demo", Label.CENTER);
+            titleLabel.setFont(DemoUtility.titleFont);
+            topPanel.add(titleLabel);
+
+            //Label demo=new Label(creditString, Label.CENTER);
+            //demo.setFont(DemoUtility.creditFont);
+            //topPanel.add(demo);
+
+            Panel choicePanel = new Panel();
+
+            Label demo1=new Label("Boundaries", Label.LEFT);
+            demo1.setFont(DemoUtility.labelFont);
+            choicePanel.add(demo1);
+
+            bound = new Choice();
+                bound.setBackground(DemoUtility.choiceColor);
+            bound.addItem("Sentence");
+            bound.addItem("Line Break");
+            bound.addItem("Word");
+            bound.addItem("Char");
+            bound.addItemListener(this);
+            if (choiceFont != null)
+                bound.setFont(choiceFont);
+
+            choicePanel.add(bound);
+            topPanel.add(choicePanel);
+
+            DemoUtility.fixGrid(topPanel,1);
+
+
+        add("North", topPanel);
+
+
+            int ROWS = 15;
+            int COLUMNS = 50;
+//            text = new TextArea(getInitialText(), ROWS, COLUMNS);
+text = new JTextArea(getInitialText(), ROWS, COLUMNS);
+text.setLineWrap(true);
+text.setWrapStyleWord(true);
+            text.setEditable(true);
+            text.selectAll();
+            text.setFont(DemoUtility.editFont);
+            text.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
+
+        add("Center", new JScrollPane(text, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+                        JScrollPane.HORIZONTAL_SCROLLBAR_NEVER));
+
+        Panel copyrightPanel = new Panel();
+        addWithFont (copyrightPanel,
+            new Label(DemoUtility.copyright1, Label.LEFT),DemoUtility.creditFont);
+        addWithFont (copyrightPanel,
+            new Label(DemoUtility.copyright2, Label.LEFT),DemoUtility.creditFont);
+        DemoUtility.fixGrid(copyrightPanel,1);
+        add("South", copyrightPanel);
+
+        //layout();
+        handleEnumChanged();
+        
+        enableEvents(WindowEvent.WINDOW_CLOSING);
+        enableEvents(KeyEvent.KEY_PRESSED);
+        enableEvents(KeyEvent.KEY_RELEASED);
+
+        // (new Thread(this)).start();
+    }
+
+
+
+    public String getInitialText()
+    {
+        return
+    /*
+            "\"This is a sentence.\" This is not.\" \"because. And go. " +
+            "This is a simple 012.566,5 sample sentence. \n"+
+            "It does not have to make any sense as you can see. \n"+
+            "Nel mezzo del cammin di nostra vita, mi ritrovai in "+
+                "una selva oscura. \n"+
+            "Che la dritta via aveo smarrita. \n"+
+            "He said, that I said, that you said!! \n"+
+            "Don't rock the boat.\n\n"+
+            "Because I am the daddy, that is why. \n"+
+            "Not on my time (el timo.)! \n"+
+            "Tab\tTab\rTab\tWow."+
+            "So what!!\n\n"+
+            "Is this a question???  " +
+            "I wonder...Hmm.\n" +
+            "Harris thumbed down several, including \"Away We Go\" "+
+                "(which became the huge success Oklahoma!). \n"+
+            "One species, B. anthracis, is highly virulent.\n"+
+            "Wolf said about Sounder: \"Beautifully thought-out and "+
+                "directed.\"\n"+
+            "Have you ever said, \"This is where I shall live\"? \n"+
+            "He 1000,233,456.000 answered, \"You may not!\" \n"+
+            "Another popular saying is: \"How do you do?\". \n"+
+            "What is the proper use of the abbreviation pp.? \n"+
+            "Yes, I am 1,23.322% definatelly 12\" tall!!";
+    */
+            "(\"This is a complete sentence.\") This is (\"not.\") also.  "
+            +"An abbreviation in the middle, etc. and one at the end, etc. "+
+                "This "
+            +"is a simple sample 012.566,5 sentence. It doesn't "
+            +"have to make any sense, as you can see. Nel mezzo del  c"
+            +"ammin di nostra vita, mi ritrovai in una selva oscura. Che "
+            +"la dritta via aveo smarrita. Not on my time (el timo.)! And "
+            +"tabulated columns: \tCol1\tCol2\t3,456%.\t "
+            +"Is this a question???  I wonder... Hmm. Harris thumbed "
+            +"down several, including \"Away We Go\" (which became the  "
+            +"huge success Oklahoma!). One species, B. anthracis, is  "
+            +"highly virulent. Wolf said about Sounder: \"Beautifully  "
+            +"thought-out and directed.\" Have you ever said, \"This is "+
+                "where I "
+            +"shall live\"? He said 1000,233,456.000 and answered, \"You "+
+                "may not!\"  "
+            +"Another popular saying is: \"How do you do?\". What is the  "
+            +"proper use of the abbreviation pp.? Yes, I am 12\' 3\" tall!!";
+    }
+
+
+    public void handleEnumChanged()
+    {
+        String s = bound.getSelectedItem();
+        if (s.equals("Char")) {
+            errorText("getCharacterInstance");
+            enum = BreakIterator.getCharacterInstance();
+        }
+        else if (s.equals("Word")) {
+            errorText("tWordBreak");
+            enum = BreakIterator.getWordInstance();
+        }
+        else if (s.equals("Line Break")) {
+            errorText("getLineInstance");
+            enum = BreakIterator.getLineInstance();
+        }
+        else /* if (s.equals("Sentence")) */ {
+            errorText("getSentenceInstance");
+            enum = BreakIterator.getSentenceInstance();
+        }
+        enum.setText(text.getText());
+        selectRange(0, 0);
+        //text.select(0,0);
+    }
+
+    public void handleForward()
+    {
+        try {
+//          System.out.println("entering handleForward");
+            enum.setText(text.getText());
+            int oldStart = getSelectionStart();
+            int oldEnd = getSelectionEnd();
+
+//          System.out.println("handleForward: oldStart=" + oldStart + ", oldEnd=" + oldEnd);
+
+            if (oldEnd < 1) {
+                selectRange(0, enum.following(0));
+            }
+            else {
+                int s = enum.following(oldEnd-1);
+                int e = enum.next();
+                if (e == -1) {
+                    e = s;
+                }
+                selectRange(s, e);
+            }
+            //text.select(s, e);
+            errorText("<" + oldStart + "," + oldEnd + "> -> <" +
+                s + "," + e + ">");
+        }
+        catch (Exception exp) {
+            errorText(exp.toString());
+        }
+    }
+
+    public void handleBackward()
+    {
+        try {
+            enum.setText(text.getText());
+            int oldStart = getSelectionStart();
+            int oldEnd = getSelectionEnd();
+            if (oldStart < 1) {
+                selectRange(0, 0);
+            }
+            else {
+                int e = enum.following(oldStart-1);
+                int s = enum.previous();
+                selectRange(s, e);
+            }
+            //text.select(s, e);
+            errorText("<" + oldStart + "," + oldEnd + "> -> <" + s + "," + e + ">");
+        }
+        catch (Exception exp) {
+            errorText(exp.toString());
+        }
+    }
+
+    public void itemStateChanged(ItemEvent evt)
+    {
+        if (evt.getSource() instanceof Choice) {
+            handleEnumChanged();
+        }
+    }
+
+    public void errorText(String s)
+    {
+       if (DEBUG)
+           System.out.println(s);
+    }
+    
+    protected void processWindowEvent(WindowEvent evt)
+    {
+        if (evt.getID() == WindowEvent.WINDOW_CLOSING && 
+            evt.getWindow() == this) {
+            hide();
+            dispose();
+            if (applet != null) {
+                applet.demoClosed();
+            } else System.exit(0);
+        }
+    }
+    
+    protected void processKeyEvent(KeyEvent evt)
+    {
+        switch (evt.getID()) {
+            case KeyEvent.KEY_PRESSED :
+                if (evt.getKeyCode() == KeyEvent.VK_CONTROL) {
+                    isctrldown_ = true;
+                }
+                break;
+            case KeyEvent.KEY_RELEASED :
+                int key = evt.getKeyCode();
+                if (key == KeyEvent.VK_RIGHT || 
+                    (key == KeyEvent.VK_N && isctrldown_)) {
+                    handleForward();
+                }
+                else 
+                if (key == KeyEvent.VK_LEFT || 
+                    (key == KeyEvent.VK_P && isctrldown_)) {
+                    handleBackward();
+                }
+                isctrldown_ = false;
+                break;
+        }
+    }
+}
diff --git a/src/com/ibm/demo/rbbi/package.html b/src/com/ibm/demo/rbbi/package.html
new file mode 100755
index 0000000..d5eb46a
--- /dev/null
+++ b/src/com/ibm/demo/rbbi/package.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--  Copyright (C) 2000, International Business Machines Corporation and
+  others. All Rights Reserved.
+
+  $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/rbbi/Attic/package.html,v $
+  $Revision: 1.1 $
+  $Date: 2000/03/15 17:43:53 $
+-->
+</head>
+<body bgcolor="white">
+RuleBasedBreakIterator and DictionaryBasedBreakIterator demo applications.
+</body>
+</html>
\ No newline at end of file
diff --git a/src/com/ibm/demo/rbnf/RbnfDemo.java b/src/com/ibm/demo/rbnf/RbnfDemo.java
new file mode 100755
index 0000000..e78295a
--- /dev/null
+++ b/src/com/ibm/demo/rbnf/RbnfDemo.java
@@ -0,0 +1,533 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/rbnf/Attic/RbnfDemo.java,v $ 
+ * $Date: 2000/03/10 03:47:43 $ 
+ * $Revision: 1.2 $
+ *
+ *****************************************************************************************
+ */
+package com.ibm.demo.rbnf;
+
+import com.ibm.demo.*;
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.*;
+import java.text.DecimalFormat;
+import java.text.BreakIterator;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+import com.ibm.text.RuleBasedNumberFormat;
+
+public class RbnfDemo extends DemoApplet {
+    /**
+     * Puts a copyright in the .class file
+     */
+    private static final String copyrightNotice
+        = "Copyright \u00a91997-1998 IBM Corp.  All rights reserved.";
+
+    /*
+     * code to run the demo as an application
+     */
+    public static void main(String[] argv) {
+    	new RbnfDemo().showDemo();
+    }
+
+    protected Dimension getDefaultFrameSize(DemoApplet applet, Frame f) {
+    	return new Dimension(430,270);
+    }
+
+    protected Frame createDemoFrame(DemoApplet applet) {
+        final Frame window = new Frame("Number Spellout Demo");
+        window.setSize(800, 600);
+        window.setLayout(new BorderLayout());
+
+        Panel mainPanel = new Panel();
+        mainPanel.setLayout(new GridLayout(1,2));
+
+        commentaryField = new TextArea("", 0, 0, TextArea.SCROLLBARS_VERTICAL_ONLY);
+        commentaryField.setSize(800, 50);
+        commentaryField.setText(RbnfSampleRuleSets.sampleRuleSetCommentary[0]);
+        commentaryField.setEditable(false);
+        commentaryField.setFont(new Font("Helvetica", Font.PLAIN, 14));
+
+        spelloutFormatter = new RuleBasedNumberFormat(RbnfSampleRuleSets.usEnglish, Locale.US);
+        spelloutFormatter.setLenientParseMode(lenientParse);
+        populateRuleSetMenu();
+        numberFormatter = new DecimalFormat("#,##0.##########");
+        parsePosition = new ParsePosition(0);
+        theNumber = 0;
+
+        numberField = new TextField();
+        numberField.setFont(new Font("Serif", Font.PLAIN, 24));
+        textField = new DemoTextFieldHolder();
+        textField.setFont(new Font("Serif", Font.PLAIN, 24));
+        rulesField = new DemoTextFieldHolder();
+        rulesField.setFont(new Font("Serif", Font.PLAIN, 14));
+        lenientParseButton = new Checkbox("Lenient parse", lenientParse);
+
+        numberField.addTextListener(new TextListener() {
+            public void textValueChanged(TextEvent e) {
+                if (!numberFieldHasFocus)
+                    return;
+
+                String fieldText = ((TextComponent)(e.getSource())).getText();
+                parsePosition.setIndex(0);
+                Number temp = numberFormatter.parse(fieldText, parsePosition);
+                if (temp == null || parsePosition.getIndex() == 0) {
+                    theNumber = 0;
+                    textField.setText("PARSE ERROR");
+                }
+                else {
+                    theNumber = temp.doubleValue();
+                    textField.setText(spelloutFormatter.format(theNumber, ruleSetName));
+                }
+            }
+        } );
+
+        numberField.addFocusListener(new FocusAdapter() {
+            public void focusLost(FocusEvent e) {
+                numberFieldHasFocus = false;
+                numberField.setText(numberFormatter.format(theNumber));
+            }
+
+            public void focusGained(FocusEvent e) {
+                numberFieldHasFocus = true;
+                numberField.selectAll();
+            }
+        } );
+
+        textField.addKeyListener(new KeyAdapter() {
+            public void keyTyped(KeyEvent e) {
+                if (e.getKeyChar() == '\t') {
+                    String fieldText = ((TextComponent)(e.getSource())).getText();
+                    parsePosition.setIndex(0);
+                    theNumber = spelloutFormatter.parse(fieldText, parsePosition)
+                                        .doubleValue();
+                    if (parsePosition.getIndex() == 0) {
+                        theNumber = 0;
+                        numberField.setText("PARSE ERROR");
+                        textField.selectAll();
+                    }
+                    else if (parsePosition.getIndex() < fieldText.length()) {
+                        textField.select(parsePosition.getIndex(), fieldText.length());
+                        numberField.setText(numberFormatter.format(theNumber));
+                    }
+                    else {
+                        textField.selectAll();
+                        numberField.setText(numberFormatter.format(theNumber));
+                    }
+                    e.consume();
+                }
+            }
+        } );
+
+        textField.addFocusListener(new FocusAdapter() {
+            public void focusLost(FocusEvent e) {
+                String fieldText = ((TextComponent)(e.getSource())).getText();
+                parsePosition.setIndex(0);
+                theNumber = spelloutFormatter.parse(fieldText, parsePosition)
+                                .doubleValue();
+                if (parsePosition.getIndex() == 0)
+                    numberField.setText("PARSE ERROR");
+                else
+                    numberField.setText(numberFormatter.format(theNumber));
+                textField.setText(textField.getText()); // textField.repaint() didn't work right
+            }
+
+            public void focusGained(FocusEvent e) {
+                textField.selectAll();
+            }
+        } );
+
+        rulesField.addKeyListener(new KeyAdapter() {
+            public void keyTyped(KeyEvent e) {
+                if (e.getKeyChar() == '\t') {
+                    String fieldText = ((TextComponent)(e.getSource())).getText();
+                    if (formatterMenu.getSelectedItem().equals("Custom") || !fieldText.equals(
+                                    RbnfSampleRuleSets.sampleRuleSets[formatterMenu.getSelectedIndex()])) {
+                        try {
+                            RuleBasedNumberFormat temp = new RuleBasedNumberFormat(fieldText);
+                            temp.setLenientParseMode(lenientParse);
+                            populateRuleSetMenu();
+                            spelloutFormatter = temp;
+                            customRuleSet = fieldText;
+                            formatterMenu.select("Custom");
+                            commentaryField.setText(RbnfSampleRuleSets.
+                                sampleRuleSetCommentary[RbnfSampleRuleSets.
+                                sampleRuleSetCommentary.length - 1]);
+                            redisplay();
+                        }
+                        catch (Exception x) {
+                            textField.setText(x.toString());
+                        }
+                    }
+                    e.consume();
+                }
+            }
+        } );
+
+        rulesField.addFocusListener(new FocusAdapter() {
+            public void focusLost(FocusEvent e) {
+                String fieldText = ((TextComponent)(e.getSource())).getText();
+                if (formatterMenu.getSelectedItem().equals("Custom") || !fieldText.equals(
+                                RbnfSampleRuleSets.sampleRuleSets[formatterMenu.getSelectedIndex()])) {
+                    try {
+                        RuleBasedNumberFormat temp = new RuleBasedNumberFormat(fieldText);
+                        temp.setLenientParseMode(lenientParse);
+                        populateRuleSetMenu();
+                        spelloutFormatter = temp;
+                        customRuleSet = fieldText;
+                        formatterMenu.select("Custom");
+                        redisplay();
+                    }
+                    catch (Exception x) {
+                        textField.setText(x.toString());
+                    }
+                }
+                rulesField.setText(rulesField.getText()); // rulesField.repaint() didn't work right
+            }
+        } );
+
+        lenientParseButton.addItemListener(new ItemListener() {
+            public void itemStateChanged(ItemEvent e) {
+                lenientParse = lenientParseButton.getState();
+                spelloutFormatter.setLenientParseMode(lenientParse);
+            }
+        } );
+
+        numberField.setText(numberFormatter.format(theNumber));
+        numberField.selectAll();
+        textField.setText(spelloutFormatter.format(theNumber, ruleSetName));
+
+        Panel leftPanel = new Panel();
+        leftPanel.setLayout(new BorderLayout());
+        Panel panel = new Panel();
+        panel.setLayout(new BorderLayout());
+        Panel panel1 = new Panel();
+        panel1.setLayout(new GridLayout(3, 1));
+        panel1.add(new Panel());
+        panel1.add(numberField, "Center");
+        panel1.add(lenientParseButton);
+        panel.add(panel1, "Center");
+        Panel panel2 = new Panel();
+        panel2.setLayout(new GridLayout(3, 3));
+        Button button = new Button("+100");
+        button.addActionListener( new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                roll(100);
+            }
+        } );
+        panel2.add(button);
+        button = new Button("+10");
+        button.addActionListener( new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                roll(10);
+            }
+        } );
+        panel2.add(button);
+        button = new Button("+1");
+        button.addActionListener( new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                roll(1);
+            }
+        } );
+        panel2.add(button);
+        button = new Button("<");
+        button.addActionListener( new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                theNumber *= 10;
+                redisplay();
+            }
+        } );
+        panel2.add(button);
+        panel2.add(new Panel());
+        button = new Button(">");
+        button.addActionListener( new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                theNumber /= 10;
+                redisplay();
+            }
+        } );
+        panel2.add(button);
+        button = new Button("-100");
+        button.addActionListener( new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                roll(-100);
+            }
+        } );
+        panel2.add(button);
+        button = new Button("-10");
+        button.addActionListener( new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                roll(-10);
+            }
+        } );
+        panel2.add(button);
+        button = new Button("-1");
+        button.addActionListener( new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                roll(-1);
+            }
+        } );
+        panel2.add(button);
+        panel.add(panel2, "East");
+        leftPanel.add(panel, "North");
+        leftPanel.add(textField, "Center");
+
+        Panel rightPanel = new Panel();
+        rightPanel.setLayout(new BorderLayout());
+        formatterMenu = new Choice();
+        for (int i = 0; i < RbnfSampleRuleSets.sampleRuleSetNames.length; i++)
+            formatterMenu.addItem(RbnfSampleRuleSets.sampleRuleSetNames[i]);
+        formatterMenu.addItem("Custom");
+        formatterMenu.addItemListener(new ItemListener() {
+            public void itemStateChanged(ItemEvent e) {
+                Choice source = (Choice)(e.getSource());
+                int item = source.getSelectedIndex();
+                Locale locale = RbnfSampleRuleSets.sampleRuleSetLocales[item];
+
+                commentaryField.setText(RbnfSampleRuleSets.
+                                sampleRuleSetCommentary[item]);
+
+                if (locale != null && (locale.getLanguage().equals("iw")
+                        || locale.getLanguage().equals("ru") || locale.getLanguage().equals("ja")
+                        || locale.getLanguage().equals("el")
+                        || locale.getLanguage().equals("zh"))) {
+                    textField.togglePanes(false);
+                    rulesField.togglePanes(false);
+                }
+                else {
+                    textField.togglePanes(true);
+                    rulesField.togglePanes(true);
+                }
+
+                makeNewSpelloutFormatter();
+                redisplay();
+            }
+        } );
+
+        ruleSetMenu = new Choice();
+        populateRuleSetMenu();
+
+        ruleSetMenu.addItemListener(new ItemListener() {
+            public void itemStateChanged(ItemEvent e) {
+                ruleSetName = ruleSetMenu.getSelectedItem();
+                redisplay();
+            }
+        } );
+
+        Panel menuPanel = new Panel();
+        menuPanel.setLayout(new GridLayout(1, 2));
+        menuPanel.add(formatterMenu);
+        menuPanel.add(ruleSetMenu);
+        rightPanel.add(menuPanel, "North");
+
+        rulesField.setText(RbnfSampleRuleSets.sampleRuleSets[formatterMenu.getSelectedIndex()]);
+        rightPanel.add(rulesField, "Center");
+
+        mainPanel.add(leftPanel);
+        mainPanel.add(rightPanel);
+
+        window.add(mainPanel, "Center");
+        window.add(commentaryField, "South");
+
+        window.doLayout();
+        window.show();
+        return window;
+    }
+
+    void roll(int delta) {
+        theNumber += delta;
+        redisplay();
+    }
+
+    void redisplay() {
+        numberField.setText(numberFormatter.format(theNumber));
+        textField.setText(spelloutFormatter.format(theNumber, ruleSetName));
+    }
+
+    void makeNewSpelloutFormatter() {
+        int item = formatterMenu.getSelectedIndex();
+        String formatterMenuItem = formatterMenu.getSelectedItem();
+
+        if (formatterMenuItem.equals("Custom")) {
+            rulesField.setText(customRuleSet);
+            spelloutFormatter = new RuleBasedNumberFormat(customRuleSet);
+        }
+        else {
+            rulesField.setText(RbnfSampleRuleSets.sampleRuleSets[item]);
+
+            Locale locale = RbnfSampleRuleSets.sampleRuleSetLocales[item];
+            if (locale == null)
+                locale = Locale.getDefault();
+
+            spelloutFormatter = new RuleBasedNumberFormat(RbnfSampleRuleSets.
+                            sampleRuleSets[item], locale);
+        }
+        spelloutFormatter.setLenientParseMode(lenientParse);
+        populateRuleSetMenu();
+    }
+
+    void populateRuleSetMenu() {
+        String[] ruleSetNames = spelloutFormatter.getRuleSetNames();
+
+        if (ruleSetMenu != null) {
+            ruleSetMenu.removeAll();
+            for (int i = 0; i < ruleSetNames.length; i++)
+                ruleSetMenu.addItem(ruleSetNames[i]);
+
+            ruleSetName = ruleSetMenu.getSelectedItem();
+        }
+        else
+            ruleSetName = ruleSetNames[0];
+    }
+
+    private Frame demoWindow = null;
+
+    private TextComponent numberField;
+    private DemoTextFieldHolder textField;
+    private DemoTextFieldHolder rulesField;
+    private TextComponent commentaryField;
+    private Checkbox lenientParseButton;
+
+    private boolean numberFieldHasFocus = true;
+
+    private RuleBasedNumberFormat spelloutFormatter;
+    private DecimalFormat numberFormatter;
+    private ParsePosition parsePosition;
+
+    private boolean lenientParse = true;
+
+    private double theNumber = 0;
+    private boolean canEdit = true;
+
+    private Choice formatterMenu;
+    private Choice ruleSetMenu;
+    private String ruleSetName;
+
+    private String customRuleSet = "NO RULES!";
+}
+
+class DemoTextField extends Component {
+    public DemoTextField() {
+    }
+
+    public void setText(String text) {
+        this.text = text;
+        this.repaint();
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void paint(Graphics g) {
+        Font font = getFont();
+        FontMetrics fm = g.getFontMetrics();
+        g.setFont(font);
+        String text = getText();
+        BreakIterator bi = BreakIterator.getLineInstance();
+        bi.setText(text);
+        int lineHeight = fm.getHeight();
+        int width = getSize().width;
+        int penY = fm.getAscent();
+        int lineStart = 0;
+        int tempLineEnd = bi.first();
+        int lineEnd = 0;
+        int maxLineEnd = 0;
+        totalHeight = 0;
+
+        while (lineStart < text.length()) {
+            maxLineEnd = text.indexOf('\n', lineStart);
+            if (maxLineEnd == -1)
+                maxLineEnd = Integer.MAX_VALUE;
+            while (tempLineEnd != BreakIterator.DONE && fm.stringWidth(text.substring(
+                            lineStart, tempLineEnd)) < width) {
+                lineEnd = tempLineEnd;
+                tempLineEnd = bi.next();
+            }
+            if (lineStart >= lineEnd) {
+                if (tempLineEnd == BreakIterator.DONE)
+                    lineEnd = text.length();
+                else
+                    lineEnd = tempLineEnd;
+            }
+            if (lineEnd > maxLineEnd)
+                lineEnd = maxLineEnd;
+            g.drawString(text.substring(lineStart, lineEnd), 0, penY);
+            penY += lineHeight;
+            totalHeight += lineHeight;
+            lineStart = lineEnd;
+            if (lineStart < text.length() && text.charAt(lineStart) == '\n')
+                ++lineStart;
+        }
+    }
+
+/*
+    public Dimension getPreferredSize() {
+        Dimension size = getParent().getSize();
+        return new Dimension(size.width, totalHeight);
+    }
+*/
+
+    private String text;
+    private int totalHeight;
+}
+
+class DemoTextFieldHolder extends Panel {
+    public DemoTextFieldHolder() {
+        tf1 = new TextArea("", 0, 0, TextArea.SCROLLBARS_VERTICAL_ONLY);
+        tf2 = new DemoTextField();
+        sp = new ScrollPane();
+
+        setLayout(new CardLayout());
+
+        sp.add(tf2, "TextField1");
+        sp.setVisible(false);
+        add(tf1, "TestField2");
+        add(sp, "ScrollPane");
+    }
+
+    public void addFocusListener(FocusListener l) {
+        tf1.addFocusListener(l);
+    }
+
+    public void addKeyListener(KeyListener l) {
+        tf1.addKeyListener(l);
+    }
+
+    public void setText(String text) {
+        tf1.setText(text);
+        tf2.setText(text);
+    }
+
+    public String getText() {
+        return tf1.getText();
+    }
+
+    public void select(int start, int end) {
+        tf1.select(start, end);
+    }
+
+    public void selectAll() {
+        tf1.selectAll();
+    }
+
+    public void togglePanes(boolean canShowRealTextField) {
+        if (canShowRealTextField != showingRealTextField) {
+            CardLayout layout = (CardLayout)(getLayout());
+            layout.next(this);
+            showingRealTextField = canShowRealTextField;
+        }
+    }
+
+    private TextArea tf1 = null;
+    private DemoTextField tf2 = null;
+    private ScrollPane sp = null;
+    private boolean showingRealTextField = true;
+}
diff --git a/src/com/ibm/demo/rbnf/RbnfSampleRuleSets.java b/src/com/ibm/demo/rbnf/RbnfSampleRuleSets.java
new file mode 100755
index 0000000..2294212
--- /dev/null
+++ b/src/com/ibm/demo/rbnf/RbnfSampleRuleSets.java
@@ -0,0 +1,1949 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/rbnf/Attic/RbnfSampleRuleSets.java,v $ 
+ * $Date: 2000/03/10 03:47:44 $ 
+ * $Revision: 1.2 $
+ *
+ *****************************************************************************************
+ */
+package com.ibm.demo.rbnf;
+
+import com.ibm.demo.*;
+import java.util.Locale;
+
+/**
+ * A collection of example rule sets for use with RuleBasedNumberFormat.
+ * These examples are intended to serve both as demonstrations of what can
+ * be done with this framework, and as starting points for designing new
+ * rule sets.
+ *
+ * For those that claim to represent number-spellout rules for languages
+ * other than U.S. English, we make no claims of either accuracy or
+ * completeness.  In fact, we know them to be incomplete, and suspect
+ * most have mistakes in them.  If you see something that you know is wrong,
+ * please tell us!
+ *
+ * @author Richard Gillam
+ * @version $Version$ $Date: 2000/03/10 03:47:44 $
+ */
+public class RbnfSampleRuleSets {
+    /**
+     * Puts a copyright in the .class file
+     */
+    private static final String copyrightNotice
+        = "Copyright \u00a91997-1998 IBM Corp.  All rights reserved.";
+
+    //========================================================================
+    // Spellout rules for various languages
+    //
+    // The following RuleBasedNumberFormat descriptions show the rules for
+    // spelling out numeric values in various languages.  As mentioned
+    // before, we cannot vouch for the accuracy or completeness of this
+    // data, although we believe it's pretty close.  Basically, this
+    // represents one day's worth of Web-surfing.  If you can supply the
+    // missing information in any of these rule sets, or if you find errors,
+    // or if you can supply spellout rules for languages that aren't shown
+    // here, we want to hear from you!
+    //========================================================================
+
+    /**
+     * Spellout rules for U.S. English.  This demonstration version of the
+     * U.S. English spellout rules has four variants: 1) %simplified is a
+     * set of rules showing the simple method of spelling out numbers in
+     * English: 289 is formatted as "two hundred eighty-nine".  2) %alt-teens
+     * is the same as %simplified, except that values between 1,000 and 9,999
+     * whose hundreds place isn't zero are formatted in hundreds.  For example,
+     * 1,983 is formatted as "nineteen hundred eighty-three," and 2,183 is
+     * formatted as "twenty-one hundred eighty-three," but 2,083 is still
+     * formatted as "two thousand eighty-three."  3) %ordinal formats the
+     * values as ordinal numbers in English (e.g., 289 is "two hundred eighty-
+     * ninth").  4) %default uses a more complicated algorithm to format
+     * numbers in a more natural way: 289 is formatted as "two hundred AND
+     * eighty-nine" and commas are inserted between the thousands groups for
+     * values above 100,000.
+     */
+    public static final String usEnglish =
+        // This rule set shows the normal simple formatting rules for English
+        "%simplified:\n"
+               // negative number rule.  This rule is used to format negative
+               // numbers.  The result of formatting the number's absolute
+               // value is placed where the >> is.
+        + "    -x: minus >>;\n"
+               // faction rule.  This rule is used for formatting numbers
+               // with fractional parts.  The result of formatting the
+               // number's integral part is substituted for the <<, and
+               // the result of formatting the number's fractional part
+               // (one digit at a time, e.g., 0.123 is "zero point one two
+               // three") replaces the >>.
+        + "    x.x: << point >>;\n"
+               // the rules for the values from 0 to 19 are simply the
+               // words for those numbers
+        + "    zero; one; two; three; four; five; six; seven; eight; nine;\n"
+        + "    ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
+        + "        seventeen; eighteen; nineteen;\n"
+               // beginning at 20, we use the >> to mark the position where
+               // the result of formatting the number's ones digit.  Thus,
+               // we only need a new rule at every multiple of 10.  Text in
+               // backets is omitted if the value being formatted is an
+               // even multiple of 10.
+        + "    20: twenty[->>];\n"
+        + "    30: thirty[->>];\n"
+        + "    40: forty[->>];\n"
+        + "    50: fifty[->>];\n"
+        + "    60: sixty[->>];\n"
+        + "    70: seventy[->>];\n"
+        + "    80: eighty[->>];\n"
+        + "    90: ninety[->>];\n"
+               // beginning at 100, we can use << to mark the position where
+               // the result of formatting the multiple of 100 is to be
+               // inserted.  Notice also that the meaning of >> has shifted:
+               // here, it refers to both the ones place and the tens place.
+               // The meanings of the << and >> tokens depend on the base value
+               // of the rule.  A rule's divisor is (usually) the highest
+               // power of 10 that is less than or equal to the rule's base
+               // value.  The value being formatted is divided by the rule's
+               // divisor, and the integral quotient is used to get the text
+               // for <<, while the remainder is used to produce the text
+               // for >>.  Again, text in brackets is omitted if the value
+               // being formatted is an even multiple of the rule's divisor
+               // (in this case, an even multiple of 100)
+        + "    100: << hundred[ >>];\n"
+               // The rules for the higher numbers work the same way as the
+               // rule for 100: Again, the << and >> tokens depend on the
+               // rule's divisor, which for all these rules is also the rule's
+               // base value.  To group by thousand, we simply don't have any
+               // rules between 1,000 and 1,000,000.
+        + "    1000: << thousand[ >>];\n"
+        + "    1,000,000: << million[ >>];\n"
+        + "    1,000,000,000: << billion[ >>];\n"
+        + "    1,000,000,000,000: << trillion[ >>];\n"
+               // overflow rule.  This rule specifies that values of a
+               // quadrillion or more are shown in numerals rather than words.
+               // The == token means to format (with new rules) the value
+               // being formatted by this rule and place the result where
+               // the == is.  The #,##0 inside the == signs is a
+               // DecimalFormat pattern.  It specifies that the value should
+               // be formatted with a DecimalFormat object, and that it
+               // should be formatted with no decimal places, at least one
+               // digit, and a thousands separator.
+        + "    1,000,000,000,000,000: =#,##0=;\n"
+
+        // This rule set formats numbers between 1,000 and 9,999 somewhat
+        // differently: If the hundreds digit is not zero, the first two
+        // digits are treated as a number of hundreds.  For example, 2,197
+        // would come out as "twenty-one hundred ninety-seven."
+        + "%alt-teens:\n"
+               // just use %simplified to format values below 1,000
+        + "    =%simplified=;\n"
+               // values between 1,000 and 9,999 are delegated to %%alt-hundreds
+               // for formatting.  The > after "1000" decreases the exponent
+               // of the rule's radix by one, causing the rule's divisor
+               // to be 100 instead of 1,000.  This causes the first TWO
+               // digits of the number, instead of just the first digit,
+               // to be sent to %%alt-hundreds
+        + "    1000>: <%%alt-hundreds<[ >>];\n"
+               // for values of 10,000 and more, we again just use %simplified
+        + "    10,000: =%simplified=;\n"
+        // This rule set uses some obscure voodoo of the description language
+        // to format the first two digits of a value in the thousands.
+        // The rule at 10 formats the first two digits as a multiple of 1,000
+        // and the rule at 11 formats the first two digits as a multiple of
+        // 100.  This works because of something known as the "rollback rule":
+        // if the rule applicable to the value being formatted has two
+        // substitutions, the value being formatted is an even multiple of
+        // the rule's divisor, and the rule's base value ISN'T an even multiple
+        // if the rule's divisor, then the rule that precedes this one in the
+        // list is used instead.  (The [] notation is implemented internally
+        // using this notation: a rule containing [] is split into two rules,
+        // and the right one is chosen using the rollback rule.) In this case,
+        // it means that if the first two digits are an even multiple of 10,
+        // they're formatted with the 10 rule (containing "thousand"), and if
+        // they're not, they're formatted with the 11 rule (containing
+        // "hundred").  %%empty is a hack to cause the rollback rule to be
+        // invoked: it makes the 11 rule have two substitutions, even though
+        // the second substitution (calling %%empty) doesn't actually do
+        // anything.
+        + "%%alt-hundreds:\n"
+        + "    0: SHOULD NEVER GET HERE!;\n"
+        + "    10: <%simplified< thousand;\n"
+        + "    11: =%simplified= hundred>%%empty>;\n"
+        + "%%empty:\n"
+        + "    0:;"
+
+        // this rule set is the same as %simplified, except that it formats
+        // the value as an ordinal number: 234 is formatted as "two hundred
+        // thirty-fourth".  Notice the calls to ^simplified: we have to
+        // call %simplified to avoid getting "second hundred thirty-fourth."
+        + "%ordinal:\n"
+        + "    zeroth; first; second; third; fourth; fifth; sixth; seventh;\n"
+        + "        eighth; ninth;\n"
+        + "    tenth; eleventh; twelfth; thirteenth; fourteenth;\n"
+        + "        fifteenth; sixteenth; seventeenth; eighteenth;\n"
+        + "        nineteenth;\n"
+        + "    twentieth; twenty->>;\n"
+        + "    30: thirtieth; thirty->>;\n"
+        + "    40: fortieth; forty->>;\n"
+        + "    50: fiftieth; fifty->>;\n"
+        + "    60: sixtieth; sixty->>;\n"
+        + "    70: seventieth; seventy->>;\n"
+        + "    80: eightieth; eighty->>;\n"
+        + "    90: ninetieth; ninety->>;\n"
+        + "    100: <%simplified< hundredth; <%simplified< hundred >>;\n"
+        + "    1000: <%simplified< thousandth; <%simplified< thousand >>;\n"
+        + "    1,000,000: <%simplified< millionth; <%simplified< million >>;\n"
+        + "    1,000,000,000: <%simplified< billionth;\n"
+        + "        <%simplified< billion >>;\n"
+        + "    1,000,000,000,000: <%simplified< trillionth;\n"
+        + "        <%simplified< trillion >>;\n"
+        + "    1,000,000,000,000,000: =#,##0=;"
+
+        // %default is a more elaborate form of %simplified;  It is basically
+        // the same, except that it introduces "and" before the ones digit
+        // when appropriate (basically, between the tens and ones digits) and
+        // separates the thousands groups with commas in values over 100,000.
+        + "%default:\n"
+               // negative-number and fraction rules.  These are the same
+               // as those for %simplified, but ave to be stated here too
+               // because this is an entry point
+        + "    -x: minus >>;\n"
+        + "    x.x: << point >>;\n"
+               // just use %simplified for values below 100
+        + "    =%simplified=;\n"
+               // for values from 100 to 9,999 use %%and to decide whether or
+               // not to interpose the "and"
+        + "    100: << hundred[ >%%and>];\n"
+        + "    1000: << thousand[ >%%and>];\n"
+               // for values of 100,000 and up, use %%commas to interpose the
+               // commas in the right places (and also to interpose the "and")
+        + "    100,000>>: << thousand[>%%commas>];\n"
+        + "    1,000,000: << million[>%%commas>];\n"
+        + "    1,000,000,000: << billion[>%%commas>];\n"
+        + "    1,000,000,000,000: << trillion[>%%commas>];\n"
+        + "    1,000,000,000,000,000: =#,##0=;\n"
+        // if the value passed to this rule set is greater than 100, don't
+        // add the "and"; if it's less than 100, add "and" before the last
+        // digits
+        + "%%and:\n"
+        + "    and =%default=;\n"
+        + "    100: =%default=;\n"
+        // this rule set is used to place the commas
+        + "%%commas:\n"
+               // for values below 100, add "and" (the apostrophe at the
+               // beginning is ignored, but causes the space that follows it
+               // to be significant: this is necessary because the rules
+               // calling %%commas don't put a space before it)
+        + "    ' and =%default=;\n"
+               // put a comma after the thousands (or whatever preceded the
+               // hundreds)
+        + "    100: , =%default=;\n"
+               // put a comma after the millions (or whatever precedes the
+               // thousands)
+        + "    1000: , <%default< thousand, >%default>;\n"
+               // and so on...
+        + "    1,000,000: , =%default=;"
+        // %%lenient-parse isn't really a set of number formatting rules;
+        // it's a set of collation rules.  Lenient-parse mode uses a Collator
+        // object to compare fragments of the text being parsed to the text
+        // in the rules, allowing more leeway in the matching text.  This set
+        // of rules tells the formatter to ignore commas when parsing (it
+        // already ignores spaces, which is why we refer to the space; it also
+        // ignores hyphens, making "twenty one" and "twenty-one" parse
+        // identically)
+        + "%%lenient-parse:\n"
+        + "    & ' ' , ',' ;\n";
+
+    /**
+     * Spellout rules for U.K. English.  U.K. English has one significant
+     * difference from U.S. English: the names for values of 1,000,000,000
+     * and higher.  In American English, each successive "-illion" is 1,000
+     * times greater than the preceding one: 1,000,000,000 is "one billion"
+     * and 1,000,000,000,000 is "one trillion."  In British English, each
+     * successive "-illion" is one million times greater than the one before:
+     * "one billion" is 1,000,000,000,000 (or what Americans would call a
+     * "trillion"), and "one trillion" is 1,000,000,000,000,000,000.
+     * 1,000,000,000 in British English is "one thousand million."  (This
+     * value is sometimes called a "milliard," but this word seems to have
+     * fallen into disuse.)
+     */
+    public static final String ukEnglish =
+        "%simplified:\n"
+        + "    -x: minus >>;\n"
+        + "    x.x: << point >>;\n"
+        + "    zero; one; two; three; four; five; six; seven; eight; nine;\n"
+        + "    ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
+        + "        seventeen; eighteen; nineteen;\n"
+        + "    20: twenty[->>];\n"
+        + "    30: thirty[->>];\n"
+        + "    40: forty[->>];\n"
+        + "    50: fifty[->>];\n"
+        + "    60: sixty[->>];\n"
+        + "    70: seventy[->>];\n"
+        + "    80: eighty[->>];\n"
+        + "    90: ninety[->>];\n"
+        + "    100: << hundred[ >>];\n"
+        + "    1000: << thousand[ >>];\n"
+        + "    1,000,000: << million[ >>];\n"
+        + "    1,000,000,000,000: << billion[ >>];\n"
+        + "    1,000,000,000,000,000: =#,##0=;\n"
+        + "%alt-teens:\n"
+        + "    =%simplified=;\n"
+        + "    1000>: <%%alt-hundreds<[ >>];\n"
+        + "    10,000: =%simplified=;\n"
+        + "    1,000,000: << million[ >%simplified>];\n"
+        + "    1,000,000,000,000: << billion[ >%simplified>];\n"
+        + "    1,000,000,000,000,000: =#,##0=;\n"
+        + "%%alt-hundreds:\n"
+        + "    0: SHOULD NEVER GET HERE!;\n"
+        + "    10: <%simplified< thousand;\n"
+        + "    11: =%simplified= hundred>%%empty>;\n"
+        + "%%empty:\n"
+        + "    0:;"
+        + "%ordinal:\n"
+        + "    zeroth; first; second; third; fourth; fifth; sixth; seventh;\n"
+        + "        eighth; ninth;\n"
+        + "    tenth; eleventh; twelfth; thirteenth; fourteenth;\n"
+        + "        fifteenth; sixteenth; seventeenth; eighteenth;\n"
+        + "        nineteenth;\n"
+        + "    twentieth; twenty->>;\n"
+        + "    30: thirtieth; thirty->>;\n"
+        + "    40: fortieth; forty->>;\n"
+        + "    50: fiftieth; fifty->>;\n"
+        + "    60: sixtieth; sixty->>;\n"
+        + "    70: seventieth; seventy->>;\n"
+        + "    80: eightieth; eighty->>;\n"
+        + "    90: ninetieth; ninety->>;\n"
+        + "    100: <%simplified< hundredth; <%simplified< hundred >>;\n"
+        + "    1000: <%simplified< thousandth; <%simplified< thousand >>;\n"
+        + "    1,000,000: <%simplified< millionth; <%simplified< million >>;\n"
+        + "    1,000,000,000,000: <%simplified< billionth;\n"
+        + "        <%simplified< billion >>;\n"
+        + "    1,000,000,000,000,000: =#,##0=;"
+        + "%default:\n"
+        + "    -x: minus >>;\n"
+        + "    x.x: << point >>;\n"
+        + "    =%simplified=;\n"
+        + "    100: << hundred[ >%%and>];\n"
+        + "    1000: << thousand[ >%%and>];\n"
+        + "    100,000>>: << thousand[>%%commas>];\n"
+        + "    1,000,000: << million[>%%commas>];\n"
+        + "    1,000,000,000,000: << billion[>%%commas>];\n"
+        + "    1,000,000,000,000,000: =#,##0=;\n"
+        + "%%and:\n"
+        + "    and =%default=;\n"
+        + "    100: =%default=;\n"
+        + "%%commas:\n"
+        + "    ' and =%default=;\n"
+        + "    100: , =%default=;\n"
+        + "    1000: , <%default< thousand, >%default>;\n"
+        + "    1,000,000: , =%default=;"
+        + "%%lenient-parse:\n"
+        + "    & ' ' , ',' ;\n";
+    // Could someone please correct me if I'm wrong about "milliard" falling
+    // into disuse, or have missed any other details of how large numbers
+    // are rendered.  Also, could someone please provide me with information
+    // on which other English-speaking countries use which system?  Right now,
+    // I'm assuming that the U.S. system is used in Canada and that all the
+    // other English-speaking countries follow the British system.  Can
+    // someone out there confirm this?
+
+    /**
+     * Spellout rules for Spanish.  The Spanish rules are quite similar to
+     * the English rules, but there are some important differences:
+     * First, we have to provide separate rules for most of the twenties
+     * because the ones digit frequently picks up an accent mark that it
+     * doesn't have when standing alone.  Second, each multiple of 100 has
+     * to be specified separately because the multiplier on 100 very often
+     * changes form in the contraction: 500 is "quinientos," not
+     * "cincocientos."  In addition, the word for 100 is "cien" when
+     * standing alone, but changes to "ciento" when followed by more digits.
+     * There also some other differences.
+     */
+    public static final String spanish =
+        // negative-number and fraction rules
+        "-x: menos >>;\n"
+        + "x.x: << punto >>;\n"
+        // words for values from 0 to 19
+        + "cero; uno; dos; tres; cuatro; cinco; seis; siete; ocho; nueve;\n"
+        + "diez; once; doce; trece; catorce; quince; diecis\u00e9is;\n"
+        + "    diecisiete; dieciocho; diecinueve;\n"
+        // words for values from 20 to 29 (necessary because the ones digit
+        // often picks up an accent mark it doesn't have when standing alone)
+        + "veinte; veintiuno; veintid\u00f3s; veintitr\u00e9s; veinticuatro;\n"
+        + "    veinticinco; veintis\u00e9is; veintisiete; veintiocho;\n"
+        + "    veintinueve;\n"
+        // words for multiples of 10 (notice that the tens digit is separated
+        // from the ones digit by the word "y".)
+        + "30: treinta[ y >>];\n"
+        + "40: cuarenta[ y >>];\n"
+        + "50: cincuenta[ y >>];\n"
+        + "60: sesenta[ y >>];\n"
+        + "70: setenta[ y >>];\n"
+        + "80: ochenta[ y >>];\n"
+        + "90: noventa[ y >>];\n"
+        // 100 by itself is "cien," but 100 followed by something is "cineto"
+        + "100: cien;\n"
+        + "101: ciento >>;\n"
+        // words for multiples of 100 (must be stated because they're
+        // rarely simple concatenations)
+        + "200: doscientos[ >>];\n"
+        + "300: trescientos[ >>];\n"
+        + "400: cuatrocientos[ >>];\n"
+        + "500: quinientos[ >>];\n"
+        + "600: seiscientos[ >>];\n"
+        + "700: setecientos[ >>];\n"
+        + "800: ochocientos[ >>];\n"
+        + "900: novecientos[ >>];\n"
+        // for 1,000, the multiplier on "mil" is omitted: 2,000 is "dos mil,"
+        // but 1,000 is just "mil."
+        + "1000: mil[ >>];\n"
+        + "2000: << mil[ >>];\n"
+        // 1,000,000 is "un millon," not "uno millon"
+        + "1,000,000: un mill\u00f3n[ >>];\n"
+        + "2,000,000: << mill\u00f3n[ >>];\n"
+        // overflow rule
+        + "1,000,000,000: =#,##0= (incomplete data);";
+    // The Spanish rules are incomplete.  I'm missing information on negative
+    // numbers and numbers with fractional parts.  I also don't have
+    // information on numbers higher than the millions
+
+    /**
+     * Spellout rules for French.  French adds some interesting quirks of its
+     * own: 1) The word "et" is interposed between the tens and ones digits,
+     * but only if the ones digit if 1: 20 is "vingt," and 2 is "vingt-deux,"
+     * but 21 is "vingt-et-un."  2)  There are no words for 70, 80, or 90.
+     * "quatre-vingts" ("four twenties") is used for 80, and values proceed
+     * by score from 60 to 99 (e.g., 73 is "soixante-treize" ["sixty-thirteen"]).
+     * Numbers from 1,100 to 1,199 are rendered as hundreds rather than
+     * thousands: 1,100 is "onze cents" ("eleven hundred"), rather than
+     * "mille cent" ("one thousand one hundred")
+     */
+    public static final String french =
+        // the main rule set
+        "%main:\n"
+               // negative-number and fraction rules
+        + "    -x: moins >>;\n"
+        + "    x.x: << virgule >>;\n"
+               // words for numbers from 0 to 10
+        + "    z\u00e9ro; un; deux; trois; quatre; cinq; six; sept; huit; neuf;\n"
+        + "    dix; onze; douze; treize; quatorze; quinze; seize;\n"
+        + "        dix-sept; dix-huit; dix-neuf;\n"
+               // ords for the multiples of 10: %%alt-ones inserts "et"
+               // when needed
+        + "    20: vingt[->%%alt-ones>];\n"
+        + "    30: trente[->%%alt-ones>];\n"
+        + "    40: quarante[->%%alt-ones>];\n"
+        + "    50: cinquante[->%%alt-ones>];\n"
+               // rule for 60.  The /20 causes this rule's multiplier to be
+               // 20 rather than 10, allowinhg us to recurse for all values
+               // from 60 to 79...
+        + "    60/20: soixante[->%%alt-ones>];\n"
+               // ...except for 71, which must be special-cased
+        + "    71: soixante et onze;\n"
+               // at 72, we have to repeat the rule for 60 to get us to 79
+        + "    72/20: soixante->%%alt-ones>;\n"
+               // at 80, we state a new rule with the phrase for 80.  Since
+               // it changes form when there's a ones digit, we need a second
+               // rule at 81.  This rule also includes "/20," allowing it to
+               // be used correctly for all values up to 99
+        + "    80: quatre-vingts; 81/20: quatre-vingt->>;\n"
+               // "cent" becomes plural when preceded by a multiplier, and
+               // the multiplier is omitted from the singular form
+        + "    100: cent[ >>];\n"
+        + "    200: << cents[ >>];\n"
+        + "    1000: mille[ >>];\n"
+               // values from 1,100 to 1,199 are rendered as "onze cents..."
+               // instead of "mille cent..."  The > after "1000" decreases
+               // the rule's exponent, causing its multiplier to be 100 instead
+               // of 1,000.  This prevents us from getting "onze cents cent
+               // vingt-deux" ("eleven hundred one hundred twenty-two").
+        + "    1100>: onze cents[ >>];\n"
+               // at 1,200, we go back to formating in thousands, so we
+               // repeat the rule for 1,000
+        + "    1200: mille >>;\n"
+               // at 2,000, the multiplier is added
+        + "    2000: << mille[ >>];\n"
+        + "    1,000,000: << million[ >>];\n"
+        + "    1,000,000,000: << milliarde[ >>];\n"
+        + "    1,000,000,000,000: << billion[ >>];\n"
+        + "    1,000,000,000,000,000: =#,##0=;\n"
+        // %%alt-ones is used to insert "et" when the ones digit is 1
+        + "%%alt-ones:\n"
+        + "    ; et-un; =%main=;";
+
+    /**
+     * Spellout rules for Swiss French.  Swiss French differs from French French
+     * in that it does have words for 70, 80, and 90.  This rule set shows them,
+     * and is simpler as a result.
+     */
+    public static final String swissFrench =
+        "%main:\n"
+        + "    -x: moins >>;\n"
+        + "    x.x: << virgule >>;\n"
+        + "    z\u00e9ro; un; deux; trois; quatre; cinq; six; sept; huit; neuf;\n"
+        + "    dix; onze; douze; treize; quatorze; quinze; seize;\n"
+        + "        dix-sept; dix-huit; dix-neuf;\n"
+        + "    20: vingt[->%%alt-ones>];\n"
+        + "    30: trente[->%%alt-ones>];\n"
+        + "    40: quarante[->%%alt-ones>];\n"
+        + "    50: cinquante[->%%alt-ones>];\n"
+        + "    60: soixante[->%%alt-ones>];\n"
+               // notice new words for 70, 80, and 90
+        + "    70: septante[->%%alt-ones>];\n"
+        + "    80: octante[->%%alt-ones>];\n"
+        + "    90: nonante[->%%alt-ones>];\n"
+        + "    100: cent[ >>];\n"
+        + "    200: << cents[ >>];\n"
+        + "    1000: mille[ >>];\n"
+        + "    1100>: onze cents[ >>];\n"
+        + "    1200: mille >>;\n"
+        + "    2000: << mille[ >>];\n"
+        + "    1,000,000: << million[ >>];\n"
+        + "    1,000,000,000: << milliarde[ >>];\n"
+        + "    1,000,000,000,000: << billion[ >>];\n"
+        + "    1,000,000,000,000,000: =#,##0=;\n"
+        + "%%alt-ones:\n"
+        + "    ; et-un; =%main=;";
+    // I'm not 100% sure about Swiss French.  Is
+    // this correct?  Is "onze cents" commonly used for 1,100 in both France
+    // and Switzerland?  Can someone fill me in on the rules for the other
+    // French-speaking countries?  I've heard conflicting opinions on which
+    // version is used in Canada, and I understand there's an alternate set
+    // of words for 70, 80, and 90 that is used somewhere, but I don't know
+    // what those words are or where they're used.
+
+    /**
+     * Spellout rules for German.  German also adds some interesting
+     * characteristics.  For values below 1,000,000, numbers are customarily
+     * written out as a single word.  And the ones digit PRECEDES the tens
+     * digit (e.g., 23 is "dreiundzwanzig," not "zwanzigunddrei").
+     */
+    public static final String german =
+        // 1 is "eins" when by itself, but turns into "ein" in most
+        // combinations
+        "%alt-ones:\n"
+        + "    null; eins; =%%main=;\n"
+        + "%%main:\n"
+               // words for numbers from 0 to 12.  Notice that the values
+               // from 13 to 19 can derived algorithmically, unlike in most
+               // other languages
+        + "    null; ein; zwei; drei; vier; f\u00fcnf; sechs; sieben; acht; neun;\n"
+        + "    zehn; elf; zw\u00f6lf; >>zehn;\n"
+               // rules for the multiples of 10.  Notice that the ones digit
+               // goes on the front
+        + "    20: [>>und]zwanzig;\n"
+        + "    30: [>>und]drei\u00dfig;\n"
+        + "    40: [>>und]vierzig;\n"
+        + "    50: [>>und]f\u00fcnfzig;\n"
+        + "    60: [>>und]sechzig;\n"
+        + "    70: [>>und]siebzig;\n"
+        + "    80: [>>und]achtzig;\n"
+        + "    90: [>>und]neunzig;\n"
+        + "    100: hundert[>%alt-ones>];\n"
+        + "    200: <<hundert[>%alt-ones>];\n"
+        + "    1000: tausend[>%alt-ones>];\n"
+        + "    2000: <<tausend[>%alt-ones>];\n"
+        + "    1,000,000: eine Million[ >%alt-ones>];\n"
+        + "    2,000,000: << Millionen[ >%alt-ones>];\n"
+        + "    1,000,000,000: eine Milliarde[ >%alt-ones>];\n"
+        + "    2,000,000,000: << Milliarden[ >%alt-ones>];\n"
+        + "    1,000,000,000,000: eine Billion[ >%alt-ones>];\n"
+        + "    2,000,000,000,000: << Billionen[ >%alt-ones>];\n"
+        + "    1,000,000,000,000,000: =#,##0=;";
+    // again, I'm not 100% sure of these rules.  I think both "hundert" and
+    // "einhundert" are correct or 100, but I'm not sure which is preferable
+    // in situations where this framework is likely to be used.  Also, is it
+    // really true that numbers are run together into compound words all the
+    // time?  And again, I'm missing information on negative numbers and
+    // decimas.
+
+    /**
+     * Spellout rules for Italian.  Like German, most Italian numbers are
+     * written as single words.  What makes these rules complicated is the rule
+     * that says that when a word ending in a vowel and a word beginning with
+     * a vowel are combined into a compound, the vowel is dropped from the
+     * end of the first word: 180 is "centottanta," not "centoottanta."
+     * The complexity of this rule set is to produce this behavior.
+     */
+    public static final String italian =
+        // main rule set.  Follows the patterns of the preceding rule sets,
+        // except that the final vowel is omitted from words ending in
+        // vowels when they are followed by another word; instead, we have
+        // separate rule sets that are identical to this one, except that
+        // all the words that don't begin with a vowel have a vowel tacked
+        // onto them at the front.  A word ending in a vowel calls a
+        // substitution that will supply that vowel, unless that vowel is to
+        // be elided.
+        "%main:\n"
+        + "    -x: meno >>;\n"
+        + "    x.x: << virgola >>;\n"
+        + "    zero; uno; due; tre; quattro; cinque; sei; sette; otto;\n"
+        + "        nove;\n"
+        + "    dieci; undici; dodici; tredici; quattordici; quindici; sedici;\n"
+        + "        diciasette; diciotto; diciannove;\n"
+        + "    20: venti; vent>%%with-i>;\n"
+        + "    30: trenta; trent>%%with-i>;\n"
+        + "    40: quaranta; quarant>%%with-a>;\n"
+        + "    50: cinquanta; cinquant>%%with-a>;\n"
+        + "    60: sessanta; sessant>%%with-a>;\n"
+        + "    70: settanta; settant>%%with-a>;\n"
+        + "    80: ottanta; ottant>%%with-a>;\n"
+        + "    90: novanta; novant>%%with-a>;\n"
+        + "    100: cento; cent[>%%with-o>];\n"
+        + "    200: <<cento; <<cent[>%%with-o>];\n"
+        + "    1000: mille; mill[>%%with-i>];\n"
+        + "    2000: <<mila; <<mil[>%%with-a>];\n"
+        + "    100,000>>: <<mila[ >>];\n"
+        + "    1,000,000: =#,##0= (incomplete data);\n"
+        + "%%with-a:\n"
+        + "    azero; uno; adue; atre; aquattro; acinque; asei; asette; otto;\n"
+        + "        anove;\n"
+        + "    adieci; undici; adodici; atredici; aquattordici; aquindici; asedici;\n"
+        + "        adiciasette; adiciotto; adiciannove;\n"
+        + "    20: aventi; avent>%%with-i>;\n"
+        + "    30: atrenta; atrent>%%with-i>;\n"
+        + "    40: aquaranta; aquarant>%%with-a>;\n"
+        + "    50: acinquanta; acinquant>%%with-a>;\n"
+        + "    60: asessanta; asessant>%%with-a>;\n"
+        + "    70: asettanta; asettant>%%with-a>;\n"
+        + "    80: ottanta; ottant>%%with-a>;\n"
+        + "    90: anovanta; anovant>%%with-a>;\n"
+        + "    100: acento; acent[>%%with-o>];\n"
+        + "    200: <%%with-a<cento; <%%with-a<cent[>%%with-o>];\n"
+        + "    1000: amille; amill[>%%with-i>];\n"
+        + "    2000: <%%with-a<mila; <%%with-a<mil[>%%with-a>];\n"
+        + "    100,000: =%main=;\n"
+        + "%%with-i:\n"
+        + "    izero; uno; idue; itre; iquattro; icinque; isei; isette; otto;\n"
+        + "        inove;\n"
+        + "    idieci; undici; idodici; itredici; iquattordici; iquindici; isedici;\n"
+        + "        idiciasette; idiciotto; idiciannove;\n"
+        + "    20: iventi; ivent>%%with-i>;\n"
+        + "    30: itrenta; itrent>%%with-i>;\n"
+        + "    40: iquaranta; iquarant>%%with-a>;\n"
+        + "    50: icinquanta; icinquant>%%with-a>;\n"
+        + "    60: isessanta; isessant>%%with-a>;\n"
+        + "    70: isettanta; isettant>%%with-a>;\n"
+        + "    80: ottanta; ottant>%%with-a>;\n"
+        + "    90: inovanta; inovant>%%with-a>;\n"
+        + "    100: icento; icent[>%%with-o>];\n"
+        + "    200: <%%with-i<cento; <%%with-i<cent[>%%with-o>];\n"
+        + "    1000: imille; imill[>%%with-i>];\n"
+        + "    2000: <%%with-i<mila; <%%with-i<mil[>%%with-a>];\n"
+        + "    100,000: =%main=;\n"
+        + "%%with-o:\n"
+        + "    ozero; uno; odue; otre; oquattro; ocinque; osei; osette; otto;\n"
+        + "        onove;\n"
+        + "    odieci; undici; ododici; otredici; oquattordici; oquindici; osedici;\n"
+        + "        odiciasette; odiciotto; odiciannove;\n"
+        + "    20: oventi; ovent>%%with-i>;\n"
+        + "    30: otrenta; otrent>%%with-i>;\n"
+        + "    40: oquaranta; oquarant>%%with-a>;\n"
+        + "    50: ocinquanta; ocinquant>%%with-a>;\n"
+        + "    60: osessanta; osessant>%%with-a>;\n"
+        + "    70: osettanta; osettant>%%with-a>;\n"
+        + "    80: ottanta; ottant>%%with-a>;\n"
+        + "    90: onovanta; onovant>%%with-a>;\n"
+        + "    100: ocento; ocent[>%%with-o>];\n"
+        + "    200: <%%with-o<cento; <%%with-o<cent[>%%with-o>];\n"
+        + "    1000: omille; omill[>%%with-i>];\n"
+        + "    2000: <%%with-o<mila; <%%with-o<mil[>%%with-a>];\n"
+        + "    100,000: =%main=;\n";
+    // Can someone confirm that I did the vowel-eliding thing right?  I'm
+    // not 100% sure I'm doing it in all the right places, or completely
+    // correctly.  Also, I don't have information for negatives and decimals,
+    // and I lack words fror values from 1,000,000 on up.
+
+    /**
+     * Spellout rules for Swedish.
+     */
+    public static final String swedish =
+        "noll; ett; tv\u00e5; tre; fyra; fem; sex; sjo; \u00e5tta; nio;\n"
+        + "tio; elva; tolv; tretton; fjorton; femton; sexton; sjutton; arton; nitton;\n"
+        + "20: tjugo[>>];\n"
+        + "30: trettio[>>];\n"
+        + "40: fyrtio[>>];\n"
+        + "50: femtio[>>];\n"
+        + "60: sextio[>>];\n"
+        + "70: sjuttio[>>];\n"
+        + "80: \u00e5ttio[>>];\n"
+        + "90: nittio[>>];\n"
+        + "100: hundra[>>];\n"
+        + "200: <<hundra[>>];\n"
+        + "1000: tusen[ >>];\n"
+        + "2000: << tusen[ >>];\n"
+        + "1,000,000: en miljon[ >>];\n"
+        + "2,000,000: << miljon[ >>];\n"
+        + "1,000,000,000: en miljard[ >>];\n"
+        + "2,000,000,000: << miljard[ >>];\n"
+        + "1,000,000,000,000: en biljon[ >>];\n"
+        + "2,000,000,000,000: << biljon[ >>];\n"
+        + "1,000,000,000,000,000: =#,##0=";
+    // can someone supply me with information on negatives and decimals?
+
+    /**
+     * Spellout rules for Dutch.  Notice that in Dutch, as in German,
+     * the ones digit precedes the tens digit.
+     */
+    public static final String dutch =
+        " -x: min >>;\n"
+        + "x.x: << komma >>;\n"
+        + "(zero?); een; twee; drie; vier; vijf; zes; zeven; acht; negen;\n"
+        + "tien; elf; twaalf; dertien; veertien; vijftien; zestien;\n"
+        + "zeventien; achtien; negentien;\n"
+        + "20: [>> en ]twintig;\n"
+        + "30: [>> en ]dertig;\n"
+        + "40: [>> en ]veertig;\n"
+        + "50: [>> en ]vijftig;\n"
+        + "60: [>> en ]zestig;\n"
+        + "70: [>> en ]zeventig;\n"
+        + "80: [>> en ]tachtig;\n"
+        + "90: [>> en ]negentig;\n"
+        + "100: << honderd[ >>];\n"
+        + "1000: << duizend[ >>];\n"
+        + "1,000,000: << miljoen[ >>];\n"
+        + "1,000,000,000: << biljoen[ >>];\n"
+        + "1,000,000,000,000: =#,##0=";
+
+    /**
+     * Spellout rules for Japanese.  In Japanese, there really isn't any
+     * distinction between a number written out in digits and a number
+     * written out in words: the ideographic characters are both digits
+     * and words.  This rule set provides two variants:  %traditional
+     * uses the traditional CJK numerals (which are also used in China
+     * and Korea).  %financial uses alternate ideographs for many numbers
+     * that are harder to alter than the traditional numerals (one could
+     * fairly easily change a one to
+     * a three just by adding two strokes, for example).  This is also done in
+     * the other countries using Chinese idographs, but different ideographs
+     * are used in those places.
+     */
+    public static final String japanese =
+        "%financial:\n"
+        + "    \u96f6; \u58f1; \u5f10; \u53c2; \u56db; \u4f0d; \u516d; \u4e03; \u516b; \u4e5d;\n"
+        + "    \u62fe[>>];\n"
+        + "    20: <<\u62fe[>>];\n"
+        + "    100: <<\u767e[>>];\n"
+        + "    1000: <<\u5343[>>];\n"
+        + "    10,000: <<\u4e07[>>];\n"
+        + "    100,000,000: <<\u5104[>>];\n"
+        + "    1,000,000,000,000: <<\u5146[>>];\n"
+        + "    10,000,000,000,000,000: =#,##0=;\n"
+        + "%traditional:\n"
+        + "    \u96f6; \u4e00; \u4e8c; \u4e09; \u56db; \u4e94; \u516d; \u4e03; \u516b; \u4e5d;\n"
+        + "    \u5341[>>];\n"
+        + "    20: <<\u5341[>>];\n"
+        + "    100: <<\u767e[>>];\n"
+        + "    1000: <<\u5343[>>];\n"
+        + "    10,000: <<\u4e07[>>];\n"
+        + "    100,000,000: <<\u5104[>>];\n"
+        + "    1,000,000,000,000: <<\u5146[>>];\n"
+        + "    10,000,000,000,000,000: =#,##0=;";
+    // Can someone supply me with the right fraud-proof ideographs for
+    // Simplified and Traditional Chinese, and for Korean?  Can someone
+    // supply me with information on negatives and decimals?
+
+    /**
+     * Spellout rules for Greek.  Again in Greek we have to supply the words
+     * for the multiples of 100 because they can't be derived algorithmically.
+     * Also, the tens dgit changes form when followed by a ones digit: an
+     * accent mark disappears from the tens digit and moves to the ones digit.
+     * Therefore, instead of using the [] notation, we actually have to use
+     * two separate rules for each multiple of 10 to show the two forms of
+     * the word.
+     */
+    public static final String greek =
+        "zero (incomplete data); \u03ad\u03bd\u03b1; \u03b4\u03cd\u03bf; \u03b4\u03c1\u03af\u03b1; "
+        + "\u03c4\u03ad\u03c3\u03c3\u03b5\u03c1\u03b1; \u03c0\u03ad\u03bd\u03c4\u03b5; "
+        + "\u03ad\u03be\u03b9; \u03b5\u03c0\u03c4\u03ac; \u03bf\u03ba\u03c4\u03ce; "
+        + "\u03b5\u03bd\u03bd\u03ad\u03b1;\n"
+        + "10: \u03b4\u03ad\u03ba\u03b1; "
+        + "\u03ad\u03bd\u03b4\u03b5\u03ba\u03b1; \u03b4\u03ce\u03b4\u03b5\u03ba\u03b1; "
+        + "\u03b4\u03b5\u03ba\u03b1>>;\n"
+        + "20: \u03b5\u03af\u03ba\u03bf\u03c3\u03b9; \u03b5\u03b9\u03ba\u03bf\u03c3\u03b9>>;\n"
+        + "30: \u03c4\u03c1\u03b9\u03ac\u03bd\u03c4\u03b1; \u03c4\u03c1\u03b9\u03b1\u03bd\u03c4\u03b1>>;\n"
+        + "40: \u03c3\u03b1\u03c1\u03ac\u03bd\u03c4\u03b1; \u03c3\u03b1\u03c1\u03b1\u03bd\u03c4\u03b1>>;\n"
+        + "50: \u03c0\u03b5\u03bd\u03ae\u03bd\u03c4\u03b1; \u03c0\u03b5\u03bd\u03b7\u03bd\u03c4\u03b1>>;\n"
+        + "60: \u03b5\u03be\u03ae\u03bd\u03c4\u03b1; \u03b5\u03be\u03b7\u03bd\u03c4\u03b1>>;\n"
+        + "70: \u03b5\u03b2\u03b4\u03bf\u03bc\u03ae\u03bd\u03c4\u03b1; "
+        + "\u03b5\u03b2\u03b4\u03bf\u03bc\u03b7\u03bd\u03c4\u03b1>>;\n"
+        + "80: \u03bf\u03b3\u03b4\u03cc\u03bd\u03c4\u03b1; \u03bf\u03b3\u03b4\u03bf\u03bd\u03c4\u03b1>>;\n"
+        + "90: \u03b5\u03bd\u03bd\u03b5\u03bd\u03ae\u03bd\u03c4\u03b1; "
+        + "\u03b5\u03bd\u03bd\u03b5\u03bd\u03b7\u03bd\u03c4\u03b1>>;\n"
+        + "100: \u03b5\u03ba\u03b1\u03c4\u03cc[\u03bd >>];\n"
+        + "200: \u03b4\u03b9\u03b1\u03ba\u03cc\u03c3\u03b9\u03b1[ >>];\n"
+        + "300: \u03c4\u03c1\u03b9\u03b1\u03ba\u03cc\u03c3\u03b9\u03b1[ >>];\n"
+        + "400: \u03c4\u03b5\u03c4\u03c1\u03b1\u03ba\u03cc\u03c3\u03b9\u03b1[ >>];\n"
+        + "500: \u03c0\u03b5\u03bd\u03c4\u03b1\u03ba\u03cc\u03c3\u03b9\u03b1[ >>];\n"
+        + "600: \u03b5\u03be\u03b1\u03ba\u03cc\u03c3\u03b9\u03b1[ >>];\n"
+        + "700: \u03b5\u03c0\u03c4\u03b1\u03ba\u03cc\u03c3\u03b9\u03b1[ >>];\n"
+        + "800: \u03bf\u03ba\u03c4\u03b1\u03ba\u03cc\u03c3\u03b9\u03b1[ >>];\n"
+        + "900: \u03b5\u03bd\u03bd\u03b9\u03b1\u03ba\u03cc\u03c3\u03b9\u03b1[ >>];\n"
+        + "1000: \u03c7\u03af\u03bb\u03b9\u03b1[ >>];\n"
+        + "2000: << \u03c7\u03af\u03bb\u03b9\u03b1[ >>];\n"
+        + "1,000,000: << \u03b5\u03ba\u03b1\u03c4\u03bf\u03bc\u03bc\u03b9\u03cc\u03c1\u03b9\u03bf[ >>];\n"
+        + "1,000,000,000: << \u03b4\u03b9\u03c3\u03b5\u03ba\u03b1\u03c4\u03bf\u03bc\u03bc\u03b9\u03cc\u03c1\u03b9\u03bf[ >>];\n"
+        + "1,000,000,000,000: =#,##0=";
+    // Can someone supply me with information on negatives and decimals?
+    // I'm also missing the word for zero.  Can someone clue me in?
+
+    /**
+     * Spellout rules for Russian.
+     */
+    public static final String russian =
+        "\u043d\u043e\u043b\u044c; \u043e\u0434\u0438\u043d; \u0434\u0432\u0430; \u0442\u0440\u0438; "
+        + "\u0447\u0435\u0442\u044b\u0440\u0435; \u043f\u044f\u0442; \u0448\u0435\u0441\u0442; "
+        + "\u0441\u0435\u043c\u044c; \u0432\u043e\u0441\u0435\u043c\u044c; \u0434\u0435\u0432\u044f\u0442;\n"
+        + "10: \u0434\u0435\u0441\u044f\u0442; "
+        + "\u043e\u0434\u0438\u043d\u043d\u0430\u0434\u0446\u0430\u0442\u044c;\n"
+        + "\u0434\u0432\u0435\u043d\u043d\u0430\u0434\u0446\u0430\u0442\u044c; "
+        + "\u0442\u0440\u0438\u043d\u0430\u0434\u0446\u0430\u0442\u044c; "
+        + "\u0447\u0435\u0442\u044b\u0440\u043d\u0430\u0434\u0446\u0430\u0442\u044c;\n"
+        + "15: \u043f\u044f\u0442\u043d\u0430\u0434\u0446\u0430\u0442\u044c; "
+        + "\u0448\u0435\u0441\u0442\u043d\u0430\u0434\u0446\u0430\u0442\u044c; "
+        + "\u0441\u0435\u043c\u043d\u0430\u0434\u0446\u0430\u0442\u044c; "
+        + "\u0432\u043e\u0441\u0435\u043c\u043d\u0430\u0434\u0446\u0430\u0442\u044c; "
+        + "\u0434\u0435\u0432\u044f\u0442\u043d\u0430\u0434\u0446\u0430\u0442\u044c;\n"
+        + "20: \u0434\u0432\u0430\u0434\u0446\u0430\u0442\u044c[ >>];\n"
+        + "30: \u0442\u0440\u043b\u0434\u0446\u0430\u0442\u044c[ >>];\n"
+        + "40: \u0441\u043e\u0440\u043e\u043a[ >>];\n"
+        + "50: \u043f\u044f\u0442\u044c\u0434\u0435\u0441\u044f\u0442[ >>];\n"
+        + "60: \u0448\u0435\u0441\u0442\u044c\u0434\u0435\u0441\u044f\u0442[ >>];\n"
+        + "70: \u0441\u0435\u043c\u044c\u0434\u0435\u0441\u044f\u0442[ >>];\n"
+        + "80: \u0432\u043e\u0441\u0435\u043c\u044c\u0434\u0435\u0441\u044f\u0442[ >>];\n"
+        + "90: \u0434\u0435\u0432\u044f\u043d\u043e\u0441\u0442\u043e[ >>];\n"
+        + "100: \u0441\u0442\u043e[ >>];\n"
+        + "200: << \u0441\u0442\u043e[ >>];\n"
+        + "1000: \u0442\u044b\u0441\u044f\u0447\u0430[ >>];\n"
+        + "2000: << \u0442\u044b\u0441\u044f\u0447\u0430[ >>];\n"
+        + "1,000,000: \u043c\u0438\u043b\u043b\u0438\u043e\u043d[ >>];\n"
+        + "2,000,000: << \u043c\u0438\u043b\u043b\u0438\u043e\u043d[ >>];\n"
+        + "1,000,000,000: =#,##0=;";
+    // Can someone supply me with information on negatives and decimals?
+    // How about words for billions and trillions?
+
+    /**
+     * Spellout rules for Hebrew.  Hebrew actually has inflected forms for
+     * most of the lower-order numbers.  The masculine forms are shown
+     * here.
+     */
+    public static final String hebrew =
+        "zero (incomplete data); \u05d0\u05d4\u05d3; \u05e9\u05d2\u05d9\u05d9\u05dd; \u05e9\u05dc\u05d5\u05e9\u05d4;\n"
+        + "4: \u05d0\u05d3\u05d1\u05e6\u05d4; \u05d7\u05d2\u05d5\u05d9\u05e9\u05d4; \u05e9\u05e9\u05d4;\n"
+        + "7: \u05e9\u05d1\u05e6\u05d4; \u05e9\u05de\u05d5\u05d2\u05d4; \u05ea\u05e9\u05e6\u05d4;\n"
+        + "10: \u05e6\u05e9\u05d3\u05d4[ >>];\n"
+        + "20: \u05e6\u05e9\u05d3\u05d9\u05dd[ >>];\n"
+        + "30: \u05e9\u05dc\u05d5\u05e9\u05d9\u05dd[ >>];\n"
+        + "40: \u05d0\u05d3\u05d1\u05e6\u05d9\u05dd[ >>];\n"
+        + "50: \u05d7\u05de\u05d9\u05e9\u05d9\u05dd[ >>];\n"
+        + "60: \u05e9\u05e9\u05d9\u05dd[ >>];\n"
+        + "70: \u05e9\u05d1\u05e6\u05d9\u05dd[ >>];\n"
+        + "80: \u05e9\u05de\u05d5\u05d2\u05d9\u05dd[ >>];\n"
+        + "90: \u05ea\u05e9\u05e6\u05d9\u05dd[ >>];\n"
+        + "100: \u05de\u05d0\u05d4[ >>];\n"
+        + "200: << \u05de\u05d0\u05d4[ >>];\n"
+        + "1000: \u05d0\u05dc\u05e3[ >>];\n"
+        + "2000: << \u05d0\u05dc\u05e3[ >>];\n"
+        + "1,000,000: =#,##0= (incomplete data);";
+    // This data is woefully incomplete.  Can someone fill me in on the
+    // various inflected forms of the numbers, which seem to be necessary
+    // to do Hebrew correctly?  Can somone supply me with data for values
+    // from 1,000,000 on up?  What about the word for zero?  What about
+    // information on negatives and decimals?
+
+    //========================================================================
+    // Simple examples
+    //========================================================================
+
+    /**
+     * This rule set adds an English ordinal abbreviation to the end of a
+     * number.  For example, 2 is formatted as "2nd".  Parsing doesn't work with
+     * this rule set.  To parse, use DecimalFormat on the numeral.
+     */
+    public static final String ordinal =
+        // this rule set formats the numeral and calls %%abbrev to
+        // supply the abbreviation
+        "%main:\n"
+        + "    =#,##0==%%abbrev=;\n"
+        // this rule set supplies the abbreviation
+        + "%%abbrev:\n"
+               // the abbreviations.  Everything from 4 to 19 ends in "th"
+        + "    th; st; nd; rd; th;\n"
+               // at 20, we begin repeating the cycle every 10 (13 is "13th",
+               // but 23 and 33 are "23rd" and "33rd")  We do this by
+               // ignoring all bug the ones digit in selecting the abbreviation
+        + "    20: >>;\n"
+               // at 100, we repeat the whole cycle by considering only the
+               // tens and ones digits in picking an abbreviation
+        + "    100: >>;\n";
+
+    /**
+     * This is a simple message-formatting example.  Normally one would
+     * use ChoiceFormat and MessageFormat to do something this simple,
+     * but this shows it could be done with RuleBasedNumberFormat too.
+     * A message-formatting example that might work better with
+     * RuleBasedNumberFormat appears later.
+     */
+    public static final String message1 =
+        // this rule surrounds whatever the other rules produce with the
+        // rest of the sentence
+        "x.0: The search found <<.;\n"
+        // use words for values below 10 (and change to "file" for 1)
+        + "no files; one file; two files; three files; four files; five files;\n"
+        + "    six files; seven files; eight files; nine files;\n"
+        // use numerals for values higher than 10
+        + "=#,##0= files;";
+
+    //========================================================================
+    // Fraction handling
+    //
+    // The next few examples show how RuleBasedNumberFormat can be used for
+    // more flexible handling of fractions
+    //========================================================================
+
+    /**
+     * This example formats a number in one of the two styles often used
+     * on checks.  %dollars-and-hundredths formats cents as hundredths of
+     * a dollar (23.40 comes out as "twenty-three and 40/100 dollars").
+     * %dollars-and-cents formats in dollars and cents (23.40 comes out as
+     * "twenty-three dollars and forty cents")
+     */
+    public static final String dollarsAndCents =
+        // this rule set formats numbers as dollars and cents
+        "%dollars-and-cents:\n"
+               // if the value is 1 or more, put "xx dollars and yy cents".
+               // the "and y cents" part is suppressed if the value is an
+               // even number of dollars
+        + "    x.0: << [and >%%cents>];\n"
+               // if the value is between 0 and 1, put "xx cents"
+        + "    0.x: >%%cents>;\n"
+               // these three rules take care of the singular and plural
+               // forms of "dollar" and use %%main to format the number
+        + "    0: zero dollars; one dollar; =%%main= dollars;\n"
+        // these are the regular U.S. English number spellout rules
+        + "%%main:\n"
+        + "    zero; one; two; three; four; five; six; seven; eight; nine;\n"
+        + "    ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
+        + "        seventeen; eighteen; nineteen;\n"
+        + "    20: twenty[->>];\n"
+        + "    30: thirty[->>];\n"
+        + "    40: forty[->>];\n"
+        + "    50: fifty[->>];\n"
+        + "    60: sixty[->>];\n"
+        + "    70: seventy[->>];\n"
+        + "    80: eighty[->>];\n"
+        + "    90: ninety[->>];\n"
+        + "    100: << hundred[ >>];\n"
+        + "    1000: << thousand[ >>];\n"
+        + "    1,000,000: << million[ >>];\n"
+        + "    1,000,000,000: << billion[ >>];\n"
+        + "    1,000,000,000,000: << trillion[ >>];\n"
+        + "    1,000,000,000,000,000: =#,##0=;\n"
+        // this rule takes care of the fractional part of the value.  It
+        // multiplies the fractional part of the number being formatted by
+        // 100, formats it with %%main, and then addes the word "cent" or
+        // "cents" to the end.  (The text in brackets is omitted if the
+        // numerator of the fraction is 1.)
+        + "%%cents:\n"
+        + "    100: <%%main< cent[s];\n"
+
+        // this rule set formats numbers as dollars and hundredths of dollars
+        + "%dollars-and-hundredths:\n"
+               // this rule takes care of the general shell of the output
+               // string.  We always show the cents, even when there aren't
+               // any.  Because of this, the word is always "dollars"--
+               // we don't have to worry about the singular form.  We use
+               // %%main to format the number of dollars and %%hundredths to
+               // format the number of cents
+        + "    x.0: <%%main< and >%%hundredths>/100 dollars;\n"
+        // this rule set formats the cents for %dollars-and-hundredths.
+        // It multiplies the fractional part of the number by 100 and formats
+        // the result using a DecimalFormat ("00" tells the DecimalFormat to
+        // always use two digits, even for numbers under 10)
+        + "%%hundredths:\n"
+        + "    100: <00<;\n";
+
+    /**
+     * This rule set shows the fractional part of the number as a fraction
+     * with a power of 10 as the denominator.  Some languages don't spell
+     * out the fractional part of a number as "point one two three," but
+     * always render it as a fraction.  If we still want to treat the fractional
+     * part of the number as a decimal, then the fraction's denominator
+     * is always a power of 10.  This example does that: 23.125 is formatted
+     * as "twenty-three and one hundred twenty-five thousandths" (as opposed
+     * to "twenty-three point one two five" or "twenty-three and one eighth").
+     */
+    public static final String decimalAsFraction =
+        // the regular U.S. English spellout rules, with one difference
+        "%main:\n"
+        + "    -x: minus >>;\n"
+               // the difference.  This rule uses %%frac to show the fractional
+               // part of the number.  Text in brackets is omitted when the
+               // value is between 0 and 1 (causing 0.3 to come out as "three
+               // tenths" instead of "zero and three tenths").
+        + "    x.x: [<< and ]>%%frac>;\n"
+        + "    zero; one; two; three; four; five; six; seven; eight; nine;\n"
+        + "    ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
+        + "        seventeen; eighteen; nineteen;\n"
+        + "    twenty[->>];\n"
+        + "    30: thirty[->>];\n"
+        + "    40: forty[->>];\n"
+        + "    50: fifty[->>];\n"
+        + "    60: sixty[->>];\n"
+        + "    70: seventy[->>];\n"
+        + "    80: eighty[->>];\n"
+        + "    90: ninety[->>];\n"
+        + "    100: << hundred[ >>];\n"
+        + "    1000: << thousand[ >>];\n"
+        + "    1,000,000: << million[ >>];\n"
+        + "    1,000,000,000: << billion[ >>];\n"
+        + "    1,000,000,000,000: << trillion[ >>];\n"
+        + "    1,000,000,000,000,000: =#,##0=;\n"
+        // the rule set that formats the fractional part of the number.
+        // The rule that is used is the one that, when its baase value is
+        // multiplied by the fractional part of the number being formatted,
+        // produces the result closest to zero.  Thus, the base values are
+        // prospective denominators of the fraction.  The << marks the place
+        // where the numerator of the fraction (the result of multiplying the
+        // fractional part of the number by the rule's base value) is
+        // placed.  Text in brackets is omitted when the numerator is 1, giving
+        // us the singular and plural forms of the words.
+        // [In languages where the singular and plural are completely different
+        // words, the rule can just be stated twice: the second time with
+        // the plural form.]
+        + "%%frac:\n"
+        + "    10: << tenth[s];\n"
+        + "    100: << hundredth[s];\n"
+        + "    1000: << thousandth[s];\n"
+        + "    10,000: << ten-thousandth[s];\n"
+        + "    100,000: << hundred-thousandth[s];\n"
+        + "    1,000,000: << millionth[s];";
+
+    /**
+     * Number with closest fraction.  This example formats a value using
+     * numerals, but shows the fractional part as a ratio (fraction) rather
+     * than a decimal.  The fraction always has a denominator between 2 and 10.
+     */
+    public static final String closestFraction =
+        "%main:\n"
+               // this rule formats the number if it's 1 or more.  It formats
+               // the integral part using a DecimalFormat ("#,##0" puts
+               // thousands separators in the right places) and the fractional
+               // part using %%frac.  If there is no fractional part, it
+               // just shows the integral part.
+        + "    x.0: <#,##0<[ >%%frac>];\n"
+               // this rule formats the number if it's between 0 and 1.  It
+               // shows only the fractional part (0.5 shows up as "1/2," not
+               // "0 1/2")
+        + "    0.x: >%%frac>;\n"
+        // the fraction rule set.  This works the same way as the one in the
+        // preceding example: We multiply the fractional part of the number
+        // being formatted by each rule's base value and use the rule that
+        // produces the result closest to 0 (or the first rule that produces 0).
+        // Since we only provide rules for the numbers from 2 to 10, we know
+        // we'll get a fraction with a denominator between 2 and 10.
+        // "<0<" causes the numerator of the fraction to be formatted
+        // using numerals
+        + "%%frac:\n"
+        + "    2: 1/2;\n"
+        + "    3: <0</3;\n"
+        + "    4: <0</4;\n"
+        + "    5: <0</5;\n"
+        + "    6: <0</6;\n"
+        + "    7: <0</7;\n"
+        + "    8: <0</8;\n"
+        + "    9: <0</9;\n"
+        + "    10: <0</10;\n";
+
+    /**
+     * American stock-price formatting.  Non-integral stock prices are still
+     * generally shown in eighths or sixteenths of dollars instead of dollars
+     * and cents.  This example formats stock prices in this way if possible,
+     * and in dollars and cents if not.
+     */
+    public static final String stock =
+        "%main:\n"
+               // this rule formats the integral part of the number in numerals
+               // and (if necessary) the fractional part using %%frac1
+        + "    x.0: <#,##0<[>%%frac1>];\n"
+               // this rule is used for values between 0 and 1 and omits the
+               // integral part
+        + "    0.x: >%%frac2>;\n"
+        // this rule set is used to format the fractional part of the number when
+        // there's an integral part before it (again, we try all denominators
+        // and use the "best" one)
+        + "%%frac1:\n"
+               // for even multiples of 1/4, format the fraction using the
+               // typographer's fractions
+        + "    4: <%%quarters<;\n"
+               // format the value as a number of eighths, sixteenths, or
+               // thirty-seconds, whichever produces the most accurate value.
+               // The apostrophe at the front of these rules is ignored, but
+               // it makes the space that follows it significant.  This puts a
+               // space between the value's integral and fractional parts so
+               // you can read it
+        + "    8: ' <0</8;\n"
+        + "    16: ' <0</16;\n"
+        + "    32: ' <0</32;\n"
+               // if we can't reasonably format the number in powers of 2,
+               // then show it as dollars and cents
+        + "    100: .<00<;\n"
+        // this rule set is used when the fractional part of the value stands
+        // alone
+        + "%%frac2:\n"
+        + "    4: <%%quarters<;\n"
+               // for fractions that we can't show using typographer's fractions,
+               // we don't have to put a space before the fraction
+        + "    8: <0</8;\n"
+        + "    16: <0</16;\n"
+        + "    32: <0</32;\n"
+               // but dollars and cents look better with a leading 0
+        + "    100: 0.<00<;\n"
+        // this rule set formats 1/4, 1/2, and 3/4 using typographer's fractions
+        + "%%quarters:\n"
+        + "    ; \u00bc; \u00bd; \u00be;\n"
+        // there are the lenient-parse rules.  These allow the user to type
+        // "1/4," "1/2," and "3/4" instead of their typographical counterparts
+        // and still have them be understood by the formatter
+        + "%%lenient-parse:\n"
+        + "    & '1/4' , \u00bc\n"
+        + "    & '1/2' , \u00bd\n"
+        + "    & '3/4' , \u00be\n;";
+
+    //========================================================================
+    // Changing dimensions
+    //
+    // The next few examples demonstrate using a RuleBasedNumberFormat to
+    // change the units a value is denominated in depending on its magnitude
+    //========================================================================
+
+    /**
+     * The example shows large numbers the way they often appear is nwespapers:
+     * 1,200,000 is formatted as "1.2 million".
+     */
+    public static final String abbEnglish =
+        "=#,##0=;\n"
+        // this is fairly self-explanatory, but note that the << substitution
+        // can show the fractional part of the substitution value if the user
+        // wants it
+        + "1,000,000: <##0.###< million;\n"
+        + "1,000,000,000: <##0.###< billion;\n"
+        + "1,000,000,000,000: <##0.###< trillion;\n";
+
+    /**
+     * This example takes a number of meters and formats it in whatever unit
+     * will produce a number with from one to three digits before the decimal
+     * point.  For example, 230,000 is formatted as "230 km".
+     */
+    public static final String units =
+        "%main:\n"
+               // for values between 0 and 1, delegate to %%small
+        + "    0.x: >%%small>;\n"
+               // otherwise, show between 3 and 6 significant digits of the value
+               // along with the most appropriate unit
+        + "    0: =##0.###= m;\n"
+        + "    1,000: <##0.###< km;\n"
+        + "    1,000,000: <##0.###< Mm;\n"
+        + "    1,000,000,000: <##0.###< Gm;\n"
+        + "    1,000,000,000,000: <#,##0.###< Tm;\n"
+        // %%small formats the number when it's less then 1.  It multiplies the
+        // value by one billion, and then uses %%small2 to actually do the
+        // formatting.
+        + "%%small:\n"
+        + "    1,000,000,000,000: <%%small2<;\n"
+        // this rule set actually formats small values.  %%small passes this
+        // rule set a number of picometers, and it takes care of scaling up as
+        // appropriate in exactly the same way %main does (we can't normally
+        // handle fractional values this way: here, we're concerned about
+        // magnitude; most of the time, we're concerned about precsion)
+        + "%%small2:\n"
+        + "    0: =##0= pm;\n"
+        + "    1,000: <##0.###< nm;\n"
+        + "    1,000,000: <##0.###< \u00b5m;\n"
+        + "    1,000,000,000: <##0.###< mm;\n";
+
+    /**
+     * A more complicated message-formatting example.  Here, in addition to
+     * handling the singular and plural versions of the word, the value is
+     * denominated in bytes, kilobytes, or megabytes depending on its magnitude.
+     * Also notice that it correctly treats a kilobyte as 1,024 bytes (not 1,000),
+     * and a megabyte as 1,024 kilobytes (not 1,000).
+     */
+    public static final String message2 =
+        // this rule supplies the shell of the sentence
+        "x.0: There << free space on the disk.;\n"
+        // handle singular and plural forms of "byte" (and format 0 as
+        // "There is no free space...")
+        + "0: is no;\n"
+        + "is one byte of;\n"
+        + "are =0= bytes of;\n"
+        // for values above 1,024, format the number in K (since "K" is usually
+        // promounced "K" regardless of whether it's singular or plural, we
+        // don't worry about the plural form).  The "/1024" here causes us to
+        // treat a K as 1,024 bytes rather than 1,000 bytes.
+        + "1024/1024: is <0<K of;\n"
+        // for values about 1,048,576, format the number in Mb.  Since "Mb" is
+        // usually promounced "meg" in singular and "megs" in plural, we do have
+        // both singular and plural forms.  Again, notice we treat a megabyte
+        // as 1,024 kilobytes.
+        + "1,048,576/1024: is 1 Mb of;\n"
+        + "2,097,152/1024: are <0< Mb of;";
+
+    //========================================================================
+    // Alternate radices
+    //========================================================================
+
+    /**
+     * This example formats a number in dozens and gross.  This is intended to
+     * demonstrate how this rule set can be used to format numbers in systems
+     * other than base 10.  The "/12" after the rules' base values controls this.
+     * Also notice that the base doesn't have to be consistent throughout the
+     * whole rule set: we go back to base 10 for values over 1,000.
+     */
+    public static final String dozens =
+        // words for numbers...
+        "zero; one; two; three; four; five; six;\n"
+        + "seven; eight; nine; ten; eleven;\n"
+        // format values over 12 in dozens
+        + "12/12: << dozen[ and >>];\n"
+        // format values over 144 in gross
+        + "144/12: << gross[, >>];\n"
+        // format values over 1,000 in thousands
+        + "1000: << thousand[, >>];\n"
+        // overflow rule.  Format values over 10,000 in numerals
+        + "10,000: =#,##0=;\n";
+
+    //========================================================================
+    // Major and minor units
+    //
+    // These examples show how a single value can be divided up into major
+    // and minor units that don't relate to each other by a factor of 10.
+    //========================================================================
+
+    /**
+     * This example formats a number of seconds in sexagesimal notation
+     * (i.e., hours, minutes, and seconds).  %with-words formats it with
+     * words (3740 is "1 hour, 2 minutes, 20 seconds") and %in-numerals
+     * formats it entirely in numerals (3740 is "1:02:20").
+     */
+    public static final String durationInSeconds =
+        // main rule set for formatting with words
+        "%with-words:\n"
+               // take care of singular and plural forms of "second"
+        + "    0 seconds; 1 second; =0= seconds;\n"
+               // use %%min to format values greater than 60 seconds
+        + "    60/60: <%%min<[, >>];\n"
+               // use %%hr to format values greater than 3,600 seconds
+               // (the ">>>" below causes us to see the number of minutes
+               // when when there are zero minutes)
+        + "    3600/60: <%%hr<[, >>>];\n"
+        // this rule set takes care of the singular and plural forms
+        // of "minute"
+        + "%%min:\n"
+        + "    0 minutes; 1 minute; =0= minutes;\n"
+        // this rule set takes care of the singular and plural forms
+        // of "hour"
+        + "%%hr:\n"
+        + "    0 hours; 1 hour; =0= hours;\n"
+
+        // main rule set for formatting in numerals
+        + "%in-numerals:\n"
+               // values below 60 seconds are shown with "sec."
+        + "    =0= sec.;\n"
+               // higher values are shown with colons: %%min-sec is used for
+               // values below 3,600 seconds...
+        + "    60: =%%min-sec=;\n"
+               // ...and %%hr-min-sec is used for values of 3,600 seconds
+               // and above
+        + "    3600: =%%hr-min-sec=;\n"
+        // this rule causes values of less than 10 minutes to show without
+        // a leading zero
+        + "%%min-sec:\n"
+        + "    0: :=00=;\n"
+        + "    60/60: <0<>>;\n"
+        // this rule set is used for values of 3,600 or more.  Minutes are always
+        // shown, and always shown with two digits
+        + "%%hr-min-sec:\n"
+        + "    0: :=00=;\n"
+        + "    60/60: <00<>>;\n"
+        + "    3600/60: <#,##0<:>>>;\n"
+        // the lenient-parse rules allow several different characters to be used
+        // as delimiters between hours, minutes, and seconds
+        + "%%lenient-parse:\n"
+        + "    & : = . = ' ' = -;\n";
+
+    /**
+     * This example formats a number of hours in sexagesimal notation (i.e.,
+     * hours, minutes, and seconds).  %with-words formats the value using
+     * words for the units, and %in-numerals formats the value using only
+     * numerals.
+     */
+    public static final String durationInHours =
+        // main entry point for formatting with words
+        "%with-words:\n"
+               // this rule omits minutes and seconds when the value is
+               // an even number of hours
+        + "    x.0: <<[, >%%min-sec>];\n"
+               // these rules take care of the singular and plural forms
+               // of hours
+        + "    0 hours; 1 hour; =#,##0= hours;\n"
+        // this rule set takes the fractional part of the number and multiplies
+        // it by 3,600 (turning it into a number of seconds).  Then it delegates
+        // to %%min-sec-implementation to format the resulting value
+        + "%%min-sec:\n"
+        + "    3600: =%%min-sec-implementation=;\n"
+        // this rule set formats the seconds as either seconds or minutes and
+        // seconds, and takes care of the singular and plural forms of
+        // "minute" and "second"
+        + "%%min-sec-implementation:\n"
+        + "    0 seconds; 1 second; =0= seconds;\n"
+        + "    60/60: 1 minute[, >>];\n"
+        + "    120/60: <0< minutes[, >>];\n"
+
+        // main entry point for formatting in numerals
+        + "%in-numerals:\n"
+               // show minutes even for even numbers of hours
+        + "    x.0: <#,##0<:00;\n"
+               // delegate to %%min-sec2 to format minutes and seconds
+        + "    x.x: <#,##0<:>%%min-sec2>;\n"
+        // this rule set formats minutes when there is an even number of
+        // minutes, and delegates to %%min-sec2-implementation when there
+        // are seconds
+        + "%%min-sec2:\n"
+        + "    60: <00<;\n"
+        + "    3600: <%%min-sec2-implementation<;\n"
+        // these two rule sets are used to format the minutes and seconds
+        + "%%min-sec2-implementation:\n"
+               // if there are fewer than 60 seconds, show the minutes anyway
+        + "    0: 00:=00=;\n"
+               // if there are minutes, format them too, and always use 2 digits
+               // for both minutes and seconds
+        + "    60: =%%min-sec3=;\n"
+        + "%%min-sec3:\n"
+        + "    0: :=00=;\n"
+        + "    60/60: <00<>>;\n"
+        // the lenient-parse rules allow the user to use any of several
+        // characters as delimiters between hours, minutes, and seconds
+        + "%%lenient-parse:\n"
+        + "    & : = . = ' ' = -;\n";
+
+    /**
+     * This rule set formats a number of pounds as pounds, shillings, and
+     * pence in the old English system of currency.
+     */
+    public static final String poundsShillingsAndPence =
+        // for values of 1 or more, format the integral part with a pound
+        // sign in front, and show shillings and pence if necessary
+        "%main:\n"
+        + "    x.0: \u00a3<#,##0<[ >%%shillings-and-pence>];\n"
+        // for values between 0 and 1, omit the number of pounds
+        + "    0.x: >%%pence-alone>;\n"
+        // this rule set is used to show shillings and pence.  It multiplies
+        // the fractional part of the number by 240 (the number of pence in a
+        // pound) and uses %%shillings-and-pence-implementation to format
+        // the result
+        + "%%shillings-and-pence:\n"
+        + "    240: <%%shillings-and-pence-implementation<;\n"
+        // this rule set is used to show shillings and pence when there are
+        // no pounds.  It also multiplies the value by 240, and then it uses
+        // %%pence-alone-implementation to format the result.
+        + "%%pence-alone:\n"
+        + "    240: <%%pence-alone-implementation<;\n"
+        // this rule set formats a number of pence when we know we also
+        // have pounds.  We always show shillings (with a 0 if necessary),
+        // but only show pence if the value isn't an even number of shillings
+        + "%%shillings-and-pence-implementation:\n"
+        + "    0/; 0/=0=;\n"
+        + "    12/12: <0</[>0>];\n"
+        // this rule set formats a number of pence when we know there are
+        // no pounds.  Values less than a shilling are shown with "d." (the
+        // abbreviation for pence), and values greater than a shilling are
+        // shown with a shilling bar (and without pence when the value is
+        // an even number of shillings)
+        + "%%pence-alone-implementation:\n"
+        + "    =0= d.;\n"
+        + "    12/12: <0</[>0>];\n";
+
+    //========================================================================
+    // Alternate numeration systems
+    //
+    // These examples show how RuleBasedNumberFormat can be used to format
+    // numbers using non-positional numeration systems.
+    //========================================================================
+
+    /**
+     * Arabic digits.  This example formats numbers in Arabic numerals.
+     * Normally, you'd do this with DecimalFormat, but this shows that
+     * RuleBasedNumberFormat can handle it too.
+     */
+    public static final String arabicNumerals =
+        "0; 1; 2; 3; 4; 5; 6; 7; 8; 9;\n"
+        + "10: <<>>;\n"
+        + "100: <<>>>;\n"
+        + "1000: <<,>>>;\n"
+        + "1,000,000: <<,>>>;\n"
+        + "1,000,000,000: <<,>>>;\n"
+        + "1,000,000,000,000: <<,>>>;\n"
+        + "1,000,000,000,000,000: =#,##0=;\n"
+        + "-x: ->>;\n"
+        + "x.x: <<.>>;";
+
+    /**
+     * Words for digits.  Follows the same pattern as the Arabic-numerals
+     * example above, but uses words for the various digits (e.g., 123 comes
+     * out as "one two three").
+     */
+    public static final String wordsForDigits =
+        "-x: minus >>;\n"
+        + "x.x: << point >>;\n"
+        + "zero; one; two; three; four; five; six;\n"
+        + "    seven; eight; nine;\n"
+        + "10: << >>;\n"
+        + "100: << >>>;\n"
+        + "1000: <<, >>>;\n"
+        + "1,000,000: <<, >>>;\n"
+        + "1,000,000,000: <<, >>>;\n"
+        + "1,000,000,000,000: <<, >>>;\n"
+        + "1,000,000,000,000,000: =#,##0=;\n";
+
+    /**
+     * This example formats numbers using Chinese characters in the Arabic
+     * place-value method.  This was used historically in China for a while.
+     */
+    public static final String chinesePlaceValue =
+        "\u3007; \u4e00; \u4e8c; \u4e09; \u56db; \u4e94; \u516d; \u4e03; \u516b; \u4e5d;\n"
+        + "10: <<>>;\n"
+        + "100: <<>>>;\n"
+        + "1000: <<>>>;\n"
+        + "1,000,000: <<>>>;\n"
+        + "1,000,000,000: <<>>>;\n"
+        + "1,000,000,000,000: <<>>>;\n"
+        + "1,000,000,000,000,000: =#,##0=;\n";
+
+    /**
+     * Roman numerals.  This example has two variants: %modern shows how large
+     * numbers are usually handled today; %historical ses the older symbols for
+     * thousands.
+     */
+    public static final String romanNumerals =
+        "%historical:\n"
+        + "    =%modern=;\n"
+               // in early Roman numerals, 1,000 was shown with a circle
+               // bisected by a vertical line.  Additional thousands were
+               // shown by adding more concentric circles, and fives were
+               // shown by cutting the symbol for next-higher power of 10
+               // in half (the letter D for 500 evolved from this).
+               // We could go beyond 40,000, but Unicode doesn't encode
+               // the symbols for higher numbers/
+        + "    1000: \u2180[>>]; 2000: \u2180\u2180[>>]; 3000: \u2180\u2180\u2180[>>]; 4000: \u2180\u2181[>>];\n"
+        + "    5000: \u2181[>>]; 6000: \u2181\u2180[>>]; 7000: \u2181\u2180\u2180[>>];\n"
+        + "    8000: \u2181\u2180\u2180\u2180[>>]; 9000: \u2180\u2182[>>];\n"
+        + "    10,000: \u2182[>>]; 20,000: \u2182\u2182[>>]; 30,000: \u2182\u2182\u2182[>>];\n"
+        + "    40,000: =#,##0=;\n"
+        + "%modern:\n"
+        + "    ; I; II; III; IV; V; VI; VII; VIII; IX;\n"
+        + "    10: X[>>]; 20: XX[>>]; 30: XXX[>>]; 40: XL[>>]; 50: L[>>];\n"
+        + "    60: LX[>>]; 70: LXX[>>]; 80: LXXX[>>]; 90: XC[>>];\n"
+        + "    100: C[>>]; 200: CC[>>]; 300: CCC[>>]; 400: CD[>>]; 500: D[>>];\n"
+        + "    600: DC[>>]; 700: DCC[>>]; 800: DCCC[>>]; 900: CM[>>];\n"
+               // in modern Roman numerals, high numbers are generally shown
+               // by placing a bar over the letters for the lower numbers:
+               // the bar multiplied a letter's value by 1,000
+        + "    1000: M[>>]; 2000: MM[>>]; 3000: MMM[>>]; 4000: MV\u0306[>>];\n"
+        + "    5000: V\u0306[>>]; 6000: V\u0306M[>>]; 7000: V\u0306MM[>>];\n"
+        + "    8000: V\u0306MMM[>>]; 9000: MX\u0306[>>];\n"
+        + "    10,000: X\u0306[>>]; 20,000: X\u0306X\u0306[>>]; 30,000: X\u0306X\u0306X\u0306[>>];\n"
+        + "    40,000: X\u0306L\u0306[>>]; 50,000: L\u0306[>>]; 60,000: L\u0306X\u0306[>>];\n"
+        + "    70,000: L\u0306X\u0306X\u0306[>>]; 80,000: L\u0306X\u0306X\u0306X\u0306[>>];\n"
+        + "    90,000: X\u0306C\u0306[>>];\n"
+        + "    100,000: C\u0306[>>]; 200,000: C\u0306C\u0306[>>]; 300,000: C\u0306C\u0306[>>];\n"
+        + "    400,000: C\u0306D\u0306[>>]; 500,000: D\u0306[>>]; 600,000: D\u0306C\u0306[>>];\n"
+        + "    700,000: D\u0306C\u0306C\u0306[>>]; 800,000: D\u0306C\u0306C\u0306C\u0306[>>];\n"
+        + "    900,000: =#,##0=;\n";
+
+    /**
+     * Hebrew alphabetic numerals.  Before adoption of Arabic numerals, Hebrew speakers
+     * used the letter of their alphabet as numerals.  The first nine letters of
+     * the alphabet repesented the values from 1 to 9, the second nine letters the
+     * multiples of 10, and the remaining letters the multiples of 100.  Since they
+     * ran out of letters at 400, the remaining multiples of 100 were represented
+     * using combinations of the existing letters for the hundreds.  Numbers were
+     * distinguished from words in a number of different ways: the way shown here
+     * uses a single mark after a number consisting of one letter, and a double
+     * mark between the last two letters of a number consisting of two or more
+     * letters.  Two dots over a letter multiplied its value by 1,000.  Also, since
+     * the letter for 10 is the first letter of God's name and the letters for 5 and 6
+     * are letters in God's name, which wasn't supposed to be written or spoken, 15 and
+     * 16 were usually written as 9 + 6 and 9 + 7 instead of 10 + 5 and 10 + 6.
+     */
+    public static final String hebrewAlphabetic =
+        // letters for the ones
+        "%%ones:\n"
+        + "    (no zero); \u05d0; \u05d1; \u05d2; \u05d3; \u05d4; \u05d5; \u05d6; \u05d7; \u05d8;\n"
+        // letters for the tens
+        + "%%tens:\n"
+        + "    ; \u05d9; \u05db; \u05dc; \u05de; \u05e0; \u05e1; \u05e2; \u05e4; \u05e6;\n"
+        // letters for the first four hundreds
+        + "%%hundreds:\n"
+        + "    ; \u05e7; \u05e8; \u05e9; \u05ea;\n"
+        // this rule set is used to write the combination of the tens and ones digits
+        // when we know that no other digits precede them: they put the numeral marks
+        // in the right place and properly handle 15 and 16 (I'm using the mathematical
+        // prime characters for the numeral marks because my Unicode font doesn't
+        // include the real Hebrew characters, which look just like the prime marks)
+        + "%%tens-and-ones:\n"
+               // for values less than 10, just use %%ones and put the numeral mark
+               // afterward
+        + "    =%%ones=\u2032;\n"
+               // put the numeral mark at the end for 10, but in the middle for
+               // 11 through 14
+        + "    10: <%%tens<\u2032; <%%tens<\u2033>%%ones>;\n"
+               // special-case 15 and 16
+        + "    15: \u05d8\u2033\u05d5; 16: \u05d8\u2033\u05d6;\n"
+               // go back to the normal method at 17
+        + "    17: <%%tens<\u2033>%%ones>;\n"
+               // repeat the rules for 10 and 11 to cover the values from 20 to 99
+        + "    20: <%%tens<\u2032; <%%tens<\u2033>%%ones>;\n"
+        // this rule set is used to format numbers below 1,000.  It relies on
+        // %%tens-and-ones to format the tens and ones places, and adds logic
+        // to handle the high hundreds and the numeral marks when there is no
+        // tens digit.  Notice how the rules are paired: all of these pairs of
+        // rules take advantage of the rollback rule: if the value (between 100
+        // and 499) is an even multiple of 100, the rule for 100 is used; otherwise,
+        // the rule for 101 (the following rule) is used.  The first rule in each
+        // pair (the one for the even multiple) places the numeral mark in a different
+        // spot than the second rule in each pair (which knows there are more digits
+        // and relies on the rule supplying them to also supply the numeral mark).
+        // The call to %%null in line 10 is there simply to invoke the rollback
+        // rule.
+        + "%%low-order:\n"
+               // this rule is only called when there are other characters before.
+               // It places the numeral mark before the last digit
+        + "    \u2033=%%ones=;\n"
+               // the rule for 10 places the numeral mark before the 10 character
+               // (because we know it's the last character); the rule for 11 relies
+               // on %%tens-and-ones to place the numeral mark
+        + "    10: \u2033<%%tens<; =%%tens-and-ones=>%%null>;\n"
+               // the rule for 100 places the numeral mark before the 100 character
+               // (we know it's the last character); the rule for 101 recurses to
+               // fill in the remaining digits and the numeral mark
+        + "    100: <%%hundreds<\u2032; <%%hundreds<>>;\n"
+               // special-case the hundreds from 500 to 900 because they consist of
+               // more than one character
+        + "    500: \u05ea\u2033\u05e7; \u05ea\u05e7>>;\n"
+        + "    600: \u05ea\u2033\u05e8; \u05ea\u05e8>>;\n"
+        + "    700: \u05ea\u2033\u05e9; \u05ea\u05e9>>;\n"
+        + "    800: \u05ea\u2033\u05ea; \u05ea\u05ea>>;\n"
+        + "    900: \u05ea\u05ea\u2033\u05e7; \u05ea\u05ea\u05e7>>;\n"
+        // this rule set is used to format values of 1,000 or more.  Here, we don't
+        // worry about the numeral mark, and we add two dots (the Unicode combining
+        // diaeresis character) to ever letter
+        + "%%high-order:\n"
+               // put the ones digit, followed by the diaeresis
+        + "    =%%ones=\u0308;\n"
+               // the tens can be handled with recursion
+        + "    10: <%%tens<\u0308[>>];\n"
+               // still have to special-case 15 and 16
+        + "    15: \u05d8\u0308\u05d5\u0308; 16: \u05d8\u003078\u05d6\u0308;\n"
+               // back to the regular rules at 17
+        + "    17: <%%tens<\u0308[>>];\n"
+               // the hundreds with the dots added (and without worrying about
+               // placing the numeral mark)
+        + "    100: <%%hundreds<\u0308[>>];\n"
+        + "    500: \u05ea\u0308\u05e7\u0308[>>];\n"
+        + "    600: \u05ea\u0308\u05e8\u0308[>>];\n"
+        + "    700: \u05ea\u0308\u05e9\u0308[>>];\n"
+        + "    800: \u05ea\u0308\u05ea\u0308[>>];\n"
+        + "    900: \u05ea\u0308\u05ea\u0308\u05e7\u0308[>>];\n"
+        // this rule set doesn't do anything; it's used by some other rules to
+        // invoke the rollback rule
+        + " %%null:\n"
+        + "    ;\n"
+        // the main rule set.
+        + "%main:\n"
+               // for values below 10, just output the letter and the numeral mark
+        + "    =%%ones=\u2032;\n"
+               // for values from 10 to 99, use %%tens-and-ones to do the formatting
+        + "    10: =%%tens-and-ones=;\n"
+               // for values from 100 to 999, use %%low-order to do the formatting
+        + "    100: =%%low-order=;\n"
+               // for values of 1,000 and over, use %%high-order to do the formatting
+        + "    1000: <%%high-order<[>%%low-order>];\n";
+
+    /**
+     * Greek alphabetic numerals.  The Greeks, before adopting the Arabic numerals,
+     * also used the letters of their alphabet as numerals.  There are three now-
+     * obsolete Greek letters that are used as numerals; many fonts don't have them.
+     * Large numbers were handled many different ways; the way shown here divides
+     * large numbers into groups of four letters (factors of 10,000), and separates
+     * the groups with the capital letter mu (for myriad).  Capital letters are used
+     * for values below 10,000; small letters for higher numbers (to make the capital
+     * mu stand out).
+     */
+    public static final String greekAlphabetic =
+        // this rule set is used for formatting numbers below 10,000.  It uses
+        // capital letters.
+        "%%low-order:\n"
+        + "    (no zero); \u0391; \u0392; \u0393; \u0394; \u0395; \u03dc; \u0396; \u0397; \u0398;\n"
+        + "    10: \u0399[>>]; 20: \u039a[>>]; 30: \u039b[>>]; 40: \u039c[>>]; 50: \u039d[>>];\n"
+        + "    60: \u039e[>>]; 70: \u039f[>>]; 80: \u03a0[>>]; 90: \u03de[>>];\n"
+        + "    100: \u03a1[>>]; 200: \u03a3[>>]; 300: \u03a4[>>]; 400: \u03a5[>>];\n"
+        + "    500: \u03a6[>>]; 600: \u03a7[>>]; 700: \u03a8[>>]; 800: \u03a9[>>];\n"
+        + "    900: \u03e0[>>];\n"
+               // the thousands are represented by the same numbers as the ones, but
+               // with a comma-like mark added to their left shoulder
+        + "    1000: \u0391\u0313[>>]; 2000: \u0392\u0313[>>]; 3000: \u0393\u0313[>>];\n"
+        + "    4000: \u0394\u0313[>>]; 5000: \u0395\u0313[>>]; 6000: \u03dc\u0313[>>];\n"
+        + "    7000: \u0396\u0313[>>]; 8000: \u0397\u0313[>>]; 9000: \u0398\u0313[>>];\n"
+        // this rule set is the same as above, but uses lowercase letters.  It is used
+        // for formatting the groups in numbers above 10,000.
+        + "%%high-order:\n"
+        + "    (no zero); \u03b1; \u03b2; \u03b3; \u03b4; \u03b5; \u03dc; \u03b6; \u03b7; \u03b8;\n"
+        + "    10: \u03b9[>>]; 20: \u03ba[>>]; 30: \u03bb[>>]; 40: \u03bc[>>]; 50: \u03bd[>>];\n"
+        + "    60: \u03be[>>]; 70: \u03bf[>>]; 80: \u03c0[>>]; 90: \u03de[>>];\n"
+        + "    100: \u03c1[>>]; 200: \u03c3[>>]; 300: \u03c4[>>]; 400: \u03c5[>>];\n"
+        + "    500: \u03c6[>>]; 600: \u03c7[>>]; 700: \u03c8[>>]; 800: \u03c9[>>];\n"
+        + "    900: \u03c0[>>];\n"
+        + "    1000: \u03b1\u0313[>>]; 2000: \u03b2\u0313[>>]; 3000: \u03b3\u0313[>>];\n"
+        + "    4000: \u03b4\u0313[>>]; 5000: \u03b5\u0313[>>]; 6000: \u03dc\u0313[>>];\n"
+        + "    7000: \u03b6\u0313[>>]; 8000: \u03b7\u0313[>>]; 9000: \u03b8\u0313[>>];\n"
+        // the main rule set
+        + "%main:\n"
+               // for values below 10,000, just use %%low-order
+        + "    =%%low-order=;\n"
+               // for values above 10,000, split into two groups of four digits
+               // and format each with %%high-order (putting an M in betwen)
+        + "    10,000: <%%high-order<\u039c>%%high-order>;\n"
+               // for values above 100,000,000, add another group onto the front
+               // and another M
+        + "    100,000,000: <%%high-order<\u039c>>\n";
+
+    /**
+     * A list of all the sample rule sets, used by the demo program.
+     */
+    public static final String[] sampleRuleSets =
+        { usEnglish,
+          ukEnglish,
+          spanish,
+          french,
+          swissFrench,
+          german,
+          italian,
+          swedish,
+          dutch,
+          japanese,
+          greek,
+          russian,
+          hebrew,
+          ordinal,
+          message1,
+          dollarsAndCents,
+          decimalAsFraction,
+          closestFraction,
+          stock,
+          abbEnglish,
+          units,
+          message2,
+          dozens,
+          durationInSeconds,
+          durationInHours,
+          poundsShillingsAndPence,
+          arabicNumerals,
+          wordsForDigits,
+          chinesePlaceValue,
+          romanNumerals,
+          hebrewAlphabetic,
+          greekAlphabetic };
+
+    /**
+     * The displayable names for all the sample rule sets, in the same order as
+     * the preceding array.
+     */
+    public static final String[] sampleRuleSetNames =
+        { "English (US)",
+          "English (UK)",
+          "Spanish",
+          "French (France)",
+          "French (Switzerland)",
+          "German",
+          "Italian",
+          "Swedish",
+          "Dutch",
+          "Japanese",
+          "Greek",
+          "Russian",
+          "Hebrew",
+          "English ordinal abbreviations",
+          "Simple message formatting",
+          "Dollars and cents",
+          "Decimals as fractions",
+          "Closest fraction",
+          "Stock prices",
+          "Abbreviated US English",
+          "Changing dimensions",
+          "Complex message formatting",
+          "Dozens",
+          "Duration (value in seconds)",
+          "Duration (value in hours)",
+          "Pounds, shillings, and pence",
+          "Arabic numerals",
+          "Words for digits",
+          "Chinese place-value notation",
+          "Roman numerals",
+          "Hebrew ahlphabetic numerals",
+          "Greek alphabetic numerals" };
+
+    /**
+     * The base locale for each of the sample rule sets.  The locale is used to
+     * determine DecimalFormat behavior, lenient-parse behavior, and text-display
+     * selection (we have a hack in here to allow display of non-Latin scripts).
+     * Null means the locale setting is irrelevant and the default can be used.
+     */
+    public static final Locale[] sampleRuleSetLocales =
+        { Locale.US,
+          Locale.UK,
+          new Locale("es", "", ""),
+          Locale.FRANCE,
+          new Locale("fr", "CH", ""),
+          Locale.GERMAN,
+          Locale.ITALIAN,
+          new Locale("sv", "", ""),
+          new Locale("nl", "", ""),
+          Locale.JAPANESE,
+          new Locale("el", "", ""),
+          new Locale("ru", "", ""),
+          new Locale("iw", "", ""),
+          Locale.ENGLISH,
+          Locale.ENGLISH,
+          Locale.US,
+          Locale.ENGLISH,
+          null,
+          null,
+          Locale.ENGLISH,
+          null,
+          Locale.ENGLISH,
+          Locale.ENGLISH,
+          null,
+          null,
+          Locale.UK,
+          null,
+          Locale.ENGLISH,
+          new Locale("zh", "", ""),
+          null,
+          new Locale("iw", "", ""),
+          new Locale("el", "", ""),
+          null };
+
+        public static final String[] sampleRuleSetCommentary = {
+            "This demonstration version of the "
+            + "U.S. English spellout rules has four variants: 1) %simplified is a "
+            + "set of rules showing the simple method of spelling out numbers in "
+            + "English: 289 is formatted as \"two hundred eighty-nine\".  2) %alt-teens "
+            + "is the same as %simplified, except that values between 1,000 and 9,999 "
+            + "whose hundreds place isn't zero are formatted in hundreds.  For example, "
+            + "1,983 is formatted as \"nineteen hundred eighty-three,\" and 2,183 is "
+            + "formatted as \"twenty-one hundred eighty-three,\" but 2,083 is still "
+            + "formatted as \"two thousand eighty-three.\"  3) %ordinal formats the "
+            + "values as ordinal numbers in English (e.g., 289 is \"two hundred eighty-"
+            + "ninth\").  4) %default uses a more complicated algorithm to format "
+            + "numbers in a more natural way: 289 is formatted as \"two hundred AND "
+            + "eighty-nine\" and commas are inserted between the thousands groups for "
+            + "values above 100,000.",
+
+            "U.K. English has one significant "
+            + "difference from U.S. English: the names for values of 1,000,000,000 "
+            + "and higher.  In American English, each successive \"-illion\" is 1,000 "
+            + "times greater than the preceding one: 1,000,000,000 is \"one billion\" "
+            + "and 1,000,000,000,000 is \"one trillion.\"  In British English, each "
+            + "successive \"-illion\" is one million times greater than the one before: "
+            + "\"one billion\" is 1,000,000,000,000 (or what Americans would call a "
+            + "\"trillion\"), and \"one trillion\" is 1,000,000,000,000,000,000.  "
+            + "1,000,000,000 in British English is \"one thousand million.\"  (This "
+            + "value is sometimes called a \"milliard,\" but this word seems to have "
+            + "fallen into disuse.)",
+
+            "The Spanish rules are quite similar to "
+            + "the English rules, but there are some important differences: "
+            + "First, we have to provide separate rules for most of the twenties "
+            + "because the ones digit frequently picks up an accent mark that it "
+            + "doesn't have when standing alone.  Second, each multiple of 100 has "
+            + "to be specified separately because the multiplier on 100 very often "
+            + "changes form in the contraction: 500 is \"quinientos,\" not "
+            + "\"cincocientos.\"  In addition, the word for 100 is \"cien\" when "
+            + "standing alone, but changes to \"ciento\" when followed by more digits.  "
+            + "There also some other differences.",
+
+            "French adds some interesting quirks of its "
+            + "own: 1) The word \"et\" is interposed between the tens and ones digits, "
+            + "but only if the ones digit if 1: 20 is \"vingt,\" and 2 is \"vingt-deux,\" "
+            + "but 21 is \"vingt-et-un.\"  2)  There are no words for 70, 80, or 90.  "
+            + "\"quatre-vingts\" (\"four twenties\") is used for 80, and values proceed "
+            + "by score from 60 to 99 (e.g., 73 is \"soixante-treize\" [\"sixty-thirteen\"]).  "
+            + "Numbers from 1,100 to 1,199 are rendered as hundreds rather than "
+            + "thousands: 1,100 is \"onze cents\" (\"eleven hundred\"), rather than "
+            + "\"mille cent\" (\"one thousand one hundred\")",
+
+            "Swiss French differs from French French "
+            + "in that it does have words for 70, 80, and 90.  This rule set shows them, "
+            + "and is simpler as a result.",
+
+            "German also adds some interesting "
+            + "characteristics.  For values below 1,000,000, numbers are customarily "
+            + "written out as a single word.  And the ones digit PRECEDES the tens "
+            + "digit (e.g., 23 is \"dreiundzwanzig,\" not \"zwanzigunddrei\").",
+
+            "Like German, most Italian numbers are "
+            + "written as single words.  What makes these rules complicated is the rule "
+            + "that says that when a word ending in a vowel and a word beginning with "
+            + "a vowel are combined into a compound, the vowel is dropped from the "
+            + "end of the first word: 180 is \"centottanta,\" not \"centoottanta.\"  "
+            + "The complexity of this rule set is to produce this behavior.",
+
+            "Spellout rules for Swedish.",
+
+            "Spellout rules for Dutch.  Notice that in Dutch, as in German,"
+            + "the ones digit precedes the tens digit.",
+
+            "In Japanese, there really isn't any "
+            + "distinction between a number written out in digits and a number "
+            + "written out in words: the ideographic characters are both digits "
+            + "and words.  This rule set provides two variants:  %traditional "
+            + "uses the traditional CJK numerals (which are also used in China "
+            + "and Korea).  %financial uses alternate ideographs for many numbers "
+            + "that are harder to alter than the traditional numerals (one could "
+            + "fairly easily change a one to "
+            + "a three just by adding two strokes, for example).  This is also done in "
+            + "the other countries using Chinese idographs, but different ideographs "
+            + "are used in those places.",
+
+            "Again in Greek we have to supply the words "
+            + "for the multiples of 100 because they can't be derived algorithmically.  "
+            + "Also, the tens dgit changes form when followed by a ones digit: an "
+            + "accent mark disappears from the tens digit and moves to the ones digit.  "
+            + "Therefore, instead of using the [] notation, we actually have to use "
+            + "two separate rules for each multiple of 10 to show the two forms of "
+            + "the word.",
+
+            "Spellout rules for Russian.",
+
+            "Spellout rules for Hebrew.  Hebrew actually has inflected forms for "
+            + "most of the lower-order numbers.  The masculine forms are shown "
+            + "here.",
+
+            "This rule set adds an English ordinal abbreviation to the end of a "
+            + "number.  For example, 2 is formatted as \"2nd\".  Parsing doesn't work with "
+            + "this rule set.  To parse, use DecimalFormat on the numeral.",
+
+            "This is a simple message-formatting example.  Normally one would "
+            + "use ChoiceFormat and MessageFormat to do something this simple, "
+            + "but this shows it could be done with RuleBasedNumberFormat too.  "
+            + "A message-formatting example that might work better with "
+            + "RuleBasedNumberFormat appears later.",
+
+            "The next few examples demonstrate fraction handling.  "
+            + "This example formats a number in one of the two styles often used "
+            + "on checks.  %dollars-and-hundredths formats cents as hundredths of "
+            + "a dollar (23.40 comes out as \"twenty-three and 40/100 dollars\").  "
+            + "%dollars-and-cents formats in dollars and cents (23.40 comes out as "
+            + "\"twenty-three dollars and forty cents\")",
+
+            "This rule set shows the fractional part of the number as a fraction "
+            + "with a power of 10 as the denominator.  Some languages don't spell "
+            + "out the fractional part of a number as \"point one two three,\" but "
+            + "always render it as a fraction.  If we still want to treat the fractional "
+            + "part of the number as a decimal, then the fraction's denominator "
+            + "is always a power of 10.  This example does that: 23.125 is formatted "
+            + "as \"twenty-three and one hundred twenty-five thousandths\" (as opposed "
+            + "to \"twenty-three point one two five\" or \"twenty-three and one eighth\").",
+
+            "Number with closest fraction.  This example formats a value using "
+            + "numerals, but shows the fractional part as a ratio (fraction) rather "
+            + "than a decimal.  The fraction always has a denominator between 2 and 10.",
+
+            "American stock-price formatting.  Non-integral stock prices are still "
+            + "generally shown in eighths or sixteenths of dollars instead of dollars "
+            + "and cents.  This example formats stock prices in this way if possible, "
+            + "and in dollars and cents if not.",
+
+            "The next few examples demonstrate using a RuleBasedNumberFormat to "
+            + "change the units a value is denominated in depending on its magnitude.  "
+            + "The example shows large numbers the way they often appear is nwespapers: "
+            + "1,200,000 is formatted as \"1.2 million\".",
+
+            "This example takes a number of meters and formats it in whatever unit "
+            + "will produce a number with from one to three digits before the decimal "
+            + "point.  For example, 230,000 is formatted as \"230 km\".",
+
+            "A more complicated message-formatting example.  Here, in addition to "
+            + "handling the singular and plural versions of the word, the value is "
+            + "denominated in bytes, kilobytes, or megabytes depending on its magnitude.  "
+            + "Also notice that it correctly treats a kilobyte as 1,024 bytes (not 1,000), "
+            + "and a megabyte as 1,024 kilobytes (not 1,000).",
+
+            "This example formats a number in dozens and gross.  This is intended to "
+            + "demonstrate how this rule set can be used to format numbers in systems "
+            + "other than base 10.  The \"/12\" after the rules' base values controls this.  "
+            + "Also notice that the base doesn't have to be consistent throughout the "
+            + "whole rule set: we go back to base 10 for values over 1,000.",
+
+            "The next few examples show how a single value can be divided up into major "
+            + "and minor units that don't relate to each other by a factor of 10.  "
+            + "This example formats a number of seconds in sexagesimal notation "
+            + "(i.e., hours, minutes, and seconds).  %with-words formats it with "
+            + "words (3740 is \"1 hour, 2 minutes, 20 seconds\") and %in-numerals "
+            + "formats it entirely in numerals (3740 is \"1:02:20\").",
+
+            "This example formats a number of hours in sexagesimal notation (i.e., "
+            + "hours, minutes, and seconds).  %with-words formats the value using "
+            + "words for the units, and %in-numerals formats the value using only "
+            + "numerals.",
+
+            "This rule set formats a number of pounds as pounds, shillings, and "
+            + "pence in the old English system of currency.",
+
+            "These examples show how RuleBasedNumberFormat can be used to format "
+            + "numbers using non-positional numeration systems.  "
+            + "This example formats numbers in Arabic numerals.  "
+            + "Normally, you'd do this with DecimalFormat, but this shows that "
+            + "RuleBasedNumberFormat can handle it too.",
+
+            "This example follows the same pattern as the Arabic-numerals "
+            + "example, but uses words for the various digits (e.g., 123 comes "
+            + "out as \"one two three\").",
+
+            "This example formats numbers using Chinese characters in the Arabic "
+            + "place-value method.  This was used historically in China for a while.",
+
+            "Roman numerals.  This example has two variants: %modern shows how large "
+            + "numbers are usually handled today; %historical ses the older symbols for "
+            + "thousands.  Not all of the characters are displayable with most fonts.",
+
+            "Hebrew alphabetic numerals.  Before adoption of Arabic numerals, Hebrew speakers "
+            + "used the letter of their alphabet as numerals.  The first nine letters of "
+            + "the alphabet repesented the values from 1 to 9, the second nine letters the "
+            + "multiples of 10, and the remaining letters the multiples of 100.  Since they "
+            + "ran out of letters at 400, the remaining multiples of 100 were represented "
+            + "using combinations of the existing letters for the hundreds.  Numbers were "
+            + "distinguished from words in a number of different ways: the way shown here "
+            + "uses a single mark after a number consisting of one letter, and a double "
+            + "mark between the last two letters of a number consisting of two or more "
+            + "letters.  Two dots over a letter multiplied its value by 1,000.  Also, since "
+            + "the letter for 10 is the first letter of God's name and the letters for 5 and 6 "
+            + "are letters in God's name, which wasn't supposed to be written or spoken, 15 and "
+            + "16 were usually written as 9 + 6 and 9 + 7 instead of 10 + 5 and 10 + 6.",
+
+            "Greek alphabetic numerals.  The Greeks, before adopting the Arabic numerals, "
+            + "also used the letters of their alphabet as numerals.  There are three now-"
+            + "obsolete Greek letters that are used as numerals; many fonts don't have them.  "
+            + "Large numbers were handled many different ways; the way shown here divides "
+            + "large numbers into groups of four letters (factors of 10,000), and separates "
+            + "the groups with the capital letter mu (for myriad).  Capital letters are used "
+            + "for values below 10,000; small letters for higher numbers (to make the capital "
+            + "mu stand out).",
+
+            "This is a custom (user-defined) rule set."
+        };
+}
diff --git a/src/com/ibm/demo/rbnf/package.html b/src/com/ibm/demo/rbnf/package.html
new file mode 100755
index 0000000..48917ae
--- /dev/null
+++ b/src/com/ibm/demo/rbnf/package.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--  Copyright (C) 2000, International Business Machines Corporation and
+  others. All Rights Reserved.
+
+  $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/rbnf/Attic/package.html,v $
+  $Revision: 1.1 $
+  $Date: 2000/03/15 17:44:02 $
+-->
+</head>
+<body bgcolor="white">
+RuleBasedNumberFormat demo appliation.
+</body>
+</html>
\ No newline at end of file
diff --git a/src/com/ibm/demo/translit/Demo.java b/src/com/ibm/demo/translit/Demo.java
new file mode 100755
index 0000000..83b91fb
--- /dev/null
+++ b/src/com/ibm/demo/translit/Demo.java
@@ -0,0 +1,266 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/translit/Attic/Demo.java,v $ 
+ * $Date: 2000/03/10 03:47:44 $ 
+ * $Revision: 1.4 $
+ *
+ *****************************************************************************************
+ */
+package com.ibm.demo.translit;
+import java.applet.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import com.ibm.text.components.*;
+import com.ibm.text.*;
+
+/**
+ * A frame that allows the user to experiment with keyboard
+ * transliteration.  This class has a main() method so it can be run
+ * as an application.  The frame contains an editable text component
+ * and uses keyboard transliteration to process keyboard events.
+ *
+ * <p>Copyright (c) IBM Corporation 1999.  All rights reserved.
+ *
+ * @author Alan Liu
+ * @version $RCSfile: Demo.java,v $ $Revision: 1.4 $ $Date: 2000/03/10 03:47:44 $
+ */
+public class Demo extends Frame {
+
+    static final boolean DEBUG = false;
+
+    Transliterator translit = null;
+
+    boolean compound = false;
+    Transliterator[] compoundTranslit = new Transliterator[MAX_COMPOUND];
+    static final int MAX_COMPOUND = 128;
+    int compoundCount = 0;
+
+    TransliteratingTextComponent text = null;
+
+    Menu translitMenu;
+    CheckboxMenuItem translitItem;
+    CheckboxMenuItem noTranslitItem;
+
+    static final String NO_TRANSLITERATOR = "None";
+
+    private static final String COPYRIGHT =
+        "\u00A9 IBM Corporation 1999. All rights reserved.";
+
+    public static void main(String[] args) {
+        Frame f = new Demo(600, 200);
+        f.addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent e) {
+                System.exit(0);
+            }
+        });
+        f.setVisible(true);
+    }
+
+	public Demo(int width, int height) {
+        super("Transliteration Demo");
+
+        initMenus();
+
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent e) {
+                handleClose();
+            }
+        });
+        
+        text = new TransliteratingTextComponent();
+        Font font = new Font("serif", Font.PLAIN, 48);
+        text.setFont(font);
+        text.setSize(width, height);
+        text.setVisible(true);
+        text.setText("\u03B1\u05D0\u3042\u4E80");
+        add(text);
+
+        setSize(width, height);
+    }
+
+    private void initMenus() {
+        MenuBar mbar;
+        Menu menu;
+        MenuItem mitem;
+        CheckboxMenuItem citem;
+        
+        setMenuBar(mbar = new MenuBar());
+        mbar.add(menu = new Menu("File"));
+        menu.add(mitem = new MenuItem("Quit"));
+        mitem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                handleClose();
+            }
+        });
+
+        final ItemListener setTransliteratorListener = new ItemListener() {
+            public void itemStateChanged(ItemEvent e) {
+                CheckboxMenuItem item = (CheckboxMenuItem) e.getSource();
+                if (e.getStateChange() == ItemEvent.DESELECTED) {
+                    // Don't let the current transliterator be deselected.
+                    // Just reselect it.
+                    item.setState(true);
+                } else if (compound) {
+                    // Adding an item to a compound transliterator
+                    handleAddToCompound(item.getLabel());
+                } else if (item != translitItem) {
+                    // Deselect previous choice.  Don't need to call
+                    // setState(true) on new choice.
+                    translitItem.setState(false);
+                    translitItem = item;
+                    handleSetTransliterator(item.getLabel());
+                }
+            }
+        };
+
+        translit = null;
+        mbar.add(translitMenu = new Menu("Transliterator"));
+        translitMenu.add(translitItem = noTranslitItem =
+                         new CheckboxMenuItem(NO_TRANSLITERATOR, true));
+        noTranslitItem.addItemListener(new ItemListener() {
+            public void itemStateChanged(ItemEvent e) {
+                // Can't uncheck None -- any action here sets None to true
+                setNoTransliterator();
+            }
+        });
+
+        translitMenu.addSeparator();
+
+        translitMenu.add(citem = new CheckboxMenuItem("Compound"));
+        citem.addItemListener(new ItemListener() {
+            public void itemStateChanged(ItemEvent e) {
+                CheckboxMenuItem item = (CheckboxMenuItem) e.getSource();
+                if (e.getStateChange() == ItemEvent.DESELECTED) {
+                    // If compound gets deselected, then select NONE
+                    setNoTransliterator();
+                } else if (!compound) {
+                    // Switching from non-compound to compound
+                    translitItem.setState(false);
+                    translitItem = item;
+                    translit = null;
+                    compound = true;
+                    compoundCount = 0;
+                    for (int i=0; i<MAX_COMPOUND; ++i) {
+                        compoundTranslit[i] = null;
+                    }
+                }
+            }
+        });
+      
+        translitMenu.addSeparator();
+
+        for (Enumeration e=getSystemTransliteratorNames().elements();
+             e.hasMoreElements(); ) {
+            String s = (String) e.nextElement();
+            translitMenu.add(citem = new CheckboxMenuItem(s));
+            citem.addItemListener(setTransliteratorListener);
+        }
+
+        mbar.add(menu = new Menu("Batch"));
+        menu.add(mitem = new MenuItem("Transliterate Selection"));
+        mitem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                handleBatchTransliterate();
+            }
+        });
+    }
+
+    /**
+     * Get a sorted list of the system transliterators.
+     */
+    private static Vector getSystemTransliteratorNames() {
+        Vector v = new Vector();
+        for (Enumeration e=Transliterator.getAvailableIDs();
+             e.hasMoreElements(); ) {
+            v.addElement(e.nextElement());
+        }
+        // Insertion sort, O(n^2) acceptable for small n
+        for (int i=0; i<(v.size()-1); ++i) {
+            String a = (String) v.elementAt(i);
+            for (int j=i+1; j<v.size(); ++j) {
+                String b = (String) v.elementAt(j);
+                if (a.compareTo(b) > 0) {
+                    v.setElementAt(b, i);
+                    v.setElementAt(a, j);
+                    a = b;
+                }
+            }
+        }
+        return v;
+    }
+
+    private void setNoTransliterator() {
+        translitItem = noTranslitItem;
+        noTranslitItem.setState(true);
+        handleSetTransliterator(noTranslitItem.getLabel());
+        compound = false;
+        for (int i=0; i<translitMenu.getItemCount(); ++i) {
+            MenuItem it = translitMenu.getItem(i);
+            if (it != noTranslitItem && it instanceof CheckboxMenuItem) {
+                ((CheckboxMenuItem) it).setState(false);
+            }
+        }
+    }
+
+    private void handleAddToCompound(String name) {
+        if (compoundCount < MAX_COMPOUND) {
+            compoundTranslit[compoundCount] = decodeTranslitItem(name);
+            ++compoundCount;
+            Transliterator t[] = new Transliterator[compoundCount];
+            System.arraycopy(compoundTranslit, 0, t, 0, compoundCount);
+            translit = new CompoundTransliterator(t);
+            text.setTransliterator(translit);
+        }
+    }
+
+    private void handleSetTransliterator(String name) {
+        translit = decodeTranslitItem(name);
+        text.setTransliterator(translit);
+    }
+
+    /**
+     * Decode a menu item that looks like <translit name>.
+     */
+    private static Transliterator decodeTranslitItem(String name) {
+        return (name.equals(NO_TRANSLITERATOR))
+            ? null : Transliterator.getInstance(name);
+    }
+
+    private void handleBatchTransliterate() {
+        if (translit == null) {
+            return;
+        }
+
+        int start = text.getSelectionStart();
+        int end = text.getSelectionEnd();
+        ReplaceableString s =
+            new ReplaceableString(text.getText().substring(start, end));
+
+        StringBuffer log = null;
+        if (DEBUG) {
+            log = new StringBuffer();
+            log.append('"' + s.toString() + "\" (start " + start +
+                       ", end " + end + ") -> \"");
+        }
+
+        translit.transliterate(s);
+        String str = s.toString();
+
+        if (DEBUG) {
+            log.append(str + "\"");
+            System.out.println("Batch " + translit.getID() + ": " + log.toString());
+        }
+
+        text.replaceRange(str, start, end);
+        text.select(start, start + str.length());
+    }
+
+    private void handleClose() {
+        dispose();
+    }
+}
diff --git a/src/com/ibm/demo/translit/DemoApplet.java b/src/com/ibm/demo/translit/DemoApplet.java
new file mode 100755
index 0000000..77fb815
--- /dev/null
+++ b/src/com/ibm/demo/translit/DemoApplet.java
@@ -0,0 +1,74 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2000, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/translit/Attic/DemoApplet.java,v $ 
+ * $Date: 2000/03/10 03:47:44 $ 
+ * $Revision: 1.4 $
+ *
+ *****************************************************************************************
+ */
+package com.ibm.demo.translit;
+import java.awt.*;
+import java.awt.event.*;
+import java.applet.*;
+import com.ibm.text.components.AppletFrame;
+
+/**
+ * A simple Applet that shows a button.  When pressed, the button
+ * shows the DemoAppletFrame.  This Applet is meant to be embedded
+ * in a web page.
+ *
+ * <p>Copyright (c) IBM Corporation 1999.  All rights reserved.
+ *
+ * @author Alan Liu
+ * @version $RCSfile: DemoApplet.java,v $ $Revision: 1.4 $ $Date: 2000/03/10 03:47:44 $
+ */
+public class DemoApplet extends Applet {
+
+    Demo frame = null;
+    
+    private static final String COPYRIGHT =
+        "\u00A9 IBM Corporation 1999. All rights reserved.";
+
+    public static void main(String args[]) {
+        final DemoApplet applet = new DemoApplet();
+        new AppletFrame("Transliteration Demo", applet, 640, 480);
+    }
+
+	public void init() {
+
+		Button button = new Button("Transliteration Demo");
+		button.addActionListener(new ActionListener() {
+		    public void actionPerformed(ActionEvent e) {
+		        if (frame == null) {
+                    frame = new Demo(600, 200);
+                    frame.addWindowListener(new WindowAdapter() {
+                        public void windowClosing(WindowEvent we) {
+                            frame = null;
+                        }
+                    });
+                }
+                frame.setVisible(true);
+                frame.toFront();
+		    }
+		});
+
+		add(button);
+
+        Dimension size = button.getPreferredSize();
+        size.width += 10;
+        size.height += 10;
+
+		resize(size);
+	}
+	
+    public void stop() {
+        if (frame != null) {
+            frame.dispose();
+        }
+        frame = null;
+    }
+}
diff --git a/src/com/ibm/demo/translit/demo.bat b/src/com/ibm/demo/translit/demo.bat
new file mode 100755
index 0000000..36f8b78
--- /dev/null
+++ b/src/com/ibm/demo/translit/demo.bat
@@ -0,0 +1,19 @@
+REM /*
+REM *******************************************************************************
+REM  * Copyright (C) 1996-2000, International Business Machines Corporation and    *
+REM  * others. All Rights Reserved.                                                *
+REM  *******************************************************************************
+REM  *
+REM  * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/translit/Attic/demo.bat,v $ 
+REM  * $Date: 2000/03/10 03:47:44 $ 
+REM  * $Revision: 1.2 $
+REM  *
+REM  *****************************************************************************************
+REM  */
+REM For best results, run the demo as an applet inside of Netscape
+REM with Bitstream Cyberbit installed.
+
+REM setup your JDK 1.1.x path and classpath here:
+call JDK11
+set CLASSPATH=../translit.jar;%CLASSPATH%
+javaw Demo
diff --git a/src/com/ibm/demo/translit/demo.html b/src/com/ibm/demo/translit/demo.html
new file mode 100755
index 0000000..c655dc9
--- /dev/null
+++ b/src/com/ibm/demo/translit/demo.html
@@ -0,0 +1,27 @@
+<HTML>
+<HEAD>
+<TITLE>Transliteration Demo</TITLE>
+</HEAD>
+<BODY>
+
+<APPLET CODE="com.ibm.demo.translit.DemoApplet.class" WIDTH=140 HEIGHT=33></APPLET>
+
+<HR>
+
+If you don't see a button above, then your browser is failing to
+locate the necessary Java class files.
+
+<P>
+
+One way to make this work is to copy this HTML file to
+<code>icu4j/src</code>, and make sure the Java files in the directories
+under <code>icu4j/src/com</code> are built.  Then open this HTML file
+using a browser or appletviewer.
+
+<P>
+
+For best results, run this demo as an applet within Netscape with
+Bitstream Cyberbit installed.
+
+</BODY>
+</HTML>
diff --git a/src/com/ibm/demo/translit/package.html b/src/com/ibm/demo/translit/package.html
new file mode 100755
index 0000000..3f4e5b9
--- /dev/null
+++ b/src/com/ibm/demo/translit/package.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--  Copyright (C) 2000, International Business Machines Corporation and
+  others. All Rights Reserved.
+
+  $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/demo/translit/Attic/package.html,v $
+  $Revision: 1.1 $
+  $Date: 2000/03/15 17:44:12 $
+-->
+</head>
+<body bgcolor="white">
+Transliterator demo appliation.
+</body>
+</html>
\ No newline at end of file
diff --git a/src/com/ibm/icu/internal/UInfo.java b/src/com/ibm/icu/internal/UInfo.java
new file mode 100755
index 0000000..05927f0
--- /dev/null
+++ b/src/com/ibm/icu/internal/UInfo.java
@@ -0,0 +1,610 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2001, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/internal/Attic/UInfo.java,v $ 
+ * $Date: 2001/09/08 01:13:38 $ 
+ * $Revision: 1.3 $
+ *
+ *****************************************************************************************
+ */
+
+package com.ibm.icu.internal;
+
+import java.io.*;
+import java.util.*;
+import com.ibm.util.Utility;
+
+public final class UInfo {
+    static final boolean DEBUG = false;
+    static final int UINFO_VERSION = 5;
+
+    // these values are aligned with the java.lang.Character constants
+
+    public static final byte
+    UNASSIGNED      = 0,
+    UPPERCASE_LETTER    = 1,
+    LOWERCASE_LETTER    = 2,
+    TITLECASE_LETTER    = 3,
+    MODIFIER_LETTER     = 4,
+    OTHER_LETTER        = 5,
+    NON_SPACING_MARK    = 6,
+    ENCLOSING_MARK      = 7,
+    COMBINING_SPACING_MARK  = 8,
+    DECIMAL_DIGIT_NUMBER    = 9,
+    LETTER_NUMBER       = 10,
+    OTHER_NUMBER        = 11,
+    SPACE_SEPARATOR     = 12,
+    LINE_SEPARATOR      = 13,
+    PARAGRAPH_SEPARATOR = 14,
+    CONTROL         = 15,
+    FORMAT          = 16,
+    PRIVATE_USE     = 18,
+    SURROGATE       = 19,
+    DASH_PUNCTUATION    = 20,
+    START_PUNCTUATION   = 21,
+    END_PUNCTUATION     = 22,
+    CONNECTOR_PUNCTUATION   = 23,
+    OTHER_PUNCTUATION   = 24,
+    MATH_SYMBOL     = 25,
+    CURRENCY_SYMBOL     = 26,
+    MODIFIER_SYMBOL     = 27,
+    OTHER_SYMBOL        = 28;
+
+    public String getName(char ch) {return getInfo(ch).name;}
+    public String getDecomposition(char ch) {return getInfo(ch).decomposition;}
+    public String getName10(char ch) {return getInfo(ch).name10;}
+    public String getComment(char ch) {return getInfo(ch).comment;}
+
+    public float getNumeric(char ch) {return getInfo(ch).numeric;}
+
+    public short getCanonicalClass(char ch) {return getInfo(ch).canonical;}
+    public short getDecimal(char ch) {return getInfo(ch).decimal;}
+    public short getDigit(char ch) {return getInfo(ch).digit;}
+
+    public char getUppercase(char ch) {return getInfo(ch).uppercase;}
+    public char getLowercase(char ch) {return getInfo(ch).lowercase;}
+    public char getTitlecase(char ch) {return getInfo(ch).titlecase;}
+
+    public byte getCategory(char ch) {return getInfo(ch).category;}
+    public byte getBidiClass(char ch) {return getInfo(ch).bidi;}
+    public boolean getMirrored(char ch) {return getInfo(ch).mirrored;}
+
+    public boolean isDisparaged(char ch) { return getDecomposition(ch).length() == 4; }
+
+    public boolean isLetter(char ch) {
+        return (0 != ((1<<getCategory(ch)) &
+          ((1<<UPPERCASE_LETTER)
+          | (1<<LOWERCASE_LETTER)
+          | (1<<TITLECASE_LETTER)
+          | (1<<MODIFIER_LETTER)
+          | (1<<MODIFIER_LETTER))));
+    }
+
+    public boolean isMark(char ch) {
+        return (0 != ((1<<getCategory(ch)) &
+          ((1<<NON_SPACING_MARK)
+          | (1<<ENCLOSING_MARK)
+          | (1<<COMBINING_SPACING_MARK))));
+    }
+
+    public boolean isNumber(char ch) {
+        return (0 != ((1<<getCategory(ch)) &
+          ((1<<DECIMAL_DIGIT_NUMBER)
+          | (1<<LETTER_NUMBER)
+          | (1<<OTHER_NUMBER))));
+    }
+
+    public boolean isSeparator(char ch) {
+        return (0 != ((1<<getCategory(ch)) &
+          ((1<<SPACE_SEPARATOR)
+          | (1<<LINE_SEPARATOR)
+          | (1<<PARAGRAPH_SEPARATOR))));
+    }
+
+    public boolean isFormat(char ch) {
+        return (0 != ((1<<getCategory(ch)) &
+          ((1<<CONTROL)
+          | (1<<FORMAT))));
+    }
+
+    public boolean isPunctuation(char ch) {
+        return (0 != ((1<<getCategory(ch)) &
+          ((1<<DASH_PUNCTUATION)
+          | (1<<START_PUNCTUATION)
+          | (1<<END_PUNCTUATION)
+          | (1<<CONNECTOR_PUNCTUATION)
+          | (1<<START_PUNCTUATION)
+          | (1<<END_PUNCTUATION)
+          | (1<<OTHER_PUNCTUATION))));
+    }
+
+    public boolean isSymbol(char ch) {
+        return (0 != ((1<<getCategory(ch)) &
+          ((1<<MATH_SYMBOL)
+          | (1<<CURRENCY_SYMBOL)
+          | (1<<MODIFIER_SYMBOL)
+          | (1<<OTHER_SYMBOL))));
+    }
+
+    //
+    // Characters excluded from composition.  This is read from the Unicode
+    // file CompositionExclusions.txt.
+    //
+    String composeExclude = "";
+
+    /**
+     * Is this character excluded from the composition algorithm by virtue
+     * of being listed in the composition exclusion table in Tech Report #15?
+     */
+    public boolean isExcludedComposition(char ch) {
+        return isDisparaged(ch)
+            || composeExclude.indexOf(ch) >= 0
+            || getCanonicalClass(getDecompositionChars(ch).charAt(0)) != 0;
+    }
+
+
+
+    public String getName(String s) {
+        return getName(s,true);
+    }
+
+    public String getName(String s, boolean shortVersion) {
+        StringBuffer temp = new StringBuffer();
+        for (int i = 0; i < s.length(); ++i) {
+            if (i != 0) temp.append(", ");
+            temp.append(getName(s.charAt(i), shortVersion));
+        }
+        return temp.toString();
+    }
+
+    public String getName(char ch, boolean shortVersion) {
+        String result = getName(ch);
+        if (!shortVersion) return result;
+        result = replace(result,"LETTER ","");
+        result = replace(result,"CHARACTER ","");
+        result = replace(result,"SIGN ","");
+        result = replace(result,"CAPITAL ","UC ");
+        if (getCategory(ch) == LOWERCASE_LETTER)
+          result = replace(result,"SMALL ","LC ");
+        result = replace(result,"COMBINING ","-");
+        result = replace(result,"WITH ","");
+        result = replace(result,"AND ","");
+        result = replace(result,"VARIA","GRAVE");
+        result = replace(result,"OXIA","ACUTE");
+        result = replace(result,"VRACHY","BREVE");
+        result = replace(result,"VERTICAL LINE ABOVE","TONOS");
+        result = replace(result,"PSILI","SMOOTH");
+        result = replace(result,"DASIA","ROUGH");
+        result = replace(result,"COMMA ABOVE","SMOOTH");
+        result = replace(result,"REVERSED COMMA ABOVE","ROUGH");
+        result = replace(result,"YPOGEGRAMMENI","IOTA-SUB");
+        result = replace(result,"PROSGEGRAMMENI","IOTA-AD");
+        result = replace(result,"DIALYTIKA","DIAERESIS");
+        result = replace(result,"PERISPOMENI","CIRCUMFLEX");
+        result = replace(result,"VOICED SOUND MARK","VOICED SIGN");
+        result = replace(result,"PROLONGED SOUND MARK","VOICED SIGN");
+        result = replace(result,"KATAKANA-HIRAGANA","KANA");
+        result = replace(result,"COMPATIBILITY IDEOGRAPH-","");
+        result = replace(result,"CHOSEONG","INITIAL");
+        result = replace(result,"JUNGSEONG","MEDIAL");
+        result = replace(result,"JONGSEONG","FINAL");
+
+        return result.substring(0,1)
+          + result.substring(1,result.length()).toLowerCase();
+    }
+
+    public String replace(String source,
+      String replacee, String replacer) {
+        int p = source.indexOf(replacee);
+        if (p == -1) return source;
+        return source.substring(0,p)
+          + replacer
+          + source.substring(p+replacee.length(),source.length());
+    }
+
+    public boolean isCCS(String s) {
+        if (s.length() < 2) return false;
+        if (isMark(s.charAt(0))) return false;
+        for (int i = 1; i < s.length(); ++i) {
+            if (!isMark(s.charAt(i))) return false;
+        }
+        return true;
+    }
+
+    // combining base sequence := <cat_zero>+ <cat_pos>*
+    public boolean isCBS(String s) {
+        if (s.length() == 0) return false;
+        if (getCanonicalClass(s.charAt(0)) != 0) return false;
+        boolean gotGreater = false;
+        for (int i = 1; i < s.length(); ++i) {
+            if (getCanonicalClass(s.charAt(i)) == 0) {
+                if (gotGreater) return false;
+            } else {
+                gotGreater = true;
+            }
+        }
+        return true;
+    }
+
+    public boolean hasCanonicalDecomposition(char ch) {
+        String decomp = getDecomposition(ch);
+        return (decomp.length() != 0 && decomp.indexOf('<') == -1);
+    }
+
+    public boolean hasCompatibilityDecomposition(char ch) {
+        String decomp = getDecomposition(ch);
+        return (decomp.length() != 0 && decomp.indexOf('<') != -1);
+    }
+
+    public boolean isEquivalent(
+      String a, String b, boolean canonical) {
+        return getFullDecomposition(a, canonical).equals(
+          getFullDecomposition(b, canonical));
+    }
+
+    // use very dumb algorithm. Don't need lower order one.
+
+    public String getFullDecomposition(
+      String s, boolean canonical) {
+        StringBuffer output = new StringBuffer();
+        for (int i = 0; i < s.length(); ++i) {
+            getFullDecomp2(s.charAt(i),canonical,output);
+        }
+        return fixCanonical(output).toString();
+    }
+
+    public StringBuffer getFullDecomposition(
+      char ch, boolean canonical, StringBuffer output) {
+
+        StringBuffer result = getFullDecomp2(ch,canonical,output);
+        return fixCanonical(result);
+    }
+
+    public String getFullDecomposition(
+      char ch, boolean canonical) {
+        return getFullDecomposition(ch, canonical, new StringBuffer()).toString();
+    }
+
+    /**
+     * Given a decomposed string of characters, put it in canonical
+     * order by finding and processing all exchangeable pairs.
+     */
+    public StringBuffer fixCanonical(StringBuffer target) {
+        for (int i = 1; i < target.length(); ++i) {
+            char ch = target.charAt(i);
+            short canClass = getCanonicalClass(ch);
+            char chPrev = target.charAt(i-1);
+            short canClassPrev = getCanonicalClass(chPrev);
+            if (canClass != 0 && canClass < canClassPrev) {
+                target.setCharAt(i-1, ch);
+                target.setCharAt(i, chPrev);
+                if (i > 1) i -= 2; // backup (-1 to compensate for loop)
+            }
+        }
+        return target;
+    }
+
+    public String fixCanonical(String source) {
+        return fixCanonical(new StringBuffer(source)).toString();
+    }
+
+
+    // ============================================
+    //                  PRIVATES
+    // ============================================
+
+    static class CharData {
+        public CharData() {
+        };
+
+        String name = "";
+        String decomposition = "";
+        String name10 = "";
+        String comment = "";
+
+        float numeric = Float.MIN_VALUE;
+
+        short canonical = 0;
+        short decimal = Short.MIN_VALUE;
+        short digit = Short.MIN_VALUE;
+
+        char uppercase;
+        char lowercase;
+        char titlecase;
+
+        byte category;
+        byte bidi = 0;
+
+        boolean mirrored;
+    };
+
+    private static final CharData UNASSIGNED_INFO = new CharData();
+    private static char cachedChar = 0xFFFF;
+
+    private CharData getInfo(char ch) {
+        if (ch == cachedChar) return UNASSIGNED_INFO;
+        // remap special ranges
+        if (ch >= 0x4E00 && ch < 0xF900) {
+            if (ch <= 0x9FA5) ch = 0x4E00;
+            else if (ch >= 0xAC00 && ch <= 0xD7A3) ch = 0xAC00;
+            else if (ch >= 0xD800 && ch <= 0xDFFF) ch = 0xD800;
+            else if (ch >= 0xE000) ch = 0xE000;
+        }
+        Object value = cache[ch];
+        CharData result;
+        if (value == null) {
+            result = UNASSIGNED_INFO;
+        } else if (value instanceof String) {
+            result = updateCache((String)value);
+        } else {
+            result = (CharData)value;
+        }
+        return result;
+    }
+
+    private StringBuffer getFullDecomp2(
+      char ch, boolean canonical, StringBuffer output) {
+
+        String decomp = getDecomposition(ch);
+        if (decomp.length() == 0
+          || (canonical && decomp.indexOf('<') != -1)) {
+            output.append(ch);
+            return output;
+        }
+        boolean inBrackets = false;
+        for (int i = 0; i < decomp.length(); ++i) {
+            char c = decomp.charAt(i);
+            if (c == '<') inBrackets = true;
+            else if (c == '>') inBrackets = false;
+            else if (inBrackets) ; // skip
+            else if (c == ' ') ; // skip
+            else {
+                String tempString = decomp.substring(i,i+4);
+                char temp = (char)Integer.parseInt(tempString,16);
+                getFullDecomposition(temp,canonical,output);
+                i+= 3;
+            }
+        }
+        return output;
+    }
+
+    public String getDecompositionChars(char ch) {
+        StringBuffer output = new StringBuffer();
+        String decomp = getDecomposition(ch);
+        if (decomp.length() == 0) {
+            output.append(ch);
+            return output.toString();
+        }
+        boolean inBrackets = false;
+        for (int i = 0; i < decomp.length(); ++i) {
+            char c = decomp.charAt(i);
+            if (c == '<') inBrackets = true;
+            else if (c == '>') inBrackets = false;
+            else if (inBrackets) ; // skip
+            else if (c == ' ') ; // skip
+            else {
+                String tempString = decomp.substring(i,i+4);
+                char temp = (char)Integer.parseInt(tempString,16);
+                output.append(temp);
+                i+= 3;
+            }
+        }
+        return output.toString();
+    }
+
+    public UInfo(String fileName, String composeExcludeFileName) {
+        // not used long startTime,endTime;
+
+        BufferedReader input = null;
+        String line = null;
+        try {
+            input = new BufferedReader(new FileReader(fileName),64*1024);
+            for (int count = 0;;++count) {
+                line = input.readLine();
+                if (line == null) break;
+                if (line.length() == 0) continue;
+                char ch = charFrom(line.substring(0,4));
+                if (DEBUG) if ((count % 100) == 0)
+                    System.out.println("[" + count + "," + Utility.hex(ch) + ']');
+                cache[ch] = line;
+            }
+
+            // Read composition exlusions
+            input = new BufferedReader(new FileReader(composeExcludeFileName),64*1024);
+            StringBuffer ce = new StringBuffer();
+            for (;;) {
+                line = input.readLine();
+                if (line == null) break;
+                if (line.length() == 0 ||
+                    Character.digit(line.charAt(0), 16) < 0) continue;
+                ce.append(charFrom(line.substring(0,4)));
+            }
+            composeExclude = ce.toString();
+        } catch (Exception ex) {
+            try {
+                input.close();
+            } catch (Exception ex2) {
+                System.out.print("");
+            }
+            ex.printStackTrace();
+            throw new IllegalArgumentException("Couldn't read file "
+              + ex.getClass().getName() + " " + ex.getMessage()
+              + " line = " + line
+              );
+        }
+    }
+
+    public UInfo() {
+        // FIX
+        // This is bad...this path must be correct relative to the
+        // user's current directory.  I have changed it so that it's
+        // relative to the root icu4j directory, so it works as long
+        // as code is run from that directory, e.g., "java -classpath
+        // classes...".  A better way to do this might be to get it
+        // from a system property that is defined on the command line,
+        // e.g., "java -Dicu4j=D:/icu4j..." - liu
+        this("src/data/unicode/UnicodeData-3.0.0.txt",
+             "src/data/unicode/CompositionExclusions-1.txt");
+    }
+
+    /*
+  0 Code value in 4-digit hexadecimal format.
+  1 Unicode 2.1 Character Name. These names match exactly the
+  2 General Category. This is a useful breakdown into various "character
+  3 Canonical Combining Classes. The classes used for the
+  4 Bidirectional Category. See the list below for an explanation of the
+  5 Character Decomposition. In the Unicode Standard, not all of
+  6 Decimal digit value. This is a numeric field. If the character
+  7 Digit value. This is a numeric field. If the character represents a
+  8 Numeric value. This is a numeric field. If the character has the
+  9 If the characters has been identified as a "mirrored" character in
+ 10 Unicode 1.0 Name. This is the old name as published in Unicode 1.0.
+ 11 10646 Comment field. This field is informative.
+ 12 Upper case equivalent mapping. If a character is part of an
+ 13 Lower case equivalent mapping. Similar to 12. This field is informative.
+ 14 Title case equivalent mapping. Similar to 12. This field is informative.
+    */
+
+    private CharData updateCache(String line) {
+        try {
+            String[] parts = new String[30];
+            Utility.split(line,';',parts);
+            CharData info = new CharData();
+            char ch = charFrom(parts[0]);
+            info.name = parts[1];
+            info.category = (byte)Utility.lookup(parts[2], CATEGORY_TABLE);
+            info.canonical = shortFrom(parts[3]);
+            info.bidi = (byte)Utility.lookup(parts[4], BIDI_TABLE);
+            info.decomposition = parts[5];
+            info.decimal = shortFrom(parts[6]);
+            info.digit = shortFrom(parts[7]);
+            info.numeric = floatFrom(parts[8]);
+            info.mirrored = charFrom(parts[9]) == 'Y';
+            info.name10 = parts[10];
+            info.comment = parts[11];
+            info.uppercase = charFrom(parts[12]);
+            if (info.uppercase == 0) info.uppercase = ch;
+            info.lowercase = charFrom(parts[13]);
+            if (info.lowercase == 0) info.lowercase = ch;
+            info.titlecase = charFrom(parts[14]);
+            if (info.titlecase == 0) info.titlecase = info.uppercase;
+            String trial = Utility.hex(ch) + ";" + info;
+            if (DEBUG) if (!trial.equals(line)) {
+                System.out.println("Difference between:");
+                System.out.println(line);
+                System.out.println(trial);
+            }
+            cache[ch] = info;
+            return info;
+        }
+        catch (NumberFormatException e) {
+            System.out.println("updateCache: error parsing '" + line + "'");
+            throw e;
+        }
+    }
+
+    private static CharData typeInfo = new CharData();
+
+    private boolean latin1(char c) {
+        return ((c >= 20 && c <= 0x7F) || c > 0xA0);
+    }
+
+    private static final String[] YN_TABLE = {"N", "Y"};
+
+    private static final String[] CATEGORY_TABLE = {
+        "Cn", // = Other, Not Assigned
+
+        "Lu", // = Letter, Uppercase
+        "Ll", // = Letter, Lowercase
+        "Lt", // = Letter, Titlecase
+        "Lm", // = Letter, Modifier
+        "Lo", // = Letter, Other
+
+        "Mn", // = Mark, Non-Spacing
+        "Me", // = Mark, Enclosing
+        "Mc", // = Mark, Spacing Combining
+
+        "Nd", // = Number, Decimal Digit
+        "Nl", // = Number, Letter
+        "No", // = Number, Other
+
+        "Zs", // = Separator, Space
+        "Zl", // = Separator, Line
+        "Zp", // = Separator, Paragraph
+
+        "Cc", // = Other, Control
+        "Cf", // = Other, Format
+        "",   // unused
+        "Co", // = Other, Private Use
+        "Cs", // = Other, Surrogate
+
+
+        "Pd", // = Punctuation, Dash
+        "Ps", // = Punctuation, Open
+        "Pe", // = Punctuation, Close
+        "Pc", // = Punctuation, Connector
+        "Po", // = Punctuation, Other
+
+        "Sm", // = Symbol, Math
+        "Sc", // = Symbol, Currency
+        "Sk", // = Symbol, Modifier
+        "So", // = Symbol, Other
+
+        "Pi", // = Punctuation, Initial quote (may behave like Ps or Pe depending on usage)
+        "Pf", // = Punctuation, Final quote (may behave like Ps or Pe dependingon usage)
+    };
+
+    private static String[] BIDI_TABLE = {
+        "L", // Left-Right; Most alphabetic, syllabic, and logographic characters (e.g., CJK ideographs)
+        "R", // Right-Left; Arabic, Hebrew, and punctuation specific to those scripts
+        "EN", //    European Number
+        "ES", //    European Number Separator
+        "ET", //    European Number Terminator
+        "AN", //    Arabic Number
+        "CS", //    Common Number Separator
+        "B", // Block Separator
+        "S", // Segment Separator
+        "WS", //    Whitespace
+        "ON" // Other Neutrals ; All other characters: punctuation, symbols
+    };
+
+    private static short shortFrom(String p) {
+        if (p.length() == 0) return Short.MIN_VALUE;
+        return Short.parseShort(p);
+    }
+
+    private static float floatFrom(String p) {
+        try {
+            if (p.length() == 0) return Float.MIN_VALUE;
+            int fract = p.indexOf('/');
+            if (fract == -1) return Float.valueOf(p).floatValue();
+            String q = p.substring(0,fract);
+            float num = 0;
+            if (q.length() != 0) num = Integer.parseInt(q);
+            p = p.substring(fract+1,p.length());
+            float den = 0;
+            if (p.length() != 0) den = Integer.parseInt(p);
+            return num/den;
+        }
+        catch (NumberFormatException e) {
+            System.out.println("floatFrom: error parsing '" + p + "'");
+            throw e;
+        }
+    }
+
+    private static char charFrom(String p) {
+        if (p.length() == 0) return '\u0000';
+        else if (p.length() == 1) return p.charAt(0);
+        int temp = Integer.parseInt(p, 16);
+        if (temp < 0 || temp > 0xFFFF)
+            throw new NumberFormatException(
+                "Hex char out of range: " + p);
+        return (char)temp;
+    }
+
+
+    private Object[] cache = new Object[65536];
+}
diff --git a/src/com/ibm/icu/test/format/DateFormatMiscTests.java b/src/com/ibm/icu/test/format/DateFormatMiscTests.java
new file mode 100755
index 0000000..76f288a
--- /dev/null
+++ b/src/com/ibm/icu/test/format/DateFormatMiscTests.java
@@ -0,0 +1,166 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2001, International Business Machines Corporation and         *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/test/format/Attic/DateFormatMiscTests.java,v $ 
+ * $Date: 2001/10/29 12:49:02 $ 
+ * $Revision: 1.4 $
+ *
+ *****************************************************************************************
+ */
+
+/** 
+ * Port From:   ICU4C v1.8.1 : format : DateFormatMiscTests
+ * Source File: $ICU4CRoot/source/test/intltest/miscdtfm.cpp
+ **/
+
+package com.ibm.icu.test.format;
+
+import com.ibm.text.*;
+import com.ibm.util.*;
+import java.text.FieldPosition;
+import java.text.ParseException;
+import java.util.Locale;
+import java.util.Date;
+
+/** 
+ * Performs miscellaneous tests for DateFormat, SimpleDateFormat, DateFormatSymbols
+ **/
+public class DateFormatMiscTests extends com.ibm.test.TestFmwk {
+
+    public static void main(String[] args) throws Exception{
+        new DateFormatMiscTests().run(args);
+    }
+    
+    /*
+     * @bug 4097450
+     */
+    public void Test4097450() {
+        //
+        // Date parse requiring 4 digit year.
+        //
+        String dstring[] = {
+            "97", "1997", "97", "1997", "01", "2001", "01", "2001",
+             "1", "1", "11", "11", "111", "111"}; 
+    
+        String dformat[] = 
+            {
+                "yy", "yy", "yyyy", "yyyy", "yy", "yy", "yyyy", "yyyy", 
+                "yy", "yyyy", "yy", "yyyy", "yy", "yyyy"};         
+    
+        SimpleDateFormat formatter;
+        SimpleDateFormat resultFormatter = new SimpleDateFormat("yyyy");
+        logln("Format\tSource\tResult");
+        logln("-------\t-------\t-------");
+        for (int i = 0; i < dstring.length ; i++) {
+            log(dformat[i] + "\t" + dstring[i] + "\t");
+            formatter = new SimpleDateFormat(dformat[i]);
+            try {
+                StringBuffer str = new StringBuffer("");
+                FieldPosition pos = new FieldPosition(0);
+                logln(resultFormatter.format(formatter.parse(dstring[i]), str, pos).toString()); 
+            }
+            catch (ParseException exception) {
+                errln("exception --> " + exception);
+            }
+            logln("");
+        }
+    }
+    
+    /* @Bug 4099975
+     * SimpleDateFormat constructor SimpleDateFormat(String, DateFormatSymbols)
+     * should clone the DateFormatSymbols parameter
+     */
+    public void Test4099975new() {
+        Date d = new Date();
+        //test SimpleDateFormat Constructor
+        {
+            DateFormatSymbols symbols = new DateFormatSymbols(Locale.US);
+            SimpleDateFormat df = new SimpleDateFormat("E hh:mm", symbols);
+            SimpleDateFormat dfClone = (SimpleDateFormat) df.clone();
+            
+            logln(df.toLocalizedPattern());
+            String s0 = df.format(d);
+            String s_dfClone = dfClone.format(d);
+            
+            symbols.setLocalPatternChars("abcdefghijklmonpqr"); // change value of field
+            logln(df.toLocalizedPattern());
+            String s1 = df.format(d);
+            
+            if (!s1.equals(s0) || !s1.equals(s_dfClone)) {
+                errln("Constructor: the formats are not equal");
+            }
+            if (!df.equals(dfClone)) {
+                errln("The Clone Object does not equal with the orignal source");
+            }
+        }
+        //test SimpleDateFormat.setDateFormatSymbols()
+        {
+            DateFormatSymbols symbols = new DateFormatSymbols(Locale.US);
+            SimpleDateFormat df = new SimpleDateFormat("E hh:mm");
+            df.setDateFormatSymbols(symbols);
+            SimpleDateFormat dfClone = (SimpleDateFormat) df.clone();
+            
+            logln(df.toLocalizedPattern());
+            String s0 = df.format(d);
+            String s_dfClone = dfClone.format(d);
+            
+            symbols.setLocalPatternChars("abcdefghijklmonpqr"); // change value of field
+            logln(df.toLocalizedPattern());
+            String s1 = df.format(d);
+            
+            if (!s1.equals(s0) || !s1.equals(s_dfClone)) {
+                errln("setDateFormatSymbols: the formats are not equal");
+            }
+            if (!df.equals(dfClone)) {
+                errln("The Clone Object does not equal with the orignal source");
+            }
+        }
+    }
+    
+    /*
+     * @bug 4117335
+     */
+    public void Test4117335() {
+        //char bcC[] = {0x7D00, 0x5143, 0x524D};
+        String bc = "\u7D00\u5143\u524D";
+        String ad = "\u897f\u66a6";
+        //char adC[] = {0x897F, 0x66A6};
+        String jstLong = "\u65e5\u672c\u6a19\u6e96\u6642";
+        //char jstLongC[] = {0x65e5, 0x672c, 0x6a19, 0x6e96, 0x6642}; //The variable is never used
+        String jstShort = "JST";
+    
+        DateFormatSymbols symbols = new DateFormatSymbols(Locale.JAPAN);
+        final String[] eras = symbols.getEras();
+        //int eraCount = eras.length; //The variable is never used
+        logln("BC = " + eras[0]);
+        if (!eras[0].equals(bc)) {
+            errln("*** Should have been " + bc);
+        }
+    
+        logln("AD = " + eras[1]);
+        if (!eras[1].equals(ad)) {
+            errln("*** Should have been " + ad);
+        }
+    
+        final String zones[][] = symbols.getZoneStrings();
+        //int rowCount = zones.length, colCount = zones[0].length; //The variable is never used
+        logln("Long zone name = " + zones[0][1]);
+        if (!zones[0][1].equals(jstLong)) {
+            errln("*** Should have been " + jstLong);
+        }
+        logln("Short zone name = " + zones[0][2]);
+        if (!zones[0][2].equals(jstShort)) {
+            errln("*** Should have been " + jstShort);
+        }
+        logln("Long zone name = " + zones[0][3]);
+        if (zones[0][3] != jstLong) {
+            errln("*** Should have been " + jstLong);
+        }
+        logln("SHORT zone name = " + zones[0][4]);
+        if (zones[0][4] != jstShort) {
+            errln("*** Should have been " + jstShort);
+        }
+    }
+}
diff --git a/src/com/ibm/icu/test/format/DateFormatRegressionTest.java b/src/com/ibm/icu/test/format/DateFormatRegressionTest.java
new file mode 100755
index 0000000..34d1a99
--- /dev/null
+++ b/src/com/ibm/icu/test/format/DateFormatRegressionTest.java
@@ -0,0 +1,882 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2001, International Business Machines Corporation and         *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/test/format/Attic/DateFormatRegressionTest.java,v $ 
+ * $Date: 2001/10/23 13:08:50 $ 
+ * $Revision: 1.3 $
+ *
+ *****************************************************************************************
+ */
+
+/** 
+ * Port From:   ICU4C v1.8.1 : format : DateFormatRegressionTest
+ * Source File: $ICU4CRoot/source/test/intltest/dtfmrgts.cpp
+ **/
+
+package com.ibm.icu.test.format;
+
+import com.ibm.text.*;
+import com.ibm.util.*;
+import java.util.Date;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.text.FieldPosition;
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.text.Format;
+import java.io.*;
+
+/** 
+ * Performs regression test for DateFormat
+ **/
+public class DateFormatRegressionTest extends com.ibm.test.TestFmwk {
+
+    public static void main(String[] args) throws Exception{
+        new DateFormatRegressionTest().run(args);
+    }
+    
+    /**
+     * @bug 4029195
+     */
+    public void Test4029195() {
+        Calendar cal = Calendar.getInstance();
+        Date today = cal.getTime();
+        logln("today: " + today);
+        SimpleDateFormat sdf = (SimpleDateFormat) DateFormat.getDateInstance();
+        String pat = sdf.toPattern();
+        logln("pattern: " + pat);
+        StringBuffer fmtd = new StringBuffer("");
+        FieldPosition pos = new FieldPosition(0);
+        fmtd = sdf.format(today, fmtd, pos);
+        logln("today: " + fmtd);
+    
+        sdf.applyPattern("G yyyy DDD");
+        StringBuffer todayS = new StringBuffer("");
+        todayS = sdf.format(today, todayS, pos);
+        logln("today: " + todayS);
+        try {
+            today = sdf.parse(todayS.toString());
+            logln("today date: " + today);
+        } catch (Exception e) {
+            errln("Error reparsing date: " + e.getMessage());
+        }
+    
+        try {
+            StringBuffer rt = new StringBuffer("");
+            rt = sdf.format(sdf.parse(todayS.toString()), rt, pos);
+            logln("round trip: " + rt);
+            if (!rt.toString().equals(todayS.toString()))
+                errln("Fail: Want " + todayS + " Got " + rt);
+        } catch (ParseException e) {
+            errln("Fail: " + e);
+            e.printStackTrace();
+        }
+    }
+    
+    /**
+     * @bug 4052408
+     */
+    public void Test4052408() {
+    
+        DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.US); 
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(97 + 1900, Calendar.MAY, 3, 8, 55);
+        Date dt = cal.getTime();
+        String str = fmt.format(dt);
+        logln(str);
+        
+        if (!str.equals("5/3/97 8:55 AM"))
+            errln("Fail: Test broken; Want 5/3/97 8:55 AM Got " + str);
+    
+        String expected[] = {
+            "", //"ERA_FIELD",
+            "97", //"YEAR_FIELD",
+            "5", //"MONTH_FIELD",
+            "3", //"DATE_FIELD",
+            "", //"HOUR_OF_DAY1_FIELD",
+            "", //"HOUR_OF_DAY0_FIELD",
+            "55", //"MINUTE_FIELD",
+            "", //"SECOND_FIELD",
+            "", //"MILLISECOND_FIELD",
+            "", //"DAY_OF_WEEK_FIELD",
+            "", //"DAY_OF_YEAR_FIELD",
+            "", //"DAY_OF_WEEK_IN_MONTH_FIELD",
+            "", //"WEEK_OF_YEAR_FIELD",
+            "", //"WEEK_OF_MONTH_FIELD",
+            "AM", //"AM_PM_FIELD",
+            "8", //"HOUR1_FIELD",
+            "", //"HOUR0_FIELD",
+            "" //"TIMEZONE_FIELD"
+            };        
+        String fieldNames[] = {
+                "ERA_FIELD", 
+                "YEAR_FIELD", 
+                "MONTH_FIELD", 
+                "DATE_FIELD", 
+                "HOUR_OF_DAY1_FIELD", 
+                "HOUR_OF_DAY0_FIELD", 
+                "MINUTE_FIELD", 
+                "SECOND_FIELD", 
+                "MILLISECOND_FIELD", 
+                "DAY_OF_WEEK_FIELD", 
+                "DAY_OF_YEAR_FIELD", 
+                "DAY_OF_WEEK_IN_MONTH_FIELD", 
+                "WEEK_OF_YEAR_FIELD", 
+                "WEEK_OF_MONTH_FIELD", 
+                "AM_PM_FIELD", 
+                "HOUR1_FIELD", 
+                "HOUR0_FIELD", 
+                "TIMEZONE_FIELD"}; 
+    
+        boolean pass = true;
+        for (int i = 0; i <= 17; ++i) {
+            FieldPosition pos = new FieldPosition(i);
+            StringBuffer buf = new StringBuffer("");
+            fmt.format(dt, buf, pos);
+            //char[] dst = new char[pos.getEndIndex() - pos.getBeginIndex()];
+            String dst = buf.substring(pos.getBeginIndex(), pos.getEndIndex());
+            str = dst;
+            log(i + ": " + fieldNames[i] + ", \"" + str + "\", "
+                    + pos.getBeginIndex() + ", " + pos.getEndIndex()); 
+            String exp = expected[i];
+            if ((exp.length() == 0 && str.length() == 0) || str.equals(exp))
+                logln(" ok");
+            else {
+                logln(" expected " + exp);
+                pass = false;
+            }
+        }
+        if (!pass)
+            errln("Fail: FieldPosition not set right by DateFormat");
+    }
+    
+    /**
+     * @bug 4056591
+     * Verify the function of the [s|g]et2DigitYearStart() API.
+     */
+    public void Test4056591() {
+    
+        try {
+            SimpleDateFormat fmt = new SimpleDateFormat("yyMMdd", Locale.US);
+            Calendar cal = Calendar.getInstance();
+            cal.clear();
+            cal.set(1809, Calendar.DECEMBER, 25);
+            Date start = cal.getTime();
+            fmt.set2DigitYearStart(start);
+            if ((fmt.get2DigitYearStart() != start))
+                errln("get2DigitYearStart broken");
+            cal.clear();
+            cal.set(1809, Calendar.DECEMBER, 25);
+            Date d1 = cal.getTime();
+            cal.clear();
+            cal.set(1909, Calendar.DECEMBER, 24);
+            Date d2 = cal.getTime();
+            cal.clear();
+            cal.set(1809, Calendar.DECEMBER, 26);
+            Date d3 = cal.getTime();
+            cal.clear();
+            cal.set(1861, Calendar.DECEMBER, 25);
+            Date d4 = cal.getTime();
+            
+            Date dates[] = {d1, d2, d3, d4};
+    
+            String strings[] = {"091225", "091224", "091226", "611225"};            
+    
+            for (int i = 0; i < 4; i++) {
+                String s = strings[i];
+                Date exp = dates[i];
+                Date got = fmt.parse(s);
+                logln(s + " . " + got + "; exp " + exp);
+                if (got.getTime() != exp.getTime())
+                    errln("set2DigitYearStart broken");
+            }
+        } catch (ParseException e) {
+            errln("Fail: " + e);
+            e.printStackTrace();
+        }
+    }
+    
+    /**
+     * @bug 4059917
+     */
+    public void Test4059917() {        
+        SimpleDateFormat fmt;
+        String myDate;
+        fmt = new SimpleDateFormat("yyyy/MM/dd");
+        myDate = "1997/01/01";
+        aux917( fmt, myDate );        
+        fmt = new SimpleDateFormat("yyyyMMdd");
+        myDate = "19970101";
+        aux917( fmt, myDate );
+    }
+    
+    public void aux917(SimpleDateFormat fmt, String str) {
+    
+        String pat = fmt.toPattern();
+        logln("==================");
+        logln("testIt: pattern=" + pat + " string=" + str);
+        ParsePosition pos = new ParsePosition(0);
+        Object o = fmt.parseObject(str, pos);
+        //logln( UnicodeString("Parsed object: ") + o );
+    
+        StringBuffer formatted = new StringBuffer("");
+        FieldPosition poss = new FieldPosition(0);
+        formatted = fmt.format(o, formatted, poss);
+    
+        logln("Formatted string: " + formatted);
+        if (!formatted.toString().equals(str))
+            errln("Fail: Want " + str + " Got " + formatted);
+    }
+    
+    /**
+     * @bug 4060212
+     */
+    public void Test4060212() {
+        String dateString = "1995-040.05:01:29";
+        logln("dateString= " + dateString);
+        logln("Using yyyy-DDD.hh:mm:ss");
+        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-DDD.hh:mm:ss");
+        ParsePosition pos = new ParsePosition(0);
+        Date myDate = formatter.parse(dateString, pos);
+        DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.LONG); 
+        String myString = fmt.format(myDate);
+        logln(myString);
+        Calendar cal = new GregorianCalendar();
+        cal.setTime(myDate);
+        if ((cal.get(Calendar.DAY_OF_YEAR) != 40))
+            errln("Fail: Got " + cal.get(Calendar.DAY_OF_YEAR) + " Want 40");
+    
+        logln("Using yyyy-ddd.hh:mm:ss");
+        formatter = new SimpleDateFormat("yyyy-ddd.hh:mm:ss");
+        pos.setIndex(0);
+        myDate = formatter.parse(dateString, pos);
+        myString = fmt.format(myDate);
+        logln(myString);
+        cal.setTime(myDate);
+        if ((cal.get(Calendar.DAY_OF_YEAR) != 40))
+            errln("Fail: Got " + cal.get(Calendar.DAY_OF_YEAR) + " Want 40");
+    }
+    /**
+     * @bug 4061287
+     */
+    public void Test4061287() {
+    
+        SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy");
+        try {
+            logln(df.parse("35/01/1971").toString());
+        } catch (ParseException e) {
+            errln("Fail: " + e);
+            e.printStackTrace();
+        }
+        df.setLenient(false);
+        boolean ok = false;
+        try {
+            logln(df.parse("35/01/1971").toString());
+        } catch (ParseException e) {
+            ok = true;
+        }
+        if (!ok)
+            errln("Fail: Lenient not working");
+    }
+    
+    /**
+     * @bug 4065240
+     */
+    public void Test4065240() {
+        Date curDate;
+        DateFormat shortdate, fulldate;
+        String strShortDate, strFullDate;
+        Locale saveLocale = Locale.getDefault();
+        TimeZone saveZone = TimeZone.getDefault();
+    
+        try {
+            Locale curLocale = new Locale("de", "DE");
+            Locale.setDefault(curLocale);
+            // {sfb} adoptDefault instead of setDefault
+            //TimeZone.setDefault(TimeZone.createTimeZone("EST"));
+            TimeZone.setDefault(TimeZone.getTimeZone("EST"));
+            Calendar cal = Calendar.getInstance();
+            cal.clear();
+            cal.set(98 + 1900, 0, 1);
+            curDate = cal.getTime();
+            shortdate = DateFormat.getDateInstance(DateFormat.SHORT);
+            fulldate = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
+            strShortDate = "The current date (short form) is ";
+            String temp;
+            temp = shortdate.format(curDate);
+            strShortDate += temp;
+            strFullDate = "The current date (long form) is ";
+            String temp2 = fulldate.format(curDate);
+            strFullDate += temp2;
+    
+            logln(strShortDate);
+            logln(strFullDate);
+    
+            // {sfb} What to do with resource bundle stuff?????
+    
+            // Check to see if the resource is present; if not, we can't test
+            //ResourceBundle bundle = //The variable is never used
+            //    ResourceBundle.getBundle("java.text.resources.DateFormatZoneData", curLocale); 
+    
+            // {sfb} API change to ResourceBundle -- add getLocale()
+            /*if (bundle.getLocale().getLanguage().equals("de")) {
+                // UPDATE THIS AS ZONE NAME RESOURCE FOR <EST> in de_DE is updated
+                if (!strFullDate.endsWith("GMT-05:00"))
+                    errln("Fail: Want GMT-05:00");
+            } else {
+                logln("*** TEST COULD NOT BE COMPLETED BECAUSE DateFormatZoneData ***");
+                logln("*** FOR LOCALE de OR de_DE IS MISSING ***");
+            }*/
+        } catch (Exception e) {
+            logln(e.getMessage());
+        } finally {
+            Locale.setDefault(saveLocale);
+            TimeZone.setDefault(saveZone);
+        }
+    
+    }
+    
+    /*
+      DateFormat.equals is too narrowly defined.  As a result, MessageFormat
+      does not work correctly.  DateFormat.equals needs to be written so
+      that the Calendar sub-object is not compared using Calendar.equals,
+      but rather compared for equivalency.  This may necessitate adding a
+      (package private) method to Calendar to test for equivalency.
+      
+      Currently this bug breaks MessageFormat.toPattern
+      */
+    /**
+     * @bug 4071441
+     */
+    public void Test4071441() {
+        DateFormat fmtA = DateFormat.getInstance();
+        DateFormat fmtB = DateFormat.getInstance();
+    
+        // {sfb} Is it OK to cast away const here?
+        Calendar calA = fmtA.getCalendar();
+        Calendar calB = fmtB.getCalendar();
+        calA.clear();
+        calA.set(1900, 0 ,0);
+        calB.clear();
+        calB.set(1900, 0, 0);
+        if (!calA.equals(calB))
+            errln("Fail: Can't complete test; Calendar instances unequal");
+        if (!fmtA.equals(fmtB))
+            errln("Fail: DateFormat unequal when Calendars equal");
+        calB.clear();
+        calB.set(1961, Calendar.DECEMBER, 25);
+        if (calA.equals(calB))
+            errln("Fail: Can't complete test; Calendar instances equal");
+        if (!fmtA.equals(fmtB))
+            errln("Fail: DateFormat unequal when Calendars equivalent");
+        logln("DateFormat.equals ok");
+    }
+        
+    /* The java.text.DateFormat.parse(String) method expects for the
+      US locale a string formatted according to mm/dd/yy and parses it
+      correctly.
+    
+      When given a string mm/dd/yyyy it only parses up to the first
+      two y's, typically resulting in a date in the year 1919.
+      
+      Please extend the parsing method(s) to handle strings with
+      four-digit year values (probably also applicable to various
+      other locales.  */
+    /**
+     * @bug 4073003
+     */
+    public void Test4073003() {
+        try {
+            DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
+            String tests[] = {"12/25/61", "12/25/1961", "4/3/2010", "4/3/10"};
+            for (int i = 0; i < 4; i += 2) {
+                Date d = fmt.parse(tests[i]);
+                Date dd = fmt.parse(tests[i + 1]);
+                String s;
+                s = fmt.format(d);
+                String ss;
+                ss = fmt.format(dd);
+                if (d.getTime() != dd.getTime())
+                    errln("Fail: " + d + " != " + dd);
+                if (!s.equals(ss))
+                    errln("Fail: " + s + " != " + ss);
+                logln("Ok: " + s + " " + d);
+            }
+        } catch (ParseException e) {
+            errln("Fail: " + e);
+            e.printStackTrace();
+        }    
+    }
+    
+    /**
+     * @bug 4089106
+     */
+    public void Test4089106() {
+        TimeZone def = TimeZone.getDefault();
+        try {
+            TimeZone z = new SimpleTimeZone((int) (1.25 * 3600000), "FAKEZONE");
+            TimeZone.setDefault(z);
+            SimpleDateFormat f = new SimpleDateFormat();
+            if (!f.getTimeZone().equals(z))
+                errln("Fail: SimpleTimeZone should use TimeZone.getDefault()");
+        } finally {
+            TimeZone.setDefault(def);
+        }
+    }
+    
+    /**
+     * @bug 4100302
+     */
+    public void Test4100302() {
+        
+        Locale locales[] = {
+            Locale.CANADA, Locale.CANADA_FRENCH, Locale.CHINA, 
+            Locale.CHINESE, Locale.ENGLISH, Locale.FRANCE, Locale.FRENCH, 
+            Locale.GERMAN, Locale.GERMANY, Locale.ITALIAN, Locale.ITALY, 
+            Locale.JAPAN, Locale.JAPANESE, Locale.KOREA, Locale.KOREAN, 
+            Locale.PRC, Locale.SIMPLIFIED_CHINESE, Locale.TAIWAN, 
+            Locale.TRADITIONAL_CHINESE, Locale.UK, Locale.US}; 
+        try {
+            boolean pass = true;
+            for (int i = 0; i < 21; i++) {
+                Format format = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, locales[i]); 
+                byte[] bytes;
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                ObjectOutputStream oos = new ObjectOutputStream(baos);
+                oos.writeObject(format);
+                oos.flush();
+                baos.close();
+                bytes = baos.toByteArray();
+                ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
+                Object o = ois.readObject();
+                if (!format.equals(o)) {
+                    pass = false;
+                    logln("DateFormat instance for locale " + locales[i] + " is incorrectly serialized/deserialized."); 
+                } else {
+                    logln("DateFormat instance for locale " + locales[i] + " is OKAY.");
+                }
+            }
+            if (!pass)
+                errln("Fail: DateFormat serialization/equality bug");
+        } catch (OptionalDataException e) {
+            errln("Fail: " + e);
+        } catch (IOException e) {
+            errln("Fail: " + e);
+        } catch (ClassNotFoundException e) {
+            errln("Fail: " + e);
+        } catch (Exception e) {
+            errln("Fail: " + e);
+        }
+    
+    }
+    
+    /**
+     * @bug 4101483
+     */
+    public void Test4101483() {
+        SimpleDateFormat sdf = new SimpleDateFormat("z", Locale.US);
+        FieldPosition fp = new FieldPosition(DateFormat.TIMEZONE_FIELD);
+        Date d = new Date(9234567890L);
+        StringBuffer buf = new StringBuffer("");
+        sdf.format(d, buf, fp);
+        logln(sdf.format(d, buf, fp).toString());
+        logln("beginIndex = " + fp.getBeginIndex());
+        logln("endIndex = " + fp.getEndIndex());
+        if (fp.getBeginIndex() == fp.getEndIndex())
+            errln("Fail: Empty field");
+    }
+    
+    /**
+     * @bug 4103340
+     * @bug 4138203
+     * This bug really only works in Locale.US, since that's what the locale
+     * used for Date.toString() is.  Bug 4138203 reports that it fails on Korean
+     * NT; it would actually have failed on any non-US locale.  Now it should
+     * work on all locales.
+     */
+    public void Test4103340() {
+    
+        // choose a date that is the FIRST of some month 
+        // and some arbitrary time
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(1997, 3, 1, 1, 1, 1);
+        Date d = cal.getTime(); 
+        SimpleDateFormat df = new SimpleDateFormat("MMMM", Locale.US);
+        String s = d.toString();
+        StringBuffer s2 = new StringBuffer("");
+        FieldPosition pos = new FieldPosition(0);
+        s2 = df.format(d, s2, pos);
+        logln("Date=" + s); 
+        logln("DF=" + s2);
+        String substr = s2.substring(0,2);
+        if (s.indexOf(substr) == -1)
+          errln("Months should match");
+    }
+    
+    /**
+     * @bug 4103341
+     */
+    public void Test4103341() {
+        TimeZone saveZone = TimeZone.getDefault();
+        try {
+            // {sfb} changed from adoptDefault to setDefault
+            TimeZone.setDefault(TimeZone.getTimeZone("CST"));
+            SimpleDateFormat simple = new SimpleDateFormat("MM/dd/yyyy HH:mm");
+            TimeZone temp = TimeZone.getDefault();
+            if (!simple.getTimeZone().equals(temp))
+                errln("Fail: SimpleDateFormat not using default zone");
+        } finally {
+            TimeZone.setDefault(saveZone);
+        }
+    }
+    
+    /**
+     * @bug 4104136
+     */
+    public void Test4104136() {
+        SimpleDateFormat sdf = new SimpleDateFormat();
+        String pattern = "'time' hh:mm";
+        sdf.applyPattern(pattern);
+        logln("pattern: \"" + pattern + "\"");
+        String strings[] = {"time 10:30", "time 10:x", "time 10x"};
+        ParsePosition ppos[] = {new ParsePosition(10), new ParsePosition(0), new ParsePosition(0)};
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(1970, Calendar.JANUARY, 1, 10, 30);
+        Date dates[] = {cal.getTime(), new Date(-1), new Date(-1)};
+        for (int i = 0; i < 3; i++) {
+            String text = strings[i];
+            ParsePosition finish = ppos[i];
+            Date exp = dates[i];
+            ParsePosition pos = new ParsePosition(0);
+            Date d = sdf.parse(text, pos);
+            logln(" text: \"" + text + "\"");
+            logln(" index: %d" + pos.getIndex());
+            logln(" result: " + d);
+            if (pos.getIndex() != finish.getIndex())
+                errln("Fail: Expected pos " + finish.getIndex());
+            if (!((d == null && exp.equals(new Date(-1))) || (d.equals(exp))))
+                errln( "Fail: Expected result " + exp);
+        }
+    }
+    
+    /**
+     * @bug 4104522
+     * CANNOT REPRODUCE
+     * According to the bug report, this test should throw a
+     * StringIndexOutOfBoundsException during the second parse.  However,
+     * this is not seen.
+     */
+    public void Test4104522() {
+        SimpleDateFormat sdf = new SimpleDateFormat();
+        String pattern = "'time' hh:mm";
+        sdf.applyPattern(pattern);
+        logln("pattern: \"" + pattern + "\"");
+        // works correctly
+        ParsePosition pp = new ParsePosition(0);
+        String text = "time ";
+        Date dt = sdf.parse(text, pp);
+        logln(" text: \"" + text + "\"" + " date: " + dt);
+        // works wrong
+        pp.setIndex(0);
+        text = "time";
+        dt = sdf.parse(text, pp);
+        logln(" text: \"" + text + "\"" + " date: " + dt);    
+    }
+    
+    /**
+     * @bug 4106807
+     */
+    public void Test4106807() {
+        Date dt;
+        DateFormat df = DateFormat.getDateTimeInstance();
+    
+        SimpleDateFormat sdfs[] = {
+                new SimpleDateFormat("yyyyMMddHHmmss"), 
+                new SimpleDateFormat("yyyyMMddHHmmss'Z'"), 
+                new SimpleDateFormat("yyyyMMddHHmmss''"), 
+                new SimpleDateFormat("yyyyMMddHHmmss'a''a'"), 
+                new SimpleDateFormat("yyyyMMddHHmmss %")}; 
+        String strings[] = {
+                "19980211140000", 
+                "19980211140000", 
+                "19980211140000", 
+                "19980211140000a", 
+                "19980211140000 "}; 
+        GregorianCalendar gc = new GregorianCalendar();
+        TimeZone timeZone = TimeZone.getDefault();
+        TimeZone gmt = (TimeZone) timeZone.clone();
+        gmt.setRawOffset(0);
+        for (int i = 0; i < 5; i++) {
+            SimpleDateFormat format = sdfs[i];
+            String dateString = strings[i];
+            try {
+                format.setTimeZone(gmt);
+                dt = format.parse(dateString);
+                // {sfb} some of these parses will fail purposely
+    
+                StringBuffer fmtd = new StringBuffer("");
+                FieldPosition pos = new FieldPosition(0);
+                fmtd = df.format(dt, fmtd, pos);
+                logln(fmtd.toString());
+                //logln(df.format(dt)); 
+                gc.setTime(dt);
+                logln("" + gc.get(Calendar.ZONE_OFFSET));
+                StringBuffer s = new StringBuffer("");
+                s = format.format(dt, s, pos);
+                logln(s.toString());
+            } catch (ParseException e) {
+                logln("No way Jose");
+            }
+        }
+    }
+    
+    /*
+      Synopsis: Chinese time zone CTT is not recogonized correctly.
+      Description: Platform Chinese Windows 95 - ** Time zone set to CST ** 
+      */
+    /**
+     * @bug 4108407
+     */
+    
+    // {sfb} what to do with this one ?? 
+    public void Test4108407() {
+        /*
+        long l = System.currentTimeMillis(); 
+        logln("user.timezone = " + System.getProperty("user.timezone", "?"));
+        logln("Time Zone :" + 
+                           DateFormat.getDateInstance().getTimeZone().getID()); 
+        logln("Default format :" + 
+                           DateFormat.getDateInstance().format(new Date(l))); 
+        logln("Full format :" + 
+                           DateFormat.getDateInstance(DateFormat.FULL).format(new 
+                                                                              Date(l))); 
+        logln("*** Set host TZ to CST ***");
+        logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");
+        */
+    }
+    
+    /**
+     * @bug 4134203
+     * SimpleDateFormat won't parse "GMT"
+     */
+    public void Test4134203() {
+        String dateFormat = "MM/dd/yy HH:mm:ss zzz";
+        SimpleDateFormat fmt = new SimpleDateFormat(dateFormat);
+    
+        ParsePosition p0 = new ParsePosition(0);
+        Date d = fmt.parse("01/22/92 04:52:00 GMT", p0);
+        logln(d.toString());
+        if(p0.equals(new ParsePosition(0)))
+            errln("Fail: failed to parse 'GMT'");
+        // In the failure case an exception is thrown by parse();
+        // if no exception is thrown, the test passes.
+    }
+    
+    /**
+     * @bug 4151631
+     * SimpleDateFormat incorrect handling of 2 single quotes in format()
+     */
+    public void Test4151631() {
+        String pattern = 
+            "'TO_DATE('''dd'-'MM'-'yyyy HH:mm:ss''' , ''DD-MM-YYYY HH:MI:SS'')'"; 
+        logln("pattern=" + pattern);
+        SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.US);
+        StringBuffer result = new StringBuffer("");
+        FieldPosition pos = new FieldPosition(0);
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(1998, Calendar.JUNE, 30, 13, 30, 0);
+        Date d = cal.getTime();
+        result = format.format(d, result, pos); 
+        if (!result.toString().equals("TO_DATE('30-06-1998 13:30:00' , 'DD-MM-YYYY HH:MI:SS')")) {
+            errln("Fail: result=" + result);
+        } else {
+            logln("Pass: result=" + result);
+        }
+    }
+    
+    /**
+     * @bug 4151706
+     * 'z' at end of date format throws index exception in SimpleDateFormat
+     * CANNOT REPRODUCE THIS BUG ON 1.2FCS
+     */
+    public void Test4151706() {
+        String dateString = "Thursday, 31-Dec-98 23:00:00 GMT";
+        SimpleDateFormat fmt = new SimpleDateFormat("EEEE, dd-MMM-yy HH:mm:ss z", Locale.US);
+        Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);
+        cal.clear();
+        cal.set(1998, Calendar.DECEMBER, 31, 23, 0, 0);
+        Date d = new Date();
+        try {
+            d = fmt.parse(dateString);
+            // {sfb} what about next two lines?
+            if (d.getTime() != cal.getTime().getTime())
+                errln("Incorrect value: " + d);
+        } catch (Exception e) {
+            errln("Fail: " + e);
+        }
+        StringBuffer temp = new StringBuffer("");
+        FieldPosition pos = new FieldPosition(0);
+        logln(dateString + " . " + fmt.format(d, temp, pos));
+    }
+    
+    /**
+     * @bug 4162071
+     * Cannot reproduce this bug under 1.2 FCS -- it may be a convoluted duplicate
+     * of some other bug that has been fixed.
+     */
+    public void Test4162071() {
+        String dateString = "Thu, 30-Jul-1999 11:51:14 GMT";
+        String format = "EEE', 'dd-MMM-yyyy HH:mm:ss z"; // RFC 822/1123
+        SimpleDateFormat df = new SimpleDateFormat(format, Locale.US);
+        try {
+            Date x = df.parse(dateString);
+            StringBuffer temp = new StringBuffer("");
+            FieldPosition pos = new FieldPosition(0);
+            logln(dateString + " -> " + df.format(x, temp, pos));
+        } catch (Exception e) {
+            errln("Parse format \"" + format + "\" failed.");
+        }
+    }
+    
+    /**
+     * DateFormat shouldn't parse year "-1" as a two-digit year (e.g., "-1" . 1999).
+     */
+    public void Test4182066() {
+        SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yy", Locale.US);
+        SimpleDateFormat dispFmt = new SimpleDateFormat("MMM dd yyyy HH:mm:ss GG", Locale.US);
+        /* We expect 2-digit year formats to put 2-digit years in the right
+         * window.  Out of range years, that is, anything less than "00" or
+         * greater than "99", are treated as literal years.  So "1/2/3456"
+         * becomes 3456 AD.  Likewise, "1/2/-3" becomes -3 AD == 2 BC.
+         */
+        final String STRINGS[] = 
+            {"02/29/00", "01/23/01", "04/05/-1", "01/23/-9", "11/12/1314", "10/31/1", "09/12/+1", "09/12/001",}; 
+        int STRINGS_COUNT = STRINGS.length;
+                
+        Calendar cal = Calendar.getInstance();
+        Date FAIL_DATE = cal.getTime();
+        cal.clear();
+        cal.set(2000, Calendar.FEBRUARY, 29);
+        Date d0 = cal.getTime();
+        cal.clear();
+        cal.set(2001, Calendar.JANUARY, 23);
+        Date d1 = cal.getTime();
+        cal.clear();
+        cal.set(-1, Calendar.APRIL, 5);
+        Date d2 = cal.getTime();
+        cal.clear();
+        cal.set(-9, Calendar.JANUARY, 23);
+        Date d3 = cal.getTime();
+        cal.clear();
+        cal.set(1314, Calendar.NOVEMBER, 12);
+        Date d4 = cal.getTime();
+        cal.clear();
+        cal.set(1, Calendar.OCTOBER, 31);
+        Date d5 = cal.getTime();
+        cal.clear();        
+        cal.set(1, Calendar.SEPTEMBER, 12);
+        Date d7 = cal.getTime();
+        Date DATES[] = {d0, d1, d2, d3, d4, d5, FAIL_DATE, d7};
+    
+        String out = "";
+        boolean pass = true;
+        for (int i = 0; i < STRINGS_COUNT; ++i) {
+            String str = STRINGS[i];
+            Date expected = DATES[i];            
+            Date actual = null;
+            try {
+                actual = fmt.parse(str);
+            } catch (ParseException e) {
+                actual = FAIL_DATE;
+            }
+            String actStr = "";
+            if ((actual.getTime()) == FAIL_DATE.getTime()) {
+                actStr += "null";
+            } else {
+                // Yuck: See j25
+                actStr = ((DateFormat) dispFmt).format(actual);
+            }
+                               
+            if (expected.getTime() == (actual.getTime())) {
+                out += str + " => " + actStr + "\n";
+            } else {
+                String expStr = "";
+                if (expected.getTime() == FAIL_DATE.getTime()) {
+                    expStr += "null";
+                } else {
+                    // Yuck: See j25
+                    expStr = ((DateFormat) dispFmt).format(expected);
+                }
+                out += "FAIL: " + str + " => " + actStr + ", expected " + expStr + "\n";
+                pass = false;
+            }
+        }
+        if (pass) {
+            log(out);
+        } else {
+            err(out);
+        }
+    }
+    
+    /**
+     * j32 {JDK Bug 4210209 4209272}
+     * DateFormat cannot parse Feb 29 2000 when setLenient(false)
+     */
+    public void Test4210209() {
+    
+        String pattern = "MMM d, yyyy";
+        SimpleDateFormat sfmt = new SimpleDateFormat(pattern, Locale.US);
+        SimpleDateFormat sdisp = new SimpleDateFormat("MMM dd yyyy GG", Locale.US);
+        DateFormat fmt = (DateFormat) sfmt; // Yuck: See j25
+        DateFormat disp = (DateFormat) sdisp; // Yuck: See j25
+    
+        Calendar calx = (Calendar) fmt.getCalendar(); // cast away const!
+        calx.setLenient(false);
+        Calendar calendar = Calendar.getInstance();
+        calendar.clear();
+        calendar.set(2000, Calendar.FEBRUARY, 29);
+        Date d = calendar.getTime();
+        String s = fmt.format(d);
+        logln(disp.format(d) + " f> " + pattern + " => \"" + s + "\"");
+        ParsePosition pos = new ParsePosition(0);
+        d = fmt.parse(s, pos);
+        logln("\"" + s + "\" p> " + pattern + " => " + disp.format(d));
+        logln("Parse pos = " + pos.getIndex() + ", error pos = " + pos.getErrorIndex());
+        if (pos.getErrorIndex() != -1) {
+            errln("FAIL: Error index should be -1");
+        }
+    
+        // The underlying bug is in GregorianCalendar.  If the following lines
+        // succeed, the bug is fixed.  If the bug isn't fixed, they will throw
+        // an exception.
+        GregorianCalendar cal = new GregorianCalendar();
+        cal.clear();
+        cal.setLenient(false);
+        cal.set(2000, Calendar.FEBRUARY, 29); // This should work!
+        logln("Attempt to set Calendar to Feb 29 2000: " + disp.format(cal.getTime()));
+    }
+    
+    public void Test714() {
+        //TimeZone Offset
+        TimeZone defaultTZ = TimeZone.getDefault();
+        TimeZone PST = TimeZone.getTimeZone("PST");
+        int defaultOffset = defaultTZ.getRawOffset();
+        int PSTOffset = PST.getRawOffset();
+        Date d = new Date(978103543000l - (defaultOffset - PSTOffset));
+        d = new Date(d.getTime() - (defaultTZ.inDaylightTime(d) ? 3600000 : 0));
+        DateFormat fmt = DateFormat.getDateTimeInstance(-1, DateFormat.MEDIUM, Locale.US);
+        String tests = "7:25:43 AM";
+        String s = fmt.format(d);
+        if (!s.equals(tests)) {
+            errln("Fail: " + s + " != " + tests);
+        } else {
+            logln("OK: " + s + " == " + tests);
+        }
+    }
+}
diff --git a/src/com/ibm/icu/test/format/DateFormatRegressionTestJ.java b/src/com/ibm/icu/test/format/DateFormatRegressionTestJ.java
new file mode 100755
index 0000000..9583e83
--- /dev/null
+++ b/src/com/ibm/icu/test/format/DateFormatRegressionTestJ.java
@@ -0,0 +1,285 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2001, International Business Machines Corporation and         *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/test/format/Attic/DateFormatRegressionTestJ.java,v $ 
+ * $Date: 2001/10/23 13:10:05 $ 
+ * $Revision: 1.3 $
+ *
+ *****************************************************************************************
+ */
+
+/*
+ * New added, 2001-10-17 [Jing/GCL]
+ */
+
+package com.ibm.icu.test.format;
+
+import com.ibm.text.*;
+import com.ibm.util.*;
+import java.util.Date;
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.util.Locale;
+import java.text.FieldPosition;
+
+public class DateFormatRegressionTestJ extends com.ibm.test.TestFmwk {
+    
+    static final String TIME_STRING = "2000/11/17 08:01:00";
+    static final long UTC_LONG = 974476860000L;
+    static SimpleDateFormat sdf_ = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+    
+    public static void main(String[] args) throws Exception {
+        new DateFormatRegressionTestJ().run(args);
+    }
+    
+    //Return value of getAmPmStrings
+    public void Test4103926() {
+        String act_Ampms[];
+        String exp_Ampms[]={"AM","PM"};
+        Locale.setDefault(Locale.US);
+        
+        DateFormatSymbols dfs = new DateFormatSymbols();
+        act_Ampms = dfs.getAmPmStrings();
+        if(act_Ampms.length != exp_Ampms.length) {
+            errln("The result is not expected!");
+        } else {
+            for(int i =0; i<act_Ampms.length; i++) {
+                if(!act_Ampms[i].equals(exp_Ampms[i]))
+                    errln("The result is not expected!");
+            }
+        }
+    }
+    
+    //Missing digit in millisecone format in SimpleDateFormat 
+    public void Test4148168() {
+            Date d = new Date(1002705212906l); 
+            String[] ISOPattern = {
+                "''yyyy-MM-dd-hh.mm.ss.S''", "''yyyy-MM-dd-hh.mm.ss.SS''", 
+                "''yyyy-MM-dd-hh.mm.ss.SSS''", "''yyyy-MM-dd-hh.mm.ss.SSSS''", 
+                "''yyyy-MM-dd-hh.mm.ss.SSSSS''", "''yyyy-MM-dd-hh.mm.ss.SSSSSS''", 
+                "''yyyy-MM-dd-hh.mm.ss.SSSSSSS''", "''yyyy-MM-dd-hh.mm.ss.SSS000''"};
+            SimpleDateFormat aSimpleDF = (SimpleDateFormat)DateFormat.getDateTimeInstance();
+    
+            for(int i = 0; i<ISOPattern.length; i++) {
+                aSimpleDF.applyPattern( ISOPattern[i] );
+                logln( "Pattern = " + aSimpleDF.toPattern());
+                logln( "Format = " + aSimpleDF.format(d));
+            }
+    }
+    
+    //DateFormat getDateTimeInstance(int, int), invalid styles no exception
+    public void Test4213086() {
+        Date someDate = new Date();
+        String d;
+        try {
+            DateFormat df2 = DateFormat.getDateTimeInstance(2, -2);
+            d = df2.format(someDate);
+            errln("we should catch an exception here");
+        } catch(Exception e){
+            logln("dateStyle = 2" + "\t timeStyle = -2");
+            logln("Exception caught!");
+        }            
+        
+        try {
+            DateFormat df3 = DateFormat.getDateTimeInstance(4, 2);
+            d = df3.format(someDate);
+            errln("we should catch an exception here");
+        } catch(Exception e){
+            logln("dateStyle = 4" + "\t timeStyle = 2");
+            logln("Exception caught!");
+            logln("********************************************");
+        }
+    
+        try {
+            DateFormat df4 = DateFormat.getDateTimeInstance(-12, -12);
+            d = df4.format(someDate);
+            errln("we should catch an exception here");
+        } catch(Exception e){
+            logln("dateStyle = -12" + "\t timeStyle = -12");
+            logln("Exception caught!");
+            logln("********************************************");
+        }
+    
+        try{
+            DateFormat df5 = DateFormat.getDateTimeInstance(2, 123);
+            d = df5.format(someDate);    
+            errln("we should catch an exception here");
+        } catch(Exception e){
+            logln("dateStyle = 2" + "\t timeStyle = 123");
+            logln("Exception caught!");
+            logln("********************************************");
+        }
+    }
+    
+    //DateFormat.format works wrongly?
+    public void Test4250359() {
+        Locale.setDefault(Locale.US);
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(101 + 1900, 9, 9, 17, 53);
+        Date d = cal.getTime();
+        DateFormat tf = DateFormat.getTimeInstance(DateFormat.SHORT);
+        String act_result = tf.format(d);
+        String exp_result = "5:53 PM";
+        
+        if(!act_result.equals(exp_result)){
+            errln("The result is not expected");
+        }
+    }
+    
+    //pattern "s.S, parse '1ms'"
+    public void Test4253490() {
+        Date d = new Date(1002705212231l);
+    
+        String[] ISOPattern = {
+                "''yyyy-MM-dd-hh.mm.ss.S''", 
+                "''yyyy-MM-dd-hh.mm.ss.SS''", 
+                "''yyyy-MM-dd-hh.mm.ss.SSS''", 
+                "''yyyy-MM-dd-hh.mm.ss.SSSS''", 
+                "''yyyy-MM-dd-hh.mm.ss.SSSSS''", 
+                "''yyyy-MM-dd-hh.mm.ss.SSSSSS''", 
+                "''yyyy-MM-dd-hh.mm.ss.SSSSSSS''"}; 
+    
+        SimpleDateFormat aSimpleDF = (SimpleDateFormat) DateFormat.getDateTimeInstance();
+        for (int i = 0; i < ISOPattern.length; i++) {
+            aSimpleDF.applyPattern(ISOPattern[i]);
+            logln("Pattern = " + aSimpleDF.toPattern());
+            logln("Format = " + aSimpleDF.format(d));
+        }
+    }
+    
+    //about regression test
+    public void Test4266432() {
+        Locale.setDefault(Locale.JAPAN);
+        Locale loc = Locale.getDefault();
+        String dateFormat = "MM/dd/yy HH:mm:ss zzz";
+        SimpleDateFormat fmt = new SimpleDateFormat(dateFormat);
+    
+        ParsePosition p0 = new ParsePosition(0);
+        logln("Under  " + loc +"  locale");
+        Date d = fmt.parse("01/22/92 04:52:00 GMT", p0);
+        logln(d.toString());
+    }
+    
+    //SimpleDateFormat inconsistent for number of digits for years
+    public void Test4358730() {
+        SimpleDateFormat sdf = new SimpleDateFormat();
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(2001,11,10);
+        Date today = cal.getTime();
+    
+        sdf.applyPattern("MM d y");
+        logln(sdf.format(today));
+        sdf.applyPattern("MM d yy");
+        logln(sdf.format(today));
+    
+        sdf.applyPattern("MM d yyy");
+        logln(sdf.format(today));
+    
+        sdf.applyPattern("MM d yyyy");
+        logln(sdf.format(today));
+    
+        sdf.applyPattern("MM d yyyyy");
+        logln(sdf.format(today));
+    }
+    
+    //Parse invalid string
+    public void Test4375399() {
+        final String pattern = new String("yyyy.MM.dd G 'at' hh:mm:ss z");
+        SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.JAPAN);
+        try{
+            Date currentTime = sdf.parse("vggf 20  01.0 9.29 ap. J.-C. at 05:26:33 GMT+08:00",
+                                new ParsePosition(0));
+            if(currentTime ==null)
+                logln("parse right");
+        } catch(Exception e){
+            errln("Error");
+        }
+    }
+    /*
+    public void Test4407042() {
+        DateParseThread d1 = new DateParseThread();
+        DateFormatThread d2 = new DateFormatThread();
+        d1.start();
+        d2.start();
+        try {
+            logln("test");
+            Thread.sleep(1000);
+        } catch (Exception e) {}
+    }*/
+    
+    public void Test4468663() {
+        Date d =new Date(-93716671115767l);
+        String origin_d = d.toString();
+        String str;
+        final String pattern = new String("EEEE, MMMM d, yyyy");
+        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+
+        if (sdf.getTimeZone().useDaylightTime()) {
+            logln("original date: " + origin_d.toString());
+            str = sdf.format(d);
+            logln(" after format----->" + str);
+            
+            d = sdf.parse(str, new ParsePosition(0));
+            logln(" after parse----->" + d.toString());
+    
+            str = sdf.format(d);
+            logln(" after format----->" + str);
+    
+            d = sdf.parse(str, new ParsePosition(0));
+            logln(" after parse----->" + d.toString());
+    
+            str = sdf.format(d);
+            logln(" after format----->" + str);        
+        }
+    }
+    
+    //Class used by Test4407042
+    class DateParseThread extends Thread {
+        public void run() {
+            SimpleDateFormat sdf = (SimpleDateFormat) sdf_.clone();
+            TimeZone defaultTZ = TimeZone.getDefault();
+            TimeZone PST = TimeZone.getTimeZone("PST");
+            int defaultOffset = defaultTZ.getRawOffset();
+            int PSTOffset = PST.getRawOffset();
+            int offset = defaultOffset - PSTOffset;
+            long ms = UTC_LONG - offset;
+            try {
+                int i = 0;
+                while (i < 10000) {
+                    Date date = sdf.parse(TIME_STRING);
+                    long t = date.getTime();
+                    i++;
+                    if (t != ms) {
+                        throw new ParseException("Parse Error: " + i + " (" + sdf.format(date) 
+                                  + ") " + t + " != " + ms, 0);
+                    }
+                }
+            } catch (Exception e) {
+                errln("parse error: " + e.getMessage());
+            }
+        }
+    }
+    
+    //Class used by Test4407042
+    class DateFormatThread extends Thread {
+        public void run() {            
+            SimpleDateFormat sdf = (SimpleDateFormat) sdf_.clone();
+            TimeZone tz = TimeZone.getTimeZone("PST");
+            sdf.setTimeZone(tz);
+            int i = 0;
+            while (i < 10000) {
+                i++;
+                String s = sdf.format(new Date(UTC_LONG));
+                if (!s.equals(TIME_STRING)) {
+                    errln("Format Error: " + i + " " + s + " != " 
+                                    + TIME_STRING);
+                }
+            }
+        }
+    }
+    
+}
\ No newline at end of file
diff --git a/src/com/ibm/icu/test/format/DateFormatRoundTripTest.java b/src/com/ibm/icu/test/format/DateFormatRoundTripTest.java
new file mode 100755
index 0000000..eef8477
--- /dev/null
+++ b/src/com/ibm/icu/test/format/DateFormatRoundTripTest.java
@@ -0,0 +1,307 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2001, International Business Machines Corporation and         *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/test/format/Attic/DateFormatRoundTripTest.java,v $ 
+ * $Date: 2001/10/19 11:43:37 $ 
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************************
+ */
+
+/** 
+ * Port From:   ICU4C v1.8.1 : format : DateFormatRoundTripTest
+ * Source File: $ICU4CRoot/source/test/intltest/dtfmtrtts.cpp
+ **/
+
+package com.ibm.icu.test.format;
+
+import com.ibm.text.*;
+import com.ibm.util.*;
+import java.util.Locale;
+import java.util.Date;
+import java.util.Random;
+import java.text.FieldPosition;
+import java.text.ParseException;
+
+/** 
+ * Performs round-trip tests for DateFormat
+ **/
+public class DateFormatRoundTripTest extends com.ibm.test.TestFmwk {
+    public boolean INFINITE = false;
+    public boolean quick = true;
+    private SimpleDateFormat dateFormat;
+    private Calendar getFieldCal;
+    private int SPARSENESS = 18;
+    private int TRIALS = 4;
+    private int DEPTH = 5;
+    private Random ran = new Random();
+
+    public static void main(String[] args) throws Exception {
+        new DateFormatRoundTripTest().run(args);
+    }
+    
+    //The Case fail randomly, I will recreate the case soon. [Richard/GCL]
+    /*
+    public void TestDateFormatRoundTrip() {
+        dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss.SSS zzz yyyy G");
+        getFieldCal = Calendar.getInstance();
+    
+        final Locale[] avail = DateFormat.getAvailableLocales();
+        int locCount = avail.length;
+        logln("DateFormat available locales: " + locCount);
+        if (quick) {
+            if (locCount > 5)
+                locCount = 5;
+            logln("Quick mode: only testing first 5 Locales");
+        }
+        TimeZone tz = TimeZone.getDefault();
+        logln("Default TimeZone:             " + tz.getID());
+    
+        if (INFINITE) {
+            // Special infinite loop test mode for finding hard to reproduce errors
+            Locale loc = Locale.getDefault();
+            logln("ENTERING INFINITE TEST LOOP FOR Locale: " + loc.getDisplayName());
+            for (;;) {
+                _test(loc);
+            }
+        } else {        
+            _test(Locale.getDefault());
+            for (int i = 0; i < locCount; ++i) {
+                _test(avail[i]);
+            }
+        }
+    }*/
+    
+    public String styleName(int s) {
+        switch (s) {
+            case DateFormat.SHORT :
+                return "SHORT";
+            case DateFormat.MEDIUM :
+                return "MEDIUM";
+            case DateFormat.LONG :
+                return "LONG";
+            case DateFormat.FULL :
+                return "FULL";
+            default :
+                return "Unknown";
+        }
+    }
+    
+    public void _test(Locale loc) {
+        if (!INFINITE) {
+            logln("Locale: " + loc.getDisplayName());
+        }
+        // Total possibilities = 24
+        //  4 date
+        //  4 time
+        //  16 date-time
+        boolean[] TEST_TABLE = new boolean[24];
+        int i = 0;
+        for (i = 0; i < 24; ++i)
+            TEST_TABLE[i] = true;
+    
+        // If we have some sparseness, implement it here.  Sparseness decreases
+        // test time by eliminating some tests, up to 23.
+        for (i = 0; i < SPARSENESS; i++) {
+            int random = (int) (ran.nextDouble() * 24);
+            if (random >= 0 && random < 24 && TEST_TABLE[i]) {
+                TEST_TABLE[random] = false;
+            }
+        }    
+        
+        int itable = 0;
+        int style = 0;
+        for (style = DateFormat.FULL; style <= DateFormat.SHORT; ++style) {
+            if (TEST_TABLE[itable++]) {
+                logln("Testing style " + styleName(style)); 
+                DateFormat df = DateFormat.getDateInstance(style, loc); 
+                _test(df, false);
+            }
+        }
+    
+        for (style = DateFormat.FULL; style <= DateFormat.SHORT; ++style) {
+            if (TEST_TABLE[itable++]) {
+                logln("Testing style " + styleName(style));
+                DateFormat  df = DateFormat.getTimeInstance(style, loc); 
+                _test(df, true);
+            }
+        }
+    
+        for (int dstyle = DateFormat.FULL; dstyle <= DateFormat.SHORT; ++dstyle) {
+            for (int tstyle = DateFormat.FULL; tstyle <= DateFormat.SHORT; ++tstyle) {
+                if (TEST_TABLE[itable++]) {
+                    logln("Testing dstyle " + styleName(dstyle) + ", tstyle " + styleName(tstyle)); 
+                    DateFormat df = DateFormat.getDateTimeInstance(dstyle, tstyle, loc); 
+                    _test(df, false);
+                }
+            }
+        }
+    }
+    
+    public void _test(DateFormat fmt, boolean timeOnly) {
+    
+        if (!(fmt instanceof SimpleDateFormat)) {
+            errln("DateFormat wasn't a SimpleDateFormat");
+            return;
+        }
+    
+        String pat = ((SimpleDateFormat) fmt).toPattern();
+        logln(pat);
+    
+        // NOTE TO MAINTAINER
+        // This indexOf check into the pattern needs to be refined to ignore
+        // quoted characters.  Currently, this isn't a problem with the locale
+        // patterns we have, but it may be a problem later.
+    
+        boolean hasEra = (pat.indexOf("G") != -1);
+        boolean hasZone = (pat.indexOf("z") != -1);
+    
+        // Because patterns contain incomplete data representing the Date,
+        // we must be careful of how we do the roundtrip.  We start with
+        // a randomly generated Date because they're easier to generate.
+        // From this we get a string.  The string is our real starting point,
+        // because this string should parse the same way all the time.  Note
+        // that it will not necessarily parse back to the original date because
+        // of incompleteness in patterns.  For example, a time-only pattern won't
+        // parse back to the same date.
+    
+        try {
+            for (int i = 0; i < TRIALS; ++i) {
+                Date[] d = new Date[DEPTH];
+                String[] s = new String[DEPTH];
+    
+                d[0] = generateDate();
+                
+                // We go through this loop until we achieve a match or until
+                // the maximum loop count is reached.  We record the points at
+                // which the date and the string starts to match.  Once matching
+                // starts, it should continue.
+                int loop;
+                int dmatch = 0; // d[dmatch].getTime() == d[dmatch-1].getTime()
+                int smatch = 0; // s[smatch].equals(s[smatch-1])
+                for (loop = 0; loop < DEPTH; ++loop) {
+                    if (loop > 0) {
+                        d[loop] = fmt.parse(s[loop - 1]);
+                    }
+    
+                    s[loop] = fmt.format(d[loop]);
+    
+                    if (loop > 0) {
+                        if (smatch == 0) {
+                            boolean match = s[loop].equals(s[loop - 1]);
+                            if (smatch == 0) {
+                                if (match)
+                                    smatch = loop;
+                            } else
+                                if (!match)
+                                    errln("FAIL: String mismatch after match");
+                        }
+    
+                        if (dmatch == 0) {
+                            // {sfb} watch out here, this might not work
+                            boolean match = d[loop].getTime() == d[loop - 1].getTime();
+                            if (dmatch == 0) {
+                                if (match)
+                                    dmatch = loop;
+                            } else
+                                if (!match)
+                                    errln("FAIL: Date mismatch after match");
+                        }
+    
+                        if (smatch != 0 && dmatch != 0)
+                            break;
+                    }
+                }
+                // At this point loop == DEPTH if we've failed, otherwise loop is the
+                // max(smatch, dmatch), that is, the index at which we have string and
+                // date matching.
+    
+                // Date usually matches in 2.  Exceptions handled below.
+                int maxDmatch = 2;
+                int maxSmatch = 1;
+                if (dmatch > maxDmatch) {
+                    // Time-only pattern with zone information and a starting date in PST.
+                    if (timeOnly && hasZone && (fmt.getTimeZone().inDaylightTime(d[0]))) {
+                        maxDmatch = 3;
+                        maxSmatch = 2;
+                    }
+                    if ((pat.indexOf("yyyy") == -1)) {
+                        maxDmatch = 3;
+                        maxSmatch = 2;
+                    }
+                    if (!hasEra && getField(d[0], Calendar.ERA) == GregorianCalendar.BC) {
+                        maxDmatch = 3;
+                        maxSmatch = 2;
+                    }
+                }
+    
+                // String usually matches in 1.  Exceptions are checked for here.
+                if (smatch > maxSmatch) { // Don't compute unless necessary
+                    // Starts in BC, with no era in pattern
+                    if (!hasEra && getField(d[0], Calendar.ERA) == GregorianCalendar.BC)
+                        maxSmatch = 2;
+                    // Starts in DST, no year in pattern
+                    else
+                        if (fmt.getTimeZone().inDaylightTime(d[0]) && pat.indexOf("yyyy") == -1)
+                            maxSmatch = 2;
+                    // Two digit year with zone and year change and zone in pattern
+                    else
+                        if (hasZone
+                            && fmt.getTimeZone().inDaylightTime(d[0])
+                                != fmt.getTimeZone().inDaylightTime(d[dmatch])
+                            && getField(d[0], Calendar.YEAR) != getField(d[dmatch], Calendar.YEAR)
+                            && pat.indexOf("y") != -1
+                            && pat.indexOf("yyyy") == -1)
+                            maxSmatch = 2;
+                    else 
+                        if ((fmt.getTimeZone().inDaylightTime(d[0])) && (pat.indexOf("z") != -1)) {
+                            maxSmatch = 2;
+                        }
+                    else 
+                        if ((pat.indexOf("yyyy") == -1)) {
+                            maxSmatch = 2;
+                        }
+                }
+    
+                if (dmatch > maxDmatch || smatch > maxSmatch) {
+                    logln("date = " + d[0] + "getTime = " + d[0].getTime());
+                    logln(" Date " + dmatch + "  String " + smatch);
+                    logln("dmatch: " + dmatch + " maxD: " + maxDmatch+ " smatch:" + smatch
+                            + " maxS:" + maxSmatch); 
+                    errln("Pattern: " + pat + " failed to match");
+    
+                    for (int j = 0; j <= loop && j < DEPTH; ++j) {
+                        StringBuffer temp = new StringBuffer("");
+                        FieldPosition pos = new FieldPosition(0);
+                        logln((j > 0 ? " P> " : "    ")+ dateFormat.format(d[j], temp, pos)
+                                + " F> "+ s[j]+ (j > 0 && d[j] /*.getTime()*/ == d[j - 1] /*.getTime()*/ ? " d==" : "")
+                                + (j > 0 && s[j] == s[j - 1] ? " s==" : "")); 
+                    }
+                }
+    
+            }
+        } catch (ParseException e) {
+            errln("Exception: " + e.getMessage());
+            logln(e.toString());
+        }
+    }
+    
+    public int getField(Date d, int f) {
+        getFieldCal.setTime(d);
+        int ret = getFieldCal.get(f);    
+        return ret;
+    }
+    
+    public Date generateDate() {
+        double a = ran.nextDouble();
+        // Now 'a' ranges from 0..1; scale it to range from 0 to 8000 years
+        a *= 8000;
+        // Range from (4000-1970) BC to (8000-1970) AD
+        a -= 4000;
+        // Now scale up to ms
+        a *= 365.25 * 24 * 60 * 60 * 1000;
+        return new Date((long)a);
+    }
+}
diff --git a/src/com/ibm/icu/test/format/DateFormatTest.java b/src/com/ibm/icu/test/format/DateFormatTest.java
new file mode 100755
index 0000000..911974d
--- /dev/null
+++ b/src/com/ibm/icu/test/format/DateFormatTest.java
@@ -0,0 +1,748 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2001, International Business Machines Corporation and         *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/test/format/Attic/DateFormatTest.java,v $ 
+ * $Date: 2001/10/23 13:10:53 $ 
+ * $Revision: 1.2 $
+ *
+ *****************************************************************************************
+ */
+
+/** 
+ * Port From:   ICU4C v1.8.1 : format : DateFormatTest
+ * Source File: $ICU4CRoot/source/test/intltest/dtfmttst.cpp
+ **/
+
+package com.ibm.icu.test.format;
+
+import com.ibm.text.*;
+import com.ibm.util.*;
+import java.util.Date;
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.util.Locale;
+import java.text.FieldPosition;
+
+public class DateFormatTest extends com.ibm.test.TestFmwk {
+    
+    public static void main(String[] args) throws Exception {
+        new DateFormatTest().run(args);
+    }
+    
+    // Test written by Wally Wedel and emailed to me.
+    public void TestWallyWedel() {
+        /*
+         * Instantiate a TimeZone so we can get the ids.
+         */
+        //TimeZone tz = new SimpleTimeZone(7, ""); //The variable is never used
+        /*
+         * Computational variables.
+         */
+        int offset, hours, minutes;
+        /*
+         * Instantiate a SimpleDateFormat set up to produce a full time
+         zone name.
+         */
+        SimpleDateFormat sdf = new SimpleDateFormat("zzzz");
+        /*
+         * A String array for the time zone ids.
+         */
+    
+        final String[] ids = TimeZone.getAvailableIDs();
+        int ids_length = ids.length; //when fixed the bug should comment it out
+    
+        /*
+         * How many ids do we have?
+         */
+        logln("Time Zone IDs size:" + ids_length);
+        /*
+         * Column headings (sort of)
+         */
+        logln("Ordinal ID offset(h:m) name");
+        /*
+         * Loop through the tzs.
+         */
+        Date today = new Date();
+        Calendar cal = Calendar.getInstance();
+        for (int i = 0; i < ids_length; i++) {
+            logln(i + " " + ids[i]);
+            TimeZone ttz = TimeZone.getTimeZone(ids[i]);
+            // offset = ttz.getRawOffset();
+            cal.setTimeZone(ttz);
+            cal.setTime(today);
+            offset = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET);
+            // logln(i + " " + ids[i] + " offset " + offset);
+            String sign = "+";
+            if (offset < 0) {
+                sign = "-";
+                offset = -offset;
+            }
+            hours = offset / 3600000;
+            minutes = (offset % 3600000) / 60000;
+            String dstOffset = sign + (hours < 10 ? "0" : "") + hours
+                    + ":" + (minutes < 10 ? "0" : "") + minutes; 
+            /*
+             * Instantiate a date so we can display the time zone name.
+             */
+            sdf.setTimeZone(ttz);
+            /*
+             * Format the output.
+             */
+            StringBuffer fmtOffset = new StringBuffer("");
+            FieldPosition pos = new FieldPosition(0);
+            
+            try {
+                fmtOffset = sdf.format(today, fmtOffset, pos);
+            } catch (Exception e) {            
+                logln("Exception:" + e);
+                continue;
+            }
+            // UnicodeString fmtOffset = tzS.toString();
+            String fmtDstOffset = null;
+            if (fmtOffset.toString().startsWith("GMT")) {
+                //fmtDstOffset = fmtOffset.substring(3);
+                fmtDstOffset = fmtOffset.substring(3, fmtOffset.length());
+            }
+            /*
+             * Show our result.
+             */
+    
+            boolean ok = fmtDstOffset == null || fmtDstOffset.equals(dstOffset);
+            if (ok) {
+                logln(i + " " + ids[i] + " " + dstOffset + " "
+                      + fmtOffset + (fmtDstOffset != null ? " ok" : " ?")); 
+            } else {
+                errln(i + " " + ids[i] + " " + dstOffset + " " + fmtOffset + " *** FAIL ***");
+            }
+        
+        }
+    }
+    
+    public void TestEquals() {
+        DateFormat fmtA = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.FULL); 
+        DateFormat fmtB = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.FULL); 
+        if (!fmtA.equals(fmtB))
+            errln("FAIL");    
+    }
+    
+    /**
+     * Test the parsing of 2-digit years.
+     */
+    public void TestTwoDigitYearDSTParse() {
+    
+        SimpleDateFormat fullFmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss.SSS zzz yyyy G"); 
+        SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yy h:mm:ss 'o''clock' a z", Locale.ENGLISH); 
+        String s = "03-Apr-04 2:20:47 o'clock AM PST";
+    
+        /*
+         * SimpleDateFormat(pattern, locale) Construct a SimpleDateDateFormat using
+         * the givening pattern, the locale and using the TimeZone.getDefault();
+         * So it need to add the timezone offset on hour field. 
+         * ps. the Method Calendar.getTime() used by SimpleDateFormat.parse() always 
+         * return Date vaule with TimeZone.getDefault() [Richard/GCL]
+         */
+        
+        TimeZone defaultTZ = TimeZone.getDefault();
+        TimeZone PST = TimeZone.getTimeZone("PST");
+        int defaultOffset = defaultTZ.getRawOffset();
+        int PSTOffset = PST.getRawOffset();
+        int hour = 2 + (defaultOffset - PSTOffset) / (60*60*1000);
+        hour = (hour < 0) ? hour + 24 : hour;
+        try {
+            Date d = fmt.parse(s);
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(d);
+            //DSTOffset
+            hour += defaultTZ.inDaylightTime(d) ? 1 : 0;
+            
+            logln(s + " P> " + ((DateFormat) fullFmt).format(d));
+            int hr = cal.get(Calendar.HOUR_OF_DAY);
+            if (hr != hour)
+                errln("FAIL: Should parse to hour " + hour);
+        } catch (ParseException e) {
+            errln("Parse Error:" + e.getMessage());
+        }
+    
+    }
+    
+    /**
+     * Verify that returned field position indices are correct.
+     */
+    public void TestFieldPosition() {
+        DateFormat[] dateFormats = new DateFormat[4];
+        int dateFormats_length = dateFormats.length;
+        String fieldNames[] = {
+                "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",   "DAY_OF_YEAR",
+                "DAY_OF_WEEK",   "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR","HOUR_OF_DAY","MINUTE",
+                "SECOND", "MILLISECOND", "ZONE_OFFSET" };
+        /* {sfb} This test was coded incorrectly.
+        / FieldPosition uses the fields in the class you are formatting with
+        / So, for example, to get the DATE field from a DateFormat use
+        / DateFormat.DATE_FIELD, __not__ Calendar.DATE
+        / The ordering of the expected values used previously was wrong.
+        / instead of re-ordering this mess of strings, just transform the index values */
+    
+        /* field values, in Calendar order */
+        final String[] expected =
+            { "", "1997", "August", "", "", "13", "", "Wednesday", "", "PM", "2", "", "34", "12", "", "PDT",
+            /* Following two added by weiv for two new fields */"", "1997", "#", 
+            /* # is a marker for "ao\xfbt" == "aou^t" */
+            "", "", "13", "", "mercredi", "", "", "", "14", "34", "", "", "PDT",
+            /* Following two added by weiv for two new fields */
+            "AD", "97", "8", "33", "3", "13", "225", "Wed", "2", "PM", "2", "14", "34", "12", "513", "PDT",
+            /* Following two added by weiv for two new fields */
+            "AD",  "1997",  "August",  "0033", "0003", "0013", "0225", "Wednesday", "0002",
+             "PM", "0002",  "0014", "0034", "0012",   "0513", "Pacific Daylight Time",
+            /* Following two added by weiv for two new fields */ "1997", "0004", "" };
+    
+        Date someDate = new Date((long) 871508052513.0);
+        int j, exp;
+    
+        dateFormats[0] = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.US);
+        dateFormats[1] = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.FRANCE);
+        dateFormats[2] = new SimpleDateFormat("G, y, M, d, k, H, m, s, S, E, D, F, w, W, a, h, K, z, y, E", Locale.US);
+        dateFormats[3] = new SimpleDateFormat("GGGG, yyyy, MMMM, dddd, kkkk, HHHH, mmmm, ssss, SSSS, EEEE, DDDD, FFFF, wwww, WWWW, aaaa, hhhh, KKKK, zzzz, yyyy, EEEE", Locale.US);
+        for (j = 0, exp = 0; j < dateFormats_length; ++j) {
+            String str;
+            DateFormat df = dateFormats[j];
+            TimeZone tz = TimeZone.getTimeZone("PST");
+            ((SimpleTimeZone)tz).setDSTSavings(3600000);
+            df.setTimeZone(tz);
+            logln(" Pattern = " + ((SimpleDateFormat) df).toPattern());
+            str = "";
+            try {
+                logln("  Result = " + df.format(someDate));
+            } catch (Exception e) {
+                System.out.println(e);
+            }
+            for (int i = 0; i < fieldNames.length; ++i) {
+                String field = getFieldText(df, i, someDate);
+                String expStr = "";
+                if (!expected[exp].substring(0).equals("#")) {
+                    expStr = expected[exp];
+                } else {
+                    // we cannot have latin-1 characters in source code, therefore we fix up the string for "aou^t" 
+                    expStr = expStr + "\u0061" + "\u006f" + "\u00fb" + "\u0074";
+                }
+                if (!field.equals(expStr))
+                    errln("FAIL: field #" + i + " " + fieldNames[i] + " = \"" + field + "\", expected \"" + expStr + "\"");
+                ++exp;
+            }
+        }
+    }
+    
+    // internal utility function
+    public String getFieldText(DateFormat df, int field, Date date) {
+        final int[] fgCalendarToDateFormatField ={
+            DateFormat.ERA_FIELD, 
+            DateFormat.YEAR_FIELD, 
+            DateFormat.MONTH_FIELD,
+            DateFormat.WEEK_OF_YEAR_FIELD, 
+            DateFormat.WEEK_OF_MONTH_FIELD,
+            DateFormat.DATE_FIELD, 
+            DateFormat.DAY_OF_YEAR_FIELD, 
+            DateFormat.DAY_OF_WEEK_FIELD,     
+            DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD, 
+            DateFormat.AM_PM_FIELD,
+            DateFormat.HOUR1_FIELD, 
+            DateFormat.HOUR_OF_DAY0_FIELD, 
+            DateFormat.MINUTE_FIELD, 
+            DateFormat.SECOND_FIELD, 
+            DateFormat.MILLISECOND_FIELD,
+            DateFormat.TIMEZONE_FIELD
+            };
+        StringBuffer formatResult = new StringBuffer("");
+        // {sfb} added to convert Calendar Fields to DateFormat fields
+        FieldPosition pos = new FieldPosition(fgCalendarToDateFormatField[field]);
+        formatResult = df.format(date, formatResult, pos);    
+        return formatResult.substring(pos.getBeginIndex(), pos.getEndIndex());
+    }
+    
+    /**
+     * Verify that strings which contain incomplete specifications are parsed
+     * correctly.  In some instances, this means not being parsed at all, and
+     * returning an appropriate error.
+     */
+    public void TestPartialParse994() {
+    
+        SimpleDateFormat f = new SimpleDateFormat();
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(1997, 1 - 1, 17, 10, 11, 42);
+        Date date = null;
+        tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:11:42", cal.getTime());
+        tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:", date);
+        tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10", date);
+        tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 ", date);
+        tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17", date);
+    }
+    
+    // internal test subroutine, used by TestPartialParse994
+    public void tryPat994(SimpleDateFormat format, String pat, String str, Date expected) {
+        Date Null = null;
+        logln("Pattern \"" + pat + "\"   String \"" + str + "\"");
+        try {
+            format.applyPattern(pat);
+            Date date = format.parse(str);    
+            String f = ((DateFormat) format).format(date);
+            logln(" parse(" + str + ") -> " + date);
+            logln(" format -> " + f);
+            if (expected.equals(Null) || !date.equals(expected))
+                errln("FAIL: Expected null"); //" + expected);
+            if (!f.equals(str))
+                errln("FAIL: Expected " + str);
+        } catch (ParseException e) {
+            logln("ParseException: " + e.getMessage());
+            if (!(expected ==Null))
+                errln("FAIL: Expected " + expected);
+        } catch (Exception e) {
+            errln("*** Exception:");
+            e.printStackTrace();
+        }
+    }
+    
+    /**
+     * Verify the behavior of patterns in which digits for different fields run together
+     * without intervening separators.
+     */
+    public void TestRunTogetherPattern985() {
+        String format = "yyyyMMddHHmmssSSS";
+        String now, then;
+        //UBool flag;
+        SimpleDateFormat formatter = new SimpleDateFormat(format);
+        Date date1 = new Date();
+        now = ((DateFormat) formatter).format(date1);
+        logln(now);
+        ParsePosition pos = new ParsePosition(0);
+        Date date2 = formatter.parse(now, pos);
+        if (date2 == null)
+            then = "Parse stopped at " + pos.getIndex();
+        else
+            then = ((DateFormat) formatter).format(date2);
+        logln(then);
+        if (!date2.equals(date1))
+            errln("FAIL");
+    }
+
+    /**
+     * Verify the behavior of patterns in which digits for different fields run together
+     * without intervening separators.
+     */
+    public void TestRunTogetherPattern917() {
+        SimpleDateFormat fmt;
+        String myDate;
+        fmt = new SimpleDateFormat("yyyy/MM/dd");
+        myDate = "1997/02/03";
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(1997, 2 - 1, 3);
+        _testIt917(fmt, myDate, cal.getTime());
+        fmt = new SimpleDateFormat("yyyyMMdd");
+        myDate = "19970304";
+        cal.clear();
+        cal.set(1997, 3 - 1, 4);
+        _testIt917(fmt, myDate, cal.getTime());
+    
+    }
+    
+    // internal test subroutine, used by TestRunTogetherPattern917
+    public void _testIt917(SimpleDateFormat fmt, String str, Date expected) {
+        logln("pattern=" + fmt.toPattern() + "   string=" + str);
+        Date o = new Date();
+        o = (Date) ((DateFormat) fmt).parseObject(str, new ParsePosition(0));
+        logln("Parsed object: " + o);
+        if (!o.equals(expected))
+            errln("FAIL: Expected " + expected);
+        String formatted = ((DateFormat) fmt).format(o);
+        logln( "Formatted string: " + formatted);
+        if (!formatted.equals(str))
+            errln( "FAIL: Expected " + str);
+    }
+    
+    /**
+     * Verify the handling of Czech June and July, which have the unique attribute that
+     * one is a proper prefix substring of the other.
+     */
+    public void TestCzechMonths459() {
+        DateFormat fmt = DateFormat.getDateInstance(DateFormat.FULL, new Locale("cs", "", "")); 
+        logln("Pattern " + ((SimpleDateFormat) fmt).toPattern());
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(1997, Calendar.JUNE, 15);
+        Date june = cal.getTime();
+        cal.clear();
+        cal.set(1997, Calendar.JULY, 15);
+        Date july = cal.getTime();
+        String juneStr = fmt.format(june);
+        String julyStr = fmt.format(july);
+        try {
+            logln("format(June 15 1997) = " + juneStr);
+            Date d = fmt.parse(juneStr);
+            String s = fmt.format(d);
+            int month, yr, day, hr, min, sec;
+            cal.setTime(d);
+            yr = cal.get(Calendar.YEAR) - 1900;
+            month = cal.get(Calendar.MONTH);
+            day = cal.get(Calendar.DAY_OF_WEEK);
+            hr = cal.get(Calendar.HOUR_OF_DAY);
+            min = cal.get(Calendar.MINUTE);
+            sec = cal.get(Calendar.SECOND);
+            logln("  . parse . " + s + " (month = " + month + ")");
+            if (month != Calendar.JUNE)
+                errln("FAIL: Month should be June");
+            logln("format(July 15 1997) = " + julyStr);
+            d = fmt.parse(julyStr);
+            s = fmt.format(d);
+            cal.setTime(d);
+            yr = cal.get(Calendar.YEAR) - 1900;
+            month = cal.get(Calendar.MONTH);
+            day = cal.get(Calendar.DAY_OF_WEEK);
+            hr = cal.get(Calendar.HOUR_OF_DAY);
+            min = cal.get(Calendar.MINUTE);
+            sec = cal.get(Calendar.SECOND);
+            logln("  . parse . " + s + " (month = " + month + ")");
+            if (month != Calendar.JULY)
+                errln("FAIL: Month should be July");
+        } catch (ParseException e) {
+            errln(e.getMessage());
+        }
+    }
+    
+    /**
+     * Test the handling of 'D' in patterns.
+     */
+    public void TestLetterDPattern212() {
+        String dateString = "1995-040.05:01:29";
+        String bigD = "yyyy-DDD.hh:mm:ss";
+        String littleD = "yyyy-ddd.hh:mm:ss";
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(1995, 0, 1, 5, 1, 29);
+        Date expLittleD = cal.getTime();
+        Date expBigD = new Date((long) (expLittleD.getTime() + 39 * 24 * 3600000.0));
+        expLittleD = expBigD; // Expect the same, with default lenient parsing
+        logln("dateString= " + dateString);
+        SimpleDateFormat formatter = new SimpleDateFormat(bigD);
+        ParsePosition pos = new ParsePosition(0);
+        Date myDate = formatter.parse(dateString, pos);
+        logln("Using " + bigD + " . " + myDate);
+        if (!myDate.equals(expBigD))
+            errln("FAIL: Expected " + expBigD);
+        formatter = new SimpleDateFormat(littleD);
+        pos = new ParsePosition(0);
+        myDate = formatter.parse(dateString, pos);
+        logln("Using " + littleD + " . " + myDate);
+        if (!myDate.equals(expLittleD))
+            errln("FAIL: Expected " + expLittleD);
+    }
+    
+    /**
+     * Test the day of year pattern.
+     */
+    public void TestDayOfYearPattern195() {
+        Calendar cal = Calendar.getInstance();
+        Date today = cal.getTime();
+        int year,month,day; 
+        year = cal.get(Calendar.YEAR);
+        month = cal.get(Calendar.MONTH);
+        day = cal.get(Calendar.DAY_OF_MONTH);
+        cal.clear();
+        cal.set(year, month, day);
+        Date expected = cal.getTime();
+        logln("Test Date: " + today);
+        SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance();
+        tryPattern(sdf, today, null, expected);
+        tryPattern(sdf, today, "G yyyy DDD", expected);
+    }
+    
+    // interl test subroutine, used by TestDayOfYearPattern195
+    public void tryPattern(SimpleDateFormat sdf, Date d, String pattern, Date expected) {
+        if (pattern != null)
+            sdf.applyPattern(pattern);
+        logln("pattern: " + sdf.toPattern());
+        String formatResult = ((DateFormat) sdf).format(d);
+        logln(" format -> " + formatResult);
+        try {
+            Date d2 = sdf.parse(formatResult);
+            logln(" parse(" + formatResult + ") -> " + d2);
+            if (!d2.equals(expected))
+                errln("FAIL: Expected " + expected);
+            String format2 = ((DateFormat) sdf).format(d2);
+            logln(" format -> " + format2);
+            if (!formatResult.equals(format2))
+                errln("FAIL: Round trip drift");
+        } catch (Exception e) {
+            errln(e.getMessage());
+        }
+    }
+    
+    /**
+     * Test the handling of single quotes in patterns.
+     */
+    public void TestQuotePattern161() {
+        SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy 'at' hh:mm:ss a zzz", Locale.US); 
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(1997, Calendar.AUGUST, 13, 10, 42, 28);
+        Date currentTime_1 = cal.getTime();
+        String dateString = ((DateFormat) formatter).format(currentTime_1);
+        String exp = "08/13/1997 at 10:42:28 AM ";
+        logln("format(" + currentTime_1 + ") = " + dateString);
+        if (!dateString.substring(0, exp.length()).equals(exp))
+            errln("FAIL: Expected " + exp);
+    
+    }
+        
+    /**
+     * Verify the correct behavior when handling invalid input strings.
+     */
+    public void TestBadInput135() {
+        int looks[] = {DateFormat.SHORT, DateFormat.MEDIUM, DateFormat.LONG, DateFormat.FULL}; 
+        int looks_length = looks.length;
+        final String[] strings = {"Mar 15", "Mar 15 1997", "asdf", "3/1/97 1:23:", "3/1/00 1:23:45 AM"}; 
+        int strings_length = strings.length;
+        DateFormat full = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.US); 
+        String expected = "March 1, 2000 1:23:45 AM ";
+        for (int i = 0; i < strings_length; ++i) {
+            final String text = strings[i];
+            for (int j = 0; j < looks_length; ++j) {
+                int dateLook = looks[j];
+                for (int k = 0; k < looks_length; ++k) {
+                    int timeLook = looks[k];
+                    DateFormat df = DateFormat.getDateTimeInstance(dateLook, timeLook, Locale.US); 
+                    String prefix = text + ", " + dateLook + "/" + timeLook + ": "; 
+                    try {
+                        Date when = df.parse(text);
+                        if (when == null) {
+                            errln(prefix + "SHOULD NOT HAPPEN: parse returned null.");
+                            continue;
+                        }  
+                        if (when != null) {
+                            String format;
+                            format = full.format(when);
+                            logln(prefix + "OK: " + format);
+                            if (!format.substring(0, expected.length()).equals(expected))
+                                errln("FAIL: Expected " + expected);
+                        }
+                    } catch(java.text.ParseException e) {
+                        logln(e.getMessage());
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Verify the correct behavior when parsing an array of inputs against an
+     * array of patterns, with known results.  The results are encoded after
+     * the input strings in each row.
+     */
+    public void TestBadInput135a() {
+    
+        SimpleDateFormat dateParse = new SimpleDateFormat("", Locale.US);
+        final String ss;
+        Date date;
+        String[] parseFormats ={"MMMM d, yyyy", "MMMM d yyyy", "M/d/yy",
+                                "d MMMM, yyyy", "d MMMM yyyy",  "d MMMM",
+                                "MMMM d", "yyyy", "h:mm a MMMM d, yyyy" };
+        String[] inputStrings = {
+            "bogus string", null, null, null, null, null, null, null, null, null,
+                "April 1, 1997", "April 1, 1997", null, null, null, null, null, "April 1", null, null,
+                "Jan 1, 1970", "January 1, 1970", null, null, null, null, null, "January 1", null, null,
+                "Jan 1 2037", null, "January 1 2037", null, null, null, null, "January 1", null, null,
+                "1/1/70", null, null, "1/1/70", null, null, null, null, "0001", null,
+                "5 May 1997", null, null, null, null, "5 May 1997", "5 May", null, "0005", null,
+                "16 May", null, null, null, null, null, "16 May", null, "0016", null,
+                "April 30", null, null, null, null, null, null, "April 30", null, null,
+                "1998", null, null, null, null, null, null, null, "1998", null,
+                "1", null, null, null, null, null, null, null, "0001", null,
+                "3:00 pm Jan 1, 1997", null, null, null, null, null, null, null, "0003", "3:00 PM January 1, 1997",
+                };
+        final int PF_LENGTH = parseFormats.length;
+        final int INPUT_LENGTH = inputStrings.length;
+    
+        dateParse.applyPattern("d MMMM, yyyy");
+        dateParse.setTimeZone(TimeZone.getDefault());
+        ss = "not parseable";
+        //    String thePat;
+        logln("Trying to parse \"" + ss + "\" with " + dateParse.toPattern());
+        try {
+            date = dateParse.parse(ss);
+        } catch (Exception ex) {
+            logln("FAIL:" + ex);
+        }
+        for (int i = 0; i < INPUT_LENGTH; i += (PF_LENGTH + 1)) {
+            ParsePosition parsePosition = new ParsePosition(0);
+            String s = inputStrings[i];
+            for (int index = 0; index < PF_LENGTH; ++index) {
+                final String expected = inputStrings[i + 1 + index];
+                dateParse.applyPattern(parseFormats[index]);
+                dateParse.setTimeZone(TimeZone.getDefault());
+                try {
+                    parsePosition.setIndex(0);
+                    date = dateParse.parse(s, parsePosition);
+                    if (parsePosition.getIndex() != 0) {
+                        String s1, s2;
+                        s1 = s.substring(0, parsePosition.getIndex());
+                        s2 = s.substring(parsePosition.getIndex(), s.length());
+                        if (date == null) {
+                            errln("ERROR: null result fmt=\"" + parseFormats[index]
+                                    + "\" pos=" + parsePosition.getIndex()
+                                    + " " + s1 + "|" + s2);
+                        } else {
+                            String result = ((DateFormat) dateParse).format(date);
+                            logln("Parsed \"" + s + "\" using \"" + dateParse.toPattern() + "\" to: " + result);
+                            if (expected == null)
+                                errln("FAIL: Expected parse failure");
+                            else
+                                if (!result.equals(expected))
+                                    errln("FAIL: Expected " + expected);
+                        }
+                    } else
+                        if (expected != null) {
+                            errln("FAIL: Expected " + expected + " from \"" + s
+                                    + "\" with \"" + dateParse.toPattern()+ "\"");
+                        }
+                } catch (Exception ex) {
+                    logln("FAIL:" + ex);
+                }
+            }
+        }
+    
+    }
+    
+    /**
+     * Test the parsing of two-digit years.
+     */
+    public void TestTwoDigitYear() {
+        DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(117 + 1900, Calendar.JUNE, 5);
+        parse2DigitYear(fmt, "6/5/17", cal.getTime());
+        cal.clear();
+        cal.set(34 + 1900, Calendar.JUNE, 4);
+        parse2DigitYear(fmt, "6/4/34", cal.getTime());
+    }
+    
+    // internal test subroutine, used by TestTwoDigitYear
+    public void parse2DigitYear(DateFormat fmt, String str, Date expected) {
+        try {
+            Date d = fmt.parse(str);
+            logln("Parsing \""+ str+ "\" with "+ ((SimpleDateFormat) fmt).toPattern()
+                    + "  => "+ d); 
+            if (!d.equals(expected))
+                errln( "FAIL: Expected " + expected);
+        } catch (ParseException e) {
+            errln(e.getMessage());
+        }
+    }
+    
+    /**
+     * Test the formatting of time zones.
+     */
+    public void TestDateFormatZone061() {
+        Date date;
+        DateFormat formatter;
+        date = new Date(859248000000l);
+        logln("Date 1997/3/25 00:00 GMT: " + date);
+        formatter = new SimpleDateFormat("dd-MMM-yyyyy HH:mm", Locale.UK);
+        formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
+        String temp = formatter.format(date);
+        logln("Formatted in GMT to: " + temp);
+        try {
+            Date tempDate = formatter.parse(temp);
+            logln("Parsed to: " + tempDate);
+            if (!tempDate.equals(date))
+                errln("FAIL: Expected " + date);
+        } catch (Throwable t) {
+            System.out.println(t);
+        }
+    
+    }
+    
+    /**
+     * Test the formatting of time zones.
+     */
+    public void TestDateFormatZone146() {
+        TimeZone saveDefault = TimeZone.getDefault();
+    
+        //try {
+        TimeZone thedefault = TimeZone.getTimeZone("GMT");
+        TimeZone.setDefault(thedefault);
+        // java.util.Locale.setDefault(new java.util.Locale("ar", "", ""));
+    
+        // check to be sure... its GMT all right
+        TimeZone testdefault = TimeZone.getDefault();
+        String testtimezone = testdefault.getID();
+        if (testtimezone.equals("GMT"))
+            logln("Test timezone = " + testtimezone);
+        else
+            errln("Test timezone should be GMT, not " + testtimezone);
+    
+        // now try to use the default GMT time zone
+        GregorianCalendar greenwichcalendar = new GregorianCalendar(1997, 3, 4, 23, 0);
+        //*****************************greenwichcalendar.setTimeZone(TimeZone.getDefault());
+        //greenwichcalendar.set(1997, 3, 4, 23, 0);
+        // try anything to set hour to 23:00 !!!
+        greenwichcalendar.set(Calendar.HOUR_OF_DAY, 23);
+        // get time
+        Date greenwichdate = greenwichcalendar.getTime();
+        // format every way
+        String DATA[] = {
+                "simple format:  ", "04/04/97 23:00 GMT", 
+                "MM/dd/yy HH:mm z", "full format:    ", 
+                "Friday, April 4, 1997 11:00:00 o'clock PM GMT", 
+                "EEEE, MMMM d, yyyy h:mm:ss 'o''clock' a z", 
+                "long format:    ", "April 4, 1997 11:00:00 PM GMT", 
+                "MMMM d, yyyy h:mm:ss a z", "default format: ", 
+                "04-Apr-97 11:00:00 PM", "dd-MMM-yy h:mm:ss a", 
+                "short format:   ", "4/4/97 11:00 PM", 
+                "M/d/yy h:mm a"}; 
+        int DATA_length = DATA.length;
+    
+        for (int i = 0; i < DATA_length; i += 3) {
+            DateFormat fmt = new SimpleDateFormat(DATA[i + 2], Locale.ENGLISH);
+            fmt.setCalendar(greenwichcalendar);
+            String result = fmt.format(greenwichdate);
+            logln(DATA[i] + result);
+            if (!result.equals(DATA[i + 1]))
+                errln("FAIL: Expected " + DATA[i + 1] + ", got " + result);
+        }
+        //}
+        //finally {
+        TimeZone.setDefault(saveDefault);
+        //}
+    
+    }
+    
+    /**
+     * Test the formatting of dates in different locales.
+     */
+    public void TestLocaleDateFormat() {
+    
+        Date testDate = new Date(874306800000l); //Mon Sep 15 00:00:00 PDT 1997
+        DateFormat dfFrench = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.FRENCH);
+        DateFormat dfUS = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.US);
+        //Set TimeZone = PDT
+        TimeZone tz = TimeZone.getTimeZone("PST");
+        ((SimpleTimeZone)tz).setDSTSavings(3600000);
+        dfFrench.setTimeZone(tz);
+        dfUS.setTimeZone(tz);
+        //String expectedFRENCH = "lundi 15 septembre 1997 00 h 00 GMT-07:00";
+        String expectedFRENCH = "lundi 15 septembre 1997 00 h 00 PDT";
+        //UnicodeString expectedUS ( "Monday, September 15, 1997 12:00:00 o'clock AM PDT" );
+        String expectedUS = "Monday, September 15, 1997 12:00:00 AM PDT";
+        logln("Date set to : " + testDate);
+        String out = dfFrench.format(testDate);
+        logln("Date Formated with French Locale " + out);
+        if (!out.equals(expectedFRENCH))
+            errln("FAIL: Expected " + expectedFRENCH);
+        out = dfUS.format(testDate);
+        logln("Date Formated with US Locale " + out);
+        if (!out.equals(expectedUS))
+            errln("FAIL: Expected " + expectedUS);
+    }
+}
diff --git a/src/com/ibm/icu/test/format/IntlTestDateFormat.java b/src/com/ibm/icu/test/format/IntlTestDateFormat.java
new file mode 100755
index 0000000..c7f9340
--- /dev/null
+++ b/src/com/ibm/icu/test/format/IntlTestDateFormat.java
@@ -0,0 +1,270 @@
+/***************************************************************************************
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/test/format/Attic/IntlTestDateFormat.java,v $ 
+ * $Date: 2001/10/23 13:11:35 $ 
+ * $Revision: 1.3 $
+ *
+ *****************************************************************************************
+ */
+
+/** 
+ * Port From:   JDK 1.4b1 : java.text.Format.IntlTestDateFormat
+ * Source File: java/text/format/IntlTestDateFormat.java
+ **/
+
+/*
+    @test 1.4 98/03/06
+    @summary test International Date Format
+*/
+/*
+(C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+(C) Copyright IBM Corp. 1996, 1997, 2001 - All Rights Reserved
+
+  The original version of this source code and documentation is copyrighted and
+owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
+provided under terms of a License Agreement between Taligent and Sun. This
+technology is protected by multiple US and International patents. This notice and
+attribution to Taligent may not be removed.
+  Taligent is a registered trademark of Taligent, Inc.
+*/
+
+package com.ibm.icu.test.format;
+
+import com.ibm.text.*;
+import com.ibm.util.*;
+import java.text.FieldPosition;
+import java.text.ParseException;
+import java.util.Locale;
+import java.util.Random;
+import java.util.Date;
+
+public class IntlTestDateFormat extends com.ibm.test.TestFmwk {
+    // Values in milliseconds (== Date)
+    private static final long ONESECOND = 1000;
+    private static final long ONEMINUTE = 60 * ONESECOND;
+    private static final long ONEHOUR = 60 * ONEMINUTE;
+    private static final long ONEDAY = 24 * ONEHOUR;
+    //private static final double ONEYEAR = 365.25 * ONEDAY; // Approximate //The variable is never used
+
+    // EModes
+    //private static final byte GENERIC = 0;
+    //private static final byte TIME = GENERIC + 1; //The variable is never used
+    //private static final byte DATE = TIME + 1; //The variable is never used
+    //private static final byte DATE_TIME = DATE + 1; //The variable is never used
+
+    private DateFormat fFormat = DateFormat.getInstance();
+    private String fTestName = new String("getInstance");
+    private int fLimit = 3; // How many iterations it should take to reach convergence
+    
+    public IntlTestDateFormat() {
+        //Constructure
+    }
+    
+    public static void main(String[] args) throws Exception {
+        new IntlTestDateFormat().run(args);
+    }
+
+    public void TestLocale() {
+        localeTest(Locale.getDefault(), "Default Locale");
+    }
+
+    // This test does round-trip testing (format -> parse -> format -> parse -> etc.) of DateFormat.
+    public void localeTest(final Locale locale, final String localeName) {
+        int timeStyle, dateStyle;
+
+        // For patterns including only time information and a timezone, it may take
+        // up to three iterations, since the timezone may shift as the year number
+        // is determined.  For other patterns, 2 iterations should suffice.
+        fLimit = 3;
+
+        for(timeStyle = 0; timeStyle < 4; timeStyle++) {
+            fTestName = new String("Time test " + timeStyle + " (" + localeName + ")");
+            try {
+                fFormat = DateFormat.getTimeInstance(timeStyle, locale);
+            }
+            catch(StringIndexOutOfBoundsException e) {
+                errln("FAIL: localeTest time getTimeInstance exception");
+                throw e;
+            }
+            TestFormat();
+        }
+
+        fLimit = 2;
+
+        for(dateStyle = 0; dateStyle < 4; dateStyle++) {
+            fTestName = new String("Date test " + dateStyle + " (" + localeName + ")");
+            try {
+                fFormat = DateFormat.getDateInstance(dateStyle, locale);
+            }
+            catch(StringIndexOutOfBoundsException e) {
+                errln("FAIL: localeTest date getTimeInstance exception");
+                throw e;
+            }
+            TestFormat();
+        }
+
+        for(dateStyle = 0; dateStyle < 4; dateStyle++) {
+            for(timeStyle = 0; timeStyle < 4; timeStyle++) {
+                fTestName = new String("DateTime test " + dateStyle + "/" + timeStyle + " (" + localeName + ")");
+                try {
+                    fFormat = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
+                }
+                catch(StringIndexOutOfBoundsException e) {
+                    errln("FAIL: localeTest date/time getDateTimeInstance exception");
+                    throw e;
+                }
+                TestFormat();
+            }
+        }
+    }
+
+    public void TestFormat() {
+        if (fFormat == null) {
+            errln("FAIL: DateFormat creation failed");
+            return;
+        }
+        //        logln("TestFormat: " + fTestName);
+        Date now = new Date();
+        tryDate(new Date(0));
+        tryDate(new Date((long) 1278161801778.0));
+        tryDate(now);
+        // Shift 6 months into the future, AT THE SAME TIME OF DAY.
+        // This will test the DST handling.
+        tryDate(new Date(now.getTime() + 6*30*ONEDAY));
+
+        Date limit = new Date(now.getTime() * 10); // Arbitrary limit
+        for (int i=0; i<2; ++i)
+            //            tryDate(new Date(floor(randDouble() * limit)));
+            tryDate(new Date((long) (randDouble() * limit.getTime())));
+    }
+
+    private void describeTest() {
+        if (fFormat == null) {
+            errln("FAIL: no DateFormat");
+            return;
+        }
+
+        // Assume it's a SimpleDateFormat and get some info
+        SimpleDateFormat s = (SimpleDateFormat) fFormat;
+        logln(fTestName + " Pattern " + s.toPattern());
+    }
+
+    private void tryDate(Date theDate) {
+        final int DEPTH = 10;
+        Date[] date = new Date[DEPTH];
+        StringBuffer[] string = new StringBuffer[DEPTH];
+
+        int dateMatch = 0;
+        int stringMatch = 0;
+        boolean dump = false;
+        int i;
+        for (i=0; i<DEPTH; ++i) string[i] = new StringBuffer();
+        for (i=0; i<DEPTH; ++i) {
+            if (i == 0) date[i] = theDate;
+            else {
+                try {
+                    date[i] = fFormat.parse(string[i-1].toString());
+                }
+                catch (ParseException e) {
+                    describeTest();
+                    errln("********** FAIL: Parse of " + string[i-1] + " failed.");
+                    dump = true;
+                    break;
+                }
+            }
+            FieldPosition position = new FieldPosition(0);
+            fFormat.format(date[i], string[i], position);
+            if (i > 0) {
+                if (dateMatch == 0 && date[i] == date[i-1]) dateMatch = i;
+                else if (dateMatch > 0 && date[i] != date[i-1]) {
+                    describeTest();
+                    errln("********** FAIL: Date mismatch after match.");
+                    dump = true;
+                    break;
+                }
+                if (stringMatch == 0 && string[i] == string[i-1]) stringMatch = i;
+                else if (stringMatch > 0 && string[i] != string[i-1]) {
+                    describeTest();
+                    errln("********** FAIL: String mismatch after match.");
+                    dump = true;
+                    break;
+                }
+            }
+            if (dateMatch > 0 && stringMatch > 0) break;
+        }
+        if (i == DEPTH) --i;
+
+        if (stringMatch > fLimit || dateMatch > fLimit) {
+            describeTest();
+            errln("********** FAIL: No string and/or date match within " + fLimit + " iterations.");
+            dump = true;
+        }
+
+        if (dump) {
+            for (int k=0; k<=i; ++k) {
+                logln("" + k + ": " + date[k] + " F> " + string[k] + " P> ");
+            }
+        }
+    }
+
+    // Return a random double from 0.01 to 1, inclusive
+    private double randDouble() {
+        // Assume 8-bit (or larger) rand values.  Also assume
+        // that the system rand() function is very poor, which it always is.
+        //        double d;
+        //        int i;
+        //        do {
+        //            for (i=0; i < sizeof(double); ++i)
+        //            {
+        //                char poke = (char*)&d;
+        //                poke[i] = (rand() & 0xFF);
+        //            }
+        //        } while (TPlatformUtilities.isNaN(d) || TPlatformUtilities.isInfinite(d));
+
+        //        if (d < 0.0) d = -d;
+        //        if (d > 0.0)
+        //        {
+        //            double e = floor(log10(d));
+        //            if (e < -2.0) d *= pow(10.0, -e-2);
+        //            else if (e > -1.0) d /= pow(10.0, e+1);
+        //        }
+        //        return d;
+        Random rand = new Random();
+        return rand.nextDouble();
+    }
+
+    public void TestAvailableLocales() {
+        final Locale[] locales = DateFormat.getAvailableLocales();
+        long count = locales.length;
+        logln("" + count + " available locales");
+        if (locales != null  &&  count != 0) {
+            StringBuffer all = new StringBuffer();
+            for (int i=0; i<count; ++i) {
+                if (i!=0) all.append(", ");
+                all.append(locales[i].getDisplayName());
+            }
+            logln(all.toString());
+        }
+        else errln("********** FAIL: Zero available locales or null array pointer");
+    }
+
+    /* This test is too slow; we disable it for now
+    public void TestMonster() {
+        final Locale[] locales = DateFormat.getAvailableLocales();
+        long count = locales.length;
+        if (locales != null  &&  count != 0) {
+            for (int i=0; i<count; ++i) {
+                String name = locales[i].getDisplayName();
+                logln("Testing " + name + "...");
+                try {
+                    localeTest(locales[i], name);
+                }
+                catch(Exception e) {
+                    errln("FAIL: TestMonster localeTest exception" + e);
+                }
+            }
+        }
+    }
+    */
+}
+
+//eof
diff --git a/src/com/ibm/icu/test/format/IntlTestDateFormatAPI.java b/src/com/ibm/icu/test/format/IntlTestDateFormatAPI.java
new file mode 100755
index 0000000..5072c60
--- /dev/null
+++ b/src/com/ibm/icu/test/format/IntlTestDateFormatAPI.java
@@ -0,0 +1,211 @@
+/*****************************************************************************************
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/test/format/Attic/IntlTestDateFormatAPI.java,v $ 
+ * $Date: 2001/10/30 02:42:49 $ 
+ * $Revision: 1.3 $
+ *
+ *****************************************************************************************
+ **/
+
+/** 
+ * Port From:   JDK 1.4b1 : java.text.Format.IntlTestDateFormatAPI
+ * Source File: java/text/format/IntlTestDateFormatAPI.java
+ **/
+
+/*
+    @test 1.4 98/03/06
+    @summary test International Date Format API
+*/
+/*
+(C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+(C) Copyright IBM Corp. 1996, 1997, 2001 - All Rights Reserved
+
+  The original version of this source code and documentation is copyrighted and
+owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
+provided under terms of a License Agreement between Taligent and Sun. This
+technology is protected by multiple US and International patents. This notice and
+attribution to Taligent may not be removed.
+  Taligent is a registered trademark of Taligent, Inc.
+*/
+
+package com.ibm.icu.test.format;
+
+import com.ibm.util.*;
+import com.ibm.text.*;
+import java.util.Locale;
+import java.util.Date;
+import java.text.ParsePosition;
+import java.text.FieldPosition;
+import java.text.ParseException;
+
+public class IntlTestDateFormatAPI extends com.ibm.test.TestFmwk
+{
+    public static void main(String[] args) throws Exception {
+        new IntlTestDateFormatAPI().run(args);
+    }
+
+    // Test that the equals method works correctly.
+    public void TestEquals()
+    {
+        // Create two objects at different system times
+        DateFormat a = DateFormat.getInstance();
+        Date start = Calendar.getInstance().getTime();
+        while (true) {
+            // changed to remove compiler warnings.
+            if (!start.equals(Calendar.getInstance().getTime())) {
+                break; // Wait for time to change
+            }
+        }
+        DateFormat b = DateFormat.getInstance();
+
+        if (!(a.equals(b)))
+            errln("FAIL: DateFormat objects created at different times are unequal.");
+
+        if (b instanceof SimpleDateFormat)
+        {
+            //double ONE_YEAR = 365*24*60*60*1000.0; //The variable is never used
+            try {
+//                ((SimpleDateFormat)b).setTwoDigitStartDate(start.getTime() + 50*ONE_YEAR);
+//                if (a.equals(b))
+//                    errln("FAIL: DateFormat objects with different two digit start dates are equal.");
+            }
+            catch (Exception e) {
+                errln("FAIL: setTwoDigitStartDate failed.");
+            }
+        }
+    }
+
+    // This test checks various generic API methods in DateFormat to achieve 100% API coverage.
+    public void TestAPI()
+    {
+        logln("DateFormat API test---"); logln("");
+        Locale.setDefault(Locale.ENGLISH);
+
+
+        // ======= Test constructors
+
+        logln("Testing DateFormat constructors");
+
+        DateFormat def = DateFormat.getInstance();
+        DateFormat fr = DateFormat.getTimeInstance(DateFormat.FULL, Locale.FRENCH);
+        DateFormat it = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.ITALIAN);
+        DateFormat de = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.GERMAN);
+
+        // ======= Test equality
+
+        logln("Testing equality operator");
+
+        if( fr.equals(it) ) {
+            errln("ERROR: equals failed");
+        }
+
+        // ======= Test various format() methods
+
+        logln("Testing various format() methods");
+
+        Date d = new Date((long)837039928046.0);
+
+        StringBuffer res1 = new StringBuffer();
+        StringBuffer res2 = new StringBuffer();
+        String res3 = new String();
+        FieldPosition pos1 = new FieldPosition(0);
+        FieldPosition pos2 = new FieldPosition(0);
+
+        res1 = fr.format(d, res1, pos1);
+        logln("" + d.getTime() + " formatted to " + res1);
+
+        res2 = it.format(d, res2, pos2);
+        logln("" + d.getTime() + " formatted to " + res2);
+
+        res3 = de.format(d);
+        logln("" + d.getTime() + " formatted to " + res3);
+
+        // ======= Test parse()
+
+        logln("Testing parse()");
+
+        String text = new String("02/03/76 2:50 AM, CST");
+        Object result1 = new Date();
+        Date result2 = new Date();
+        Date result3 = new Date();
+        ParsePosition pos = new ParsePosition(0);
+        ParsePosition pos01 = new ParsePosition(0);
+
+        result1 = def.parseObject(text, pos);
+        if (result1 == null) {
+            errln("ERROR: parseObject() failed for " + text);
+        }
+        logln(text + " parsed into " + ((Date)result1).getTime());
+
+        try {
+            result2 = def.parse(text);
+        }
+        catch (ParseException e) {
+            errln("ERROR: parse() failed");
+        }
+        logln(text + " parsed into " + result2.getTime());
+
+        result3 = def.parse(text, pos01);
+        if (result3 == null) {
+            errln("ERROR: parse() failed for " + text);
+        }
+        logln(text + " parsed into " + result3.getTime());
+
+
+        // ======= Test getters and setters
+
+        logln("Testing getters and setters");
+
+        final Locale[] locales = DateFormat.getAvailableLocales();
+        long count = locales.length;
+        logln("Got " + count + " locales" );
+        for(int i = 0; i < count; i++) {
+            String name;
+            name = locales[i].getDisplayName();
+            logln(name);
+        }
+
+        fr.setLenient(it.isLenient());
+        if(fr.isLenient() != it.isLenient()) {
+            errln("ERROR: setLenient() failed");
+        }
+
+        final Calendar cal = def.getCalendar();
+        Calendar newCal = (Calendar) cal.clone();
+        de.setCalendar(newCal);
+        it.setCalendar(newCal);
+        if( ! de.getCalendar().equals(it.getCalendar())) {
+            errln("ERROR: set Calendar() failed");
+        }
+
+        final NumberFormat nf = def.getNumberFormat();
+        NumberFormat newNf = (NumberFormat) nf.clone();
+        de.setNumberFormat(newNf);
+        it.setNumberFormat(newNf);
+        if( ! de.getNumberFormat().equals(it.getNumberFormat())) {
+            errln("ERROR: set NumberFormat() failed");
+        }
+
+        final TimeZone tz = def.getTimeZone();
+        TimeZone newTz = (TimeZone) tz.clone();
+        de.setTimeZone(newTz);
+        it.setTimeZone(newTz);
+        if( ! de.getTimeZone().equals(it.getTimeZone())) {
+            errln("ERROR: set TimeZone() failed");
+        }
+
+        // ======= Test getStaticClassID()
+
+//        logln("Testing instanceof()");
+
+//        try {
+//            DateFormat test = new SimpleDateFormat();
+
+//            if (! (test instanceof SimpleDateFormat)) {
+//                errln("ERROR: instanceof failed");
+//            }
+//        }
+//        catch (Exception e) {
+//            errln("ERROR: Couldn't create a DateFormat");
+//        }
+    }
+}
diff --git a/src/com/ibm/icu/test/format/IntlTestDateFormatAPIC.java b/src/com/ibm/icu/test/format/IntlTestDateFormatAPIC.java
new file mode 100755
index 0000000..bcac931
--- /dev/null
+++ b/src/com/ibm/icu/test/format/IntlTestDateFormatAPIC.java
@@ -0,0 +1,159 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2001, International Business Machines Corporation and         *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/test/format/Attic/IntlTestDateFormatAPIC.java,v $ 
+ * $Date: 2001/10/19 11:43:37 $ 
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************************
+ */
+