ICU-7075 Tag r26422 of ICU4J trunk as milestone-4-3-2.

X-SVN-Rev: 26743
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..444d4ce
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,329 @@
+* 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
+
+/build.properties -text
+demos/manifest.stub -text
+icu-eclipse/misc/ICUConfig.properties -text
+main/classes/charset/.classpath -text
+main/classes/charset/.project -text
+main/classes/charset/.settings/org.eclipse.jdt.core.prefs -text
+main/classes/charset/manifest.stub -text
+main/classes/collate/.classpath -text
+main/classes/collate/.project -text
+main/classes/collate/.settings/org.eclipse.jdt.core.prefs -text
+main/classes/collate/.settings/org.eclipse.jdt.ui.prefs -text
+main/classes/collate/collate-build.launch -text
+main/classes/core/.classpath -text
+main/classes/core/.project -text
+main/classes/core/.settings/org.eclipse.jdt.core.prefs -text
+main/classes/core/manifest.stub -text
+main/classes/localespi/.classpath -text
+main/classes/localespi/.project -text
+main/classes/localespi/.settings/org.eclipse.jdt.core.prefs -text
+main/classes/localespi/manifest.stub -text
+main/classes/localespi/src/META-INF/services/java.text.spi.BreakIteratorProvider -text
+main/classes/localespi/src/META-INF/services/java.text.spi.CollatorProvider -text
+main/classes/localespi/src/META-INF/services/java.text.spi.DateFormatProvider -text
+main/classes/localespi/src/META-INF/services/java.text.spi.DateFormatSymbolsProvider -text
+main/classes/localespi/src/META-INF/services/java.text.spi.DecimalFormatSymbolsProvider -text
+main/classes/localespi/src/META-INF/services/java.text.spi.NumberFormatProvider -text
+main/classes/localespi/src/META-INF/services/java.util.spi.CurrencyNameProvider -text
+main/classes/localespi/src/META-INF/services/java.util.spi.LocaleNameProvider -text
+main/classes/localespi/src/META-INF/services/java.util.spi.TimeZoneNameProvider -text
+main/classes/localespi/src/com/ibm/icu/impl/javaspi/ICULocaleServiceProviderConfig.properties -text
+main/classes/translit/.externalToolBuilders/copy-data-translit.launch -text
+main/classes/translit/.settings/org.eclipse.jdt.core.prefs -text
+main/classes/translit/.settings/org.eclipse.jdt.ui.prefs -text
+main/classes/translit/translit-build.launch -text
+main/shared/.project -text
+main/shared/build/eclipse-dummy.jar -text
+main/shared/data/icudata.jar -text
+main/shared/data/testdata.jar -text
+main/tests/charset/.classpath -text
+main/tests/charset/.project -text
+main/tests/charset/.settings/org.eclipse.jdt.core.prefs -text
+main/tests/charset/manifest.stub -text
+main/tests/collate/.classpath -text
+main/tests/collate/.project -text
+main/tests/collate/.settings/org.eclipse.jdt.core.prefs -text
+main/tests/collate/.settings/org.eclipse.jdt.ui.prefs -text
+main/tests/collate/collate-tests-build.launch -text
+main/tests/core/.classpath -text
+main/tests/core/.project -text
+main/tests/core/.settings/org.eclipse.jdt.core.prefs -text
+main/tests/core/manifest.stub -text
+main/tests/core/src/com/ibm/icu/dev/data/rbbi/english.dict -text
+main/tests/core/src/com/ibm/icu/dev/data/thai6.ucs -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.impl.OlsonTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.impl.TimeZoneAdapter.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.math.BigDecimal.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.math.MathContext.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.text.ArabicShapingException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.text.ChineseDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.text.ChineseDateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.text.DateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.text.DateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.text.DecimalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.text.DecimalFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.text.MessageFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.text.NumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.text.RuleBasedNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.text.SimpleDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.text.StringPrepParseException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.BuddhistCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.Calendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.ChineseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.CopticCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.Currency.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.EthiopicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.GregorianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.HebrewCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.IslamicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.JapaneseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.SimpleTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.TimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.ULocale.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.util.UResourceTypeMismatchException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.impl.DateNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.impl.InvalidFormatException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.impl.OlsonTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.impl.RelativeDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.impl.TimeZoneAdapter.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.impl.duration.BasicDurationFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.math.BigDecimal.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.math.MathContext.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.ArabicShapingException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.ChineseDateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.ChineseDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.ChineseDateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.DateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.DateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.DateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.DecimalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.DecimalFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.MessageFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.MessageFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.NumberFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.NumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.PluralFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.PluralRules.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.RuleBasedNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.SimpleDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.text.StringPrepParseException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.AnnualTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.BuddhistCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.Calendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.ChineseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.CopticCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.Currency.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.DateTimeRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.EthiopicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.GregorianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.HebrewCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.IndianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.InitialTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.IslamicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.JapaneseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.RuleBasedTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.SimpleTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.TaiwanCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.TimeArrayTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.TimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.ULocale.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.UResourceTypeMismatchException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.8.1/com.ibm.icu.util.VTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.impl.DateNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.impl.InvalidFormatException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.impl.JavaTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.impl.OlsonTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.impl.RelativeDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.impl.TimeZoneAdapter.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.impl.duration.BasicDurationFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.math.BigDecimal.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.math.MathContext.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.ArabicShapingException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.ChineseDateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.ChineseDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.ChineseDateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.DateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.DateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.DateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.DateIntervalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.DateIntervalInfo$PatternInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.DateIntervalInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.DecimalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.DecimalFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.MessageFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.MessageFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.NumberFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.NumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.PluralFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.PluralRules.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.RuleBasedNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.SimpleDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.StringPrepParseException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.text.TimeUnitFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.AnnualTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.BuddhistCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.Calendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.ChineseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.CopticCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.Currency.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.DateInterval.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.DateTimeRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.EthiopicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.GregorianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.HebrewCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.IndianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.InitialTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.IslamicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.JapaneseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.RuleBasedTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.SimpleTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.TaiwanCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.TimeArrayTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.TimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.ULocale.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.UResourceTypeMismatchException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.0/com.ibm.icu.util.VTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.impl.DateNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.impl.IllegalIcuArgumentException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.impl.InvalidFormatException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.impl.JavaTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.impl.OlsonTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.impl.RelativeDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.impl.TimeZoneAdapter.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.impl.duration.BasicDurationFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.impl.locale.LocaleSyntaxException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.math.BigDecimal.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.math.MathContext.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.ArabicShapingException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.ChineseDateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.ChineseDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.ChineseDateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.CurrencyPluralInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.DateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.DateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.DateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.DateIntervalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.DateIntervalInfo$PatternInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.DateIntervalInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.DecimalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.DecimalFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.MessageFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.MessageFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.NumberFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.NumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.PluralFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.PluralRules.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.RuleBasedNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.SimpleDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.StringPrepParseException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.text.TimeUnitFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.AnnualTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.BuddhistCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.Calendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.ChineseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.CopticCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.Currency.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.DateInterval.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.DateTimeRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.EthiopicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.GregorianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.HebrewCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.IllformedLocaleException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.IndianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.InitialTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.IslamicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.JapaneseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.RuleBasedTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.SimpleTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.TaiwanCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.TimeArrayTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.TimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.ULocale.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.UResourceTypeMismatchException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_4.2.1/com.ibm.icu.util.VTimeZone.dat -text
+main/tests/framework/.classpath -text
+main/tests/framework/.project -text
+main/tests/framework/.settings/org.eclipse.jdt.core.prefs -text
+main/tests/framework/manifest.stub -text
+main/tests/localespi/.classpath -text
+main/tests/localespi/.project -text
+main/tests/localespi/manifest.stub -text
+main/tests/translit/.externalToolBuilders/copy-translit-test-data.launch -text
+main/tests/translit/.settings/org.eclipse.jdt.core.prefs -text
+main/tests/translit/.settings/org.eclipse.jdt.ui.prefs -text
+main/tests/translit/translit-tests-build.launch -text
+tools/build/icu4j28.api.gz -text
+tools/build/icu4j30.api.gz -text
+tools/build/icu4j32.api.gz -text
+tools/build/icu4j34.api.gz -text
+tools/build/icu4j341.api.gz -text
+tools/build/icu4j342.api.gz -text
+tools/build/icu4j343.api.gz -text
+tools/build/icu4j36.api.gz -text
+tools/build/icu4j38.api.gz -text
+tools/build/icu4j381.api.gz -text
+tools/build/icu4j400.api.gz -text
+tools/build/icu4j401.api.gz -text
+tools/build/icu4j42.api.gz -text
+tools/build/icu4j421.api.gz -text
+tools/build/manifest.stub -text
+tools/misc/manifest.stub -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/.gitignore b/.gitignore
new file mode 100644
index 0000000..344a017
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+/*.jar
+/.project
+demos/out
+/doc
+main/classes/charset/out
+main/classes/collate/out
+main/classes/core/out
+main/classes/localespi/out
+main/classes/translit/out
+main/tests/charset/out
+main/tests/collate/out
+main/tests/core/out
+main/tests/framework/out
+main/tests/localespi/out
+main/tests/translit/out
+/out
+tools/build/out
+tools/misc/out
diff --git a/APIChangeReport.html b/APIChangeReport.html
new file mode 100644
index 0000000..6417b35
--- /dev/null
+++ b/APIChangeReport.html
@@ -0,0 +1,401 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>ICU4J API Comparison: ICU4J 4.2.1 with ICU4J 4.3.2</title>
+<!-- Copyright 2009, IBM, All Rights Reserved. -->
+</head>
+<body>
+<h1>ICU4J API Comparison: ICU4J 4.2.1 with ICU4J 4.3.2</h1>
+
+<hr/>
+<h2>Removed from ICU4J 4.2.1</h2>
+
+<h3>Package com.ibm.icu.math</h3>
+<ul>
+BigDecimal
+<ul>
+<li>(stable)     public int <i>compareTo</i>(java.lang.Object)</li>
+</ul>
+</ul>
+
+<h3>Package com.ibm.icu.text</h3>
+<ul>
+<li><span style='color:red'>*internal*  </span>public class <i>BreakDictionary</i></li>
+CollationKey
+<ul>
+<li>(stable)     public int <i>compareTo</i>(java.lang.Object)</li>
+</ul>
+DateIntervalInfo
+<ul>
+<li>(stable)     public java.lang.Object <i>cloneAsThawed</i>()</li>
+<li>(stable)     public java.lang.Object <i>freeze</i>()</li>
+</ul>
+DateTimePatternGenerator
+<ul>
+<li>(stable)     public java.lang.Object <i>cloneAsThawed</i>()</li>
+<li>(stable)     public java.lang.Object <i>freeze</i>()</li>
+</ul>
+</ul>
+
+<h3>Package com.ibm.icu.util</h3>
+<ul>
+Calendar
+<ul>
+<li>(stable)     public int <i>compareTo</i>(java.lang.Object)</li>
+</ul>
+ChineseCalendar
+<ul>
+<li>(stable)     public static int IS_LEAP_MONTH</li>
+<li>(stable)     protected int[] <i>handleCreateFields</i>()</li>
+</ul>
+GlobalizationPreferences
+<ul>
+<li>(draft)      public java.lang.Object <i>cloneAsThawed</i>()</li>
+<li>(draft)      public java.lang.Object <i>freeze</i>()</li>
+</ul>
+ULocale
+<ul>
+<li>(draft)      public static VersionInfo <i>getCLDRVersion</i>()</li>
+</ul>
+UResourceBundle
+<ul>
+<li><span style='color:red'>*internal*  </span>protected static final int ALIAS</li>
+<li><span style='color:red'>*internal*  </span>protected static final int TABLE32</li>
+<li><span style='color:red'>*internal*  </span>protected boolean isTopLevel</li>
+<li><span style='color:red'>*internal*  </span>protected java.lang.String key</li>
+<li><span style='color:red'>*internal*  </span>protected long resource</li>
+<li><span style='color:red'>*internal*  </span>protected int size</li>
+</ul>
+VersionInfo
+<ul>
+<li>(draft)      public int <i>compareTo</i>(java.lang.Object)</li>
+</ul>
+</ul>
+
+
+<hr/>
+<h2>Withdrawn, Deprecated, or Obsoleted in ICU4J 4.3.2</h2>
+<p>(no API obsoleted)</p>
+
+<hr/>
+<h2>Changed in ICU4J 4.3.2 (old, new)</h2>
+
+<h3>Package com.ibm.icu.charset</h3>
+<ul>
+CharsetProviderICU
+<ul>
+<li>    <span style='color:red'>*internal*  </span>public static final java.lang.Object[] <i>getAvailableNames</i>()</br>
+<span style='color:red'>*internal*  </span>public static final java.lang.String[] <i>getAvailableNames</i>()</li>
+</ul>
+</ul>
+
+<h3>Package com.ibm.icu.text</h3>
+<ul>
+CharsetMatch
+<ul>
+<li>    (stable)     public int <i>compareTo</i>(java.lang.Object)</br>
+(draft)      public int <i>compareTo</i>(com.ibm.icu.text.CharsetMatch)</li>
+<li>    (stable)     public class <i>MessageFormat</i> extends com.ibm.icu.text.UFormat</br>
+(stable)     public class <i>MessageFormat</i> extends com.ibm.icu.text.UFormat implements com.ibm.icu.text.BaseFormat</li>
+</ul>
+RawCollationKey
+<ul>
+<li>    (stable)     public int <i>compareTo</i>(java.lang.Object)</br>
+(stable)     public int <i>compareTo</i>(com.ibm.icu.text.RawCollationKey)</li>
+<li>    (stable)     public interface <i>StringTransform</i> </br>
+(stable)     public interface <i>StringTransform</i> implements com.ibm.icu.text.Transform</li>
+<li>    (draft)      public abstract class <i>UFormat</i> extends java.text.Format</br>
+(draft)      public abstract class <i>UFormat</i> extends java.text.Format implements com.ibm.icu.text.BaseFormat</li>
+</ul>
+UTF16.StringComparator
+<ul>
+<li>    (stable)     public int <i>compare</i>(java.lang.Object, java.lang.Object)</br>
+(stable)     public int <i>compare</i>(java.lang.String, java.lang.String)</li>
+<li>    (stable)     public class <i>UnicodeSet</i> extends com.ibm.icu.text.UnicodeFilter implements com.ibm.icu.util.Freezable</br>
+(stable)     public class <i>UnicodeSet</i> extends com.ibm.icu.text.UnicodeFilter implements java.lang.Iterable, java.lang.Comparable, com.ibm.icu.util.Freezable</li>
+</ul>
+UnicodeSet
+<ul>
+<li>    (stable)     public void <i>addAll</i>(java.util.Collection)</br>
+(draft)      public com.ibm.icu.text.UnicodeSet <i>addAll</i>(int, int)</li>
+<li>    (stable)     public void <i>addAllTo</i>(java.util.Collection)</br>
+(draft)      public static java.lang.Object[] <i>addAllTo</i>(java.lang.Iterable, T[])</li>
+<li>    (stable)     public java.lang.Object <i>cloneAsThawed</i>()</br>
+(stable)     public com.ibm.icu.text.UnicodeSet <i>cloneAsThawed</i>()</li>
+<li>    (stable)     public java.lang.Object <i>freeze</i>()</br>
+(stable)     public com.ibm.icu.text.UnicodeSet <i>freeze</i>()</li>
+</ul>
+</ul>
+
+<h3>Package com.ibm.icu.util</h3>
+<ul>
+ByteArrayWrapper
+<ul>
+<li>    (stable)     public int <i>compareTo</i>(java.lang.Object)</br>
+(stable)     public int <i>compareTo</i>(com.ibm.icu.util.ByteArrayWrapper)</li>
+</ul>
+UResourceBundle
+<ul>
+<li>    <span style='color:red'>*internal*  </span>protected static void <i>addToCache</i>(java.lang.ClassLoader, java.lang.String, com.ibm.icu.util.ULocale, com.ibm.icu.util.UResourceBundle)</br>
+<span style='color:red'>*internal*  </span>protected static com.ibm.icu.util.UResourceBundle <i>addToCache</i>(java.lang.ClassLoader, java.lang.String, com.ibm.icu.util.ULocale, com.ibm.icu.util.UResourceBundle)</li>
+</ul>
+VersionInfo
+<ul>
+<li>    <span style='color:red'>*internal*  </span>public static final java.lang.String ICU_DATA_VERSION</br>
+(draft)      public static final com.ibm.icu.util.VersionInfo ICU_DATA_VERSION</li>
+</ul>
+</ul>
+
+
+<hr/>
+<h2>Promoted to stable in ICU4J 4.3.2</h2>
+<p>(no API promoted)</p>
+
+<hr/>
+<h2>Added in ICU4J 4.3.2</h2>
+
+<h3>Package com.ibm.icu.charset</h3>
+<ul>
+CharsetDecoderICU
+<ul>
+<li>(draft)      protected static final int EXT_MAX_BYTES</li>
+</ul>
+</ul>
+
+<h3>Package com.ibm.icu.impl</h3>
+<ul>
+<li>(draft)      public class <i>Assert</i></li>
+<li>(draft)      public class <i>BOCU</i></li>
+<li><span style='color:red'>*internal*  </span>public class <i>CalendarAstronomer</i></li>
+<li><span style='color:red'>*internal*  </span>public static final class <i>CalendarAstronomer.Ecliptic</i></li>
+<li><span style='color:red'>*internal*  </span>public static final class <i>CalendarAstronomer.Equatorial</i></li>
+<li><span style='color:red'>*internal*  </span>public static final class <i>CalendarAstronomer.Horizon</i></li>
+<li><span style='color:red'>*internal*  </span>public class <i>CalendarCache</i></li>
+<li><span style='color:red'>*internal*  </span>public class <i>CalendarData</i></li>
+<li>(draft)      public class <i>CalendarUtil</i></li>
+<li>(draft)      public class <i>CharTrie</i></li>
+<li>(draft)      public class <i>CharTrie.FriendAgent</i></li>
+<li>(draft)      public class <i>CharacterIteratorWrapper</i></li>
+<li>(draft)      public final class <i>DateNumberFormat</i></li>
+<li>(draft)      public final class <i>Differ</i></li>
+<li>(draft)      public class <i>Grego</i></li>
+<li>(draft)      public final class <i>ICUBinary</i></li>
+<li>(draft)      public static interface <i>ICUBinary.Authenticate</i></li>
+<li>(draft)      public interface <i>ICUCache</i></li>
+<li>(draft)      public class <i>ICUConfig</i></li>
+<li>(draft)      public final class <i>ICUData</i></li>
+<li>(draft)      public final class <i>ICUDataVersion</i></li>
+<li>(draft)      public final class <i>ICUDebug</i></li>
+<li>(draft)      public class <i>ICULocaleService</i></li>
+<li>(draft)      public static class <i>ICULocaleService.ICUResourceBundleFactory</i></li>
+<li>(draft)      public static class <i>ICULocaleService.LocaleKey</i></li>
+<li>(draft)      public static abstract class <i>ICULocaleService.LocaleKeyFactory</i></li>
+<li>(draft)      public static class <i>ICULocaleService.SimpleLocaleKeyFactory</i></li>
+<li>(draft)      public class <i>ICULogger</i></li>
+<li>(draft)      public abstract class <i>ICUNotifier</i></li>
+<li>(draft)      public class <i>ICURWLock</i></li>
+<li>(draft)      public static final class <i>ICURWLock.Stats</i></li>
+<li>(draft)      public class <i>ICUResourceBundle</i></li>
+<li>(draft)      public final class <i>ICUResourceBundleReader</i></li>
+<li>(draft)      public class <i>ICUService</i></li>
+<li>(draft)      public static interface <i>ICUService.Factory</i></li>
+<li>(draft)      public static class <i>ICUService.Key</i></li>
+<li>(draft)      public static interface <i>ICUService.ServiceListener</i></li>
+<li>(draft)      public static class <i>ICUService.SimpleFactory</i></li>
+<li>(draft)      public class <i>IllegalIcuArgumentException</i></li>
+<li><span style='color:red'>*internal*  </span>public class <i>ImplicitCEGenerator</i></li>
+<li>(draft)      public class <i>IntTrie</i></li>
+<li>(draft)      public class <i>IntTrieBuilder</i></li>
+<li>(draft)      public class <i>InvalidFormatException</i></li>
+<li>(draft)      public class <i>IterableComparator</i></li>
+<li>(draft)      public class <i>JavaTimeZone</i></li>
+<li>(draft)      public class <i>LocaleUtility</i></li>
+<li>(draft)      public class <i>MultiComparator</i></li>
+<li>(draft)      public final class <i>NormalizerImpl</i></li>
+<li>(draft)      public class <i>OlsonTimeZone</i></li>
+<li>(draft)      public class <i>PVecToTrieCompactHandler</i></li>
+<li>(draft)      public class <i>PatternTokenizer</i></li>
+<li>(draft)      public class <i>PluralRulesLoader</i></li>
+<li>(draft)      public class <i>PropsVectors</i></li>
+<li>(draft)      public static interface <i>PropsVectors.CompactHandler</i></li>
+<li>(draft)      public final class <i>Punycode</i></li>
+<li>(draft)      public class <i>RelativeDateFormat</i></li>
+<li>(draft)      public class <i>RelativeDateFormat.URelativeString</i></li>
+<li>(draft)      public class <i>ReplaceableUCharacterIterator</i></li>
+<li>(draft)      public class <i>ResourceBundleWrapper</i></li>
+<li>(draft)      public class <i>Row</i></li>
+<li>(draft)      public static class <i>Row.R2</i></li>
+<li>(draft)      public static class <i>Row.R3</i></li>
+<li>(draft)      public static class <i>Row.R4</i></li>
+<li>(draft)      public static class <i>Row.R5</i></li>
+<li>(draft)      public class <i>RuleCharacterIterator</i></li>
+<li>(draft)      public class <i>SimpleCache</i></li>
+<li>(draft)      public class <i>SortedSetRelation</i></li>
+<li>(draft)      public final class <i>StringPrepDataReader</i></li>
+<li>(draft)      public final class <i>StringUCharacterIterator</i></li>
+<li>(draft)      public class <i>TextTrieMap</i></li>
+<li>(draft)      public static interface <i>TextTrieMap.ResultHandler</i></li>
+<li>(draft)      public class <i>TimeZoneAdapter</i></li>
+<li>(draft)      public abstract class <i>Trie</i></li>
+<li>(draft)      public static interface <i>Trie.DataManipulate</i></li>
+<li>(draft)      public class <i>TrieBuilder</i></li>
+<li>(draft)      public static interface <i>TrieBuilder.DataManipulate</i></li>
+<li>(draft)      public class <i>TrieIterator</i></li>
+<li>(draft)      public final class <i>UBiDiProps</i></li>
+<li>(draft)      public final class <i>UCaseProps</i></li>
+<li>(draft)      public static interface <i>UCaseProps.ContextIterator</i></li>
+<li>(draft)      public final class <i>UCharArrayIterator</i></li>
+<li>(draft)      public class <i>UCharacterIteratorWrapper</i></li>
+<li>(draft)      public final class <i>UCharacterName</i></li>
+<li>(draft)      public interface <i>UCharacterNameChoice</i></li>
+<li>(draft)      public final class <i>UCharacterProperty</i></li>
+<li>(draft)      public final class <i>UCharacterUtility</i></li>
+<li>(draft)      public final class <i>UPropertyAliases</i></li>
+<li>(draft)      public abstract class <i>URLHandler</i></li>
+<li>(draft)      public static interface <i>URLHandler.URLVisitor</i></li>
+<li><span style='color:red'>*internal*  </span>public final class <i>USerializedSet</i></li>
+<li>(draft)      public class <i>UnicodeRegex</i></li>
+<li>(draft)      public final class <i>Utility</i></li>
+<li>(draft)      public class <i>UtilityExtensions</i></li>
+<li>(draft)      public final class <i>ZoneMeta</i></li>
+<li>(draft)      public class <i>ZoneStringFormat</i></li>
+<li>(draft)      public static class <i>ZoneStringFormat.ZoneStringInfo</i></li>
+</ul>
+
+<h3>Package com.ibm.icu.lang</h3>
+<ul>
+UProperty
+<ul>
+<li><span style='color:red'>*internal*  </span>public static final int UNDEFINED</li>
+</ul>
+</ul>
+
+<h3>Package com.ibm.icu.text</h3>
+<ul>
+<li>(draft)      public interface <i>BaseFormat</i></li>
+<li>(draft)      public interface <i>Formatter</i></li>
+<li>(draft)      public interface <i>Parser</i></li>
+<li>(draft)      public interface <i>RbnfLenientScanner</i></li>
+<li>(draft)      public interface <i>RbnfLenientScannerProvider</i></li>
+<li>(draft)      public class <i>RbnfScannerProviderImpl</i></li>
+<li>(draft)      public interface <i>Transform</i></li>
+<li>(draft)      public static final class <i>UnicodeSet.ComparisonStyle</i></li>
+Collator
+<ul>
+<li><span style='color:red'>*internal*  </span>public Collator <i>setStrength2</i>(int)</li>
+</ul>
+DateIntervalInfo
+<ul>
+<li>(stable)     public DateIntervalInfo <i>cloneAsThawed</i>()</li>
+<li>(stable)     public DateIntervalInfo <i>freeze</i>()</li>
+</ul>
+DateTimePatternGenerator
+<ul>
+<li>(stable)     public DateTimePatternGenerator <i>cloneAsThawed</i>()</li>
+<li>(stable)     public DateTimePatternGenerator <i>freeze</i>()</li>
+<li><span style='color:red'>*internal*  </span>public static DateTimePatternGenerator <i>getFrozenInstance</i>(ULocale)</li>
+<li><span style='color:red'>*internal*  </span>public boolean <i>skeletonsAreSimilar</i>(java.lang.String, java.lang.String)</li>
+</ul>
+IndexCharacters
+<ul>
+<li>(draft)      public <i>IndexCharacters</i>(ULocale, UnicodeSet, Collator)</li>
+</ul>
+RuleBasedNumberFormat
+<ul>
+<li>(draft)      public RbnfLenientScannerProvider <i>getLenientScannerProvider</i>()</li>
+<li>(draft)      public void <i>setLenientScannerProvider</i>(RbnfLenientScannerProvider)</li>
+</ul>
+UnicodeSet
+<ul>
+<li>(draft)      public <i>UnicodeSet</i>(int[])</li>
+<li>(stable)     public UnicodeSet <i>add</i>(java.util.Collection)</li>
+<li>(draft)      public UnicodeSet <i>addAll</i>(java.lang.String[])</li>
+<li>(draft)      public UnicodeSet <i>addAll</i>(java.util.Collection)</li>
+<li>(draft)      public java.lang.String[] <i>addAllTo</i>(java.lang.String[])</li>
+<li>(draft)      public java.util.Collection <i>addAllTo</i>(T)</li>
+<li>(draft)      public static java.util.Collection <i>addAllTo</i>(java.lang.Iterable, U)</li>
+<li><span style='color:red'>*internal*  </span>public UnicodeSet <i>addBridges</i>(UnicodeSet)</li>
+<li>(draft)      public static int <i>compare</i>(int, java.lang.String)</li>
+<li>(draft)      public static int <i>compare</i>(java.lang.Iterable, java.lang.Iterable)</li>
+<li>(draft)      public static int <i>compare</i>(java.lang.String, int)</li>
+<li>(draft)      public static int <i>compare</i>(java.util.Collection, java.util.Collection, UnicodeSet.ComparisonStyle)</li>
+<li>(draft)      public int <i>compareTo</i>(UnicodeSet)</li>
+<li>(draft)      public int <i>compareTo</i>(UnicodeSet, UnicodeSet.ComparisonStyle)</li>
+<li>(draft)      public int <i>compareTo</i>(java.lang.Iterable)</li>
+<li>(draft)      public boolean <i>containsAll</i>(java.util.Collection)</li>
+<li>(draft)      public boolean <i>containsNone</i>(java.util.Collection)</li>
+<li>(draft)      public final boolean <i>containsSome</i>(java.util.Collection)</li>
+<li><span style='color:red'>*internal*  </span>public int <i>findIn</i>(java.lang.CharSequence, int, boolean)</li>
+<li><span style='color:red'>*internal*  </span>public int <i>findLastIn</i>(java.lang.CharSequence, int, boolean)</li>
+<li><span style='color:red'>*internal*  </span>public static int <i>getSingleCodePoint</i>(java.lang.String)</li>
+<li>(draft)      public java.util.Iterator <i>iterator</i>()</li>
+<li>(draft)      public UnicodeSet <i>removeAll</i>(java.util.Collection)</li>
+<li>(draft)      public UnicodeSet <i>retainAll</i>(java.util.Collection)</li>
+<li>(draft)      public java.lang.Iterable <i>strings</i>()</li>
+<li>(draft)      public java.lang.String <i>stripFrom</i>(java.lang.CharSequence, boolean)</li>
+<li>(draft)      public static java.lang.String[] <i>toArray</i>(UnicodeSet)</li>
+</ul>
+</ul>
+
+<h3>Package com.ibm.icu.util</h3>
+<ul>
+<li>(draft)      public class <i>LocaleMatcher</i></li>
+<li><span style='color:red'>*internal*  </span>public static class <i>LocaleMatcher.LanguageMatcherData</i></li>
+<li>(draft)      public class <i>LocalePriorityList</i></li>
+<li><span style='color:red'>*internal*  </span>public static class <i>LocalePriorityList.LanguagePriorityListBuilder</i></li>
+Calendar
+<ul>
+<li>(draft)      public static final int IS_LEAP_MONTH</li>
+</ul>
+GlobalizationPreferences
+<ul>
+<li>(draft)      public GlobalizationPreferences <i>cloneAsThawed</i>()</li>
+<li>(draft)      public GlobalizationPreferences <i>freeze</i>()</li>
+</ul>
+HebrewCalendar
+<ul>
+<li>(draft)      public static final boolean <i>isLeapYear</i>(int)</li>
+<li>(draft)      public static int <i>monthsInYear</i>(int)</li>
+</ul>
+LocaleData
+<ul>
+<li>(draft)      public static VersionInfo <i>getCLDRVersion</i>()</li>
+</ul>
+TimeZone
+<ul>
+<li>(draft)      public static final int GENERIC_LOCATION</li>
+<li>(draft)      public static final int LONG_GENERIC</li>
+<li>(draft)      public static final int LONG_GMT</li>
+<li>(draft)      public static final int SHORT_COMMONLY_USED</li>
+<li>(draft)      public static final int SHORT_GENERIC</li>
+<li>(draft)      public static final int SHORT_GMT</li>
+<li>(draft)      public static ICULogger TimeZoneLogger</li>
+</ul>
+ULocale
+<ul>
+<li>(draft)      public java.lang.String <i>getDisplayLanguageWithDialect</i>()</li>
+<li>(draft)      public java.lang.String <i>getDisplayLanguageWithDialect</i>(ULocale)</li>
+<li>(draft)      public static java.lang.String <i>getDisplayLanguageWithDialect</i>(java.lang.String, ULocale)</li>
+<li>(draft)      public static java.lang.String <i>getDisplayLanguageWithDialect</i>(java.lang.String, java.lang.String)</li>
+<li>(draft)      public java.lang.String <i>getDisplayNameWithDialect</i>()</li>
+<li>(draft)      public java.lang.String <i>getDisplayNameWithDialect</i>(ULocale)</li>
+<li>(draft)      public static java.lang.String <i>getDisplayNameWithDialect</i>(java.lang.String, ULocale)</li>
+<li>(draft)      public static java.lang.String <i>getDisplayNameWithDialect</i>(java.lang.String, java.lang.String)</li>
+</ul>
+UResourceBundle
+<ul>
+<li><span style='color:red'>*internal*  </span>protected java.util.Set <i>handleKeySet</i>()</li>
+<li><span style='color:red'>*internal*  </span>protected boolean <i>isTopLevelResource</i>()</li>
+<li><span style='color:red'>*internal*  </span>public java.util.Set <i>keySet</i>()</li>
+</ul>
+VersionInfo
+<ul>
+<li><span style='color:red'>*internal*  </span>public static final java.lang.String ICU_DATA_VERSION_PATH</li>
+</ul>
+</ul>
+
+<hr/>
+<p><i><font size="-1">Contents generated by ReportAPI tool on Mon Oct 05 17:16:53 EDT 2009<br/>Copyright (C) 2009, International Business Machines Corporation, All Rights Reserved.</font></i></p>
+</body>
+</html>
diff --git a/build.properties b/build.properties
new file mode 100644
index 0000000..3baaf06
--- /dev/null
+++ b/build.properties
@@ -0,0 +1,6 @@
+#*******************************************************************************

+#* Copyright (C) 2009, International Business Machines Corporation and         *

+#* others. All Rights Reserved.                                                *

+#*******************************************************************************

+api.report.version = 432

+api.report.prev.version = 421

diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..9521482
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,1195 @@
+<!--
+*******************************************************************************
+* Copyright (C) 1997-2009, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+-->
+<project name="icu4j" default="main" basedir=".">
+    <property file="build.properties"/>
+
+    <property name="shared.dir" value="main/shared"/>
+    <import file="${shared.dir}/build/common-targets.xml"/>
+
+    <property name="icu4j.jar.file" value="icu4j.jar"/>
+    <property name="icu4jtests.jar.file" value="icu4jtests.jar"/>
+    <property name="icu4j-core.jar.file" value="icu4j-core.jar"/>
+    <property name="icu4j-collate.jar.file" value="icu4j-collate.jar"/>
+    <property name="icu4j-charsets.jar.file" value="icu4j-charsets.jar"/>
+    <property name="icu4j-localespi.jar.file" value="icu4j-localespi.jar"/>
+    <property name="icu4j-translit.jar.file" value="icu4j-translit.jar"/>
+    <property name="icu4jdocs.jar.file" value="icu4jdocs.jar"/>
+    <property name="icu4jsrc.jar.file" value="icu4jsrc.jar"/>
+    <property name="icu4jdemos.jar.file" value="icu4jdemos.jar"/>
+
+    <property name="doc.dir" value="doc"/>
+
+    <property environment="env"/>
+
+    <!-- Java version check -->
+    <condition property="is.java6.plus">
+        <or>
+            <contains string="${java.version}" substring="1.6."/>
+            <contains string="${java.version}" substring="1.7."/>
+        </or>
+    </condition>
+    <condition property="is.java5">
+        <contains string="${java.version}" substring="1.5."/>
+    </condition>
+    <fail message="The JDK version is too old or unknown.">
+        <condition>
+            <not>
+                <or>
+                    <isset property="is.java6.plus"/>
+                    <isset property="is.java5"/>
+                </or>
+             </not>
+        </condition>
+    </fail>
+
+    <!-- Build environment info -->
+    <property name="env.COMPUTERNAME" value="${env.HOSTNAME}"/>
+    <target name="info" description="Display the build environment information">
+        <echo message="----- Build Environment Information -------------------"/>
+        <echo message="Java Home:    ${java.home}"/>
+        <echo message="Java Version: ${java.version}"/>
+        <echo message="Ant Home:     ${ant.home}"/>
+        <echo message="Ant Version:  ${ant.version}"/>
+        <echo message="OS:           ${os.name}"/>
+        <echo message="OS Version:   ${os.version}"/>
+        <echo message="OS Arch:      ${os.arch}"/>
+        <echo message="Host:         ${env.COMPUTERNAME}"/>
+        <echo message="-------------------------------------------------------"/>
+    </target>
+
+    <target name="clean" description="Clean up build outputs">
+        <ant dir="${icu4j.core.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.collate.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.charset.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.localespi.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.translit.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.test-framework.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.core-tests.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.collate-tests.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.charset-tests.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.localespi-tests.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.translit-tests.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.build-tools.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.tools.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.demos.dir}" target="clean" inheritAll="false"/>
+
+        <!-- delete all .jar files in icu4j root directory -->
+        <delete>
+            <fileset dir="." includes="*.jar"/>
+        </delete>
+
+        <delete dir="${doc.dir}"/>
+        <delete dir="${out.dir}"/>
+        <delete dir="${module.dir}"/>
+    </target>
+
+    <!-- meta build targets -->
+    <target name="all" depends="info, main, tests, localespi, localespi-tests, build-tools, tools, demos, jar, docs" description="Build all primary targets"/>
+    <target name="main" depends="info, core, collate, charset, translit" description="Build ICU4J API classes"/>
+    <target name="tests" depends="info, core-tests, charset-tests, collate-tests, translit-tests" description="Build ICU4J API test classes"/>
+    <target name="releaseJar" depends="info, jar, jarDocs, jarSrc" description="Build all jar files for distribution"/>
+
+    <target name="secure" depends="icu4jJar" description="(Deprecated)Build ICU4J API and test classes for running the ICU4J test suite with Java security manager enabled"/>
+    
+    <!-- Check to see if JVM_OPTIONS enviroment variable is set. This can be use to set the heap size. -->
+    <property name="env.JVM_OPTIONS" value=""/>
+    <property name="jvm_options" value="${env.JVM_OPTIONS}"/>
+    <target name="check" description="Run the standard ICU4J test suite">
+        <antcall target="_runCheck">
+            <param name="runcheck.arg" value="-n"/>
+            <param name="runcheck.jvmarg" value="${jvm_options}"/>
+        </antcall>
+    </target>
+
+    <target name="exhaustiveCheck" description="Run the standard ICU4J test suite in exhaustive mode">
+        <antcall target="_runCheck">
+            <param name="runcheck.arg" value="-n -e10"/>
+            <param name="runcheck.jvmarg" value="${jvm_options}"/>
+        </antcall>
+    </target>
+
+    <target name="timeZoneCheck" description="Run the complete test for TimeZoneRoundTripAll">
+        <antcall target="_runCheck">
+            <param name="runcheck.arg" value="-n -e10 Core/Format/DateFormat/TimeZoneFormatTest"/>
+            <param name="runcheck.jvmarg" value="${jvm_options} -DTimeZoneRoundTripAll=true"/>
+        </antcall>
+    </target>
+
+    <target name="jdktzCheck" description="Run the standard ICU4J test suite with JDK TimeZone">
+        <antcall target="_runCheck">
+            <param name="runcheck.arg" value="-n"/>
+            <param name="runcheck.jvmarg" value="${jvm_options} -Dcom.ibm.icu.util.TimeZone.DefaultTimeZoneType=JDK"/>
+        </antcall>
+    </target>
+
+    <target name="_runCheck" depends="main, tests">
+        <echo message="JVM argument:   ${runcheck.jvmarg} -Djava.awt.headless=true"/>
+        <echo message="Test argument:   ${runcheck.arg}"/>
+
+        <java classname="com.ibm.icu.dev.test.TestAll" fork="yes" failonerror="true">
+            <arg line="${runcheck.arg}"/>
+            <jvmarg line="${runcheck.jvmarg} -Djava.awt.headless=true"/>
+            <classpath>
+                <pathelement path="${icu4j.core.jar}"/>
+                <pathelement path="${icu4j.collate.jar}"/>
+                <pathelement path="${icu4j.charset.jar}"/>
+                <pathelement path="${icu4j.translit.jar}"/>
+                <pathelement path="${icu4j.test-framework.jar}"/>
+                <pathelement path="${icu4j.core-tests.jar}"/>
+                <pathelement path="${icu4j.collate-tests.jar}"/> 
+                <pathelement path="${icu4j.charset-tests.jar}"/>
+                <pathelement path="${icu4j.translit-tests.jar}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <target name="coreCheck" depends="info, core, core-tests" description="Run only the core tests">
+        <java classname="com.ibm.icu.dev.test.TestAllCore" fork="yes" failonerror="true">
+            <arg line="-n"/>
+            <classpath>
+                <pathelement path="${icu4j.core.jar}"/>
+                <pathelement path="${icu4j.charset.jar}"/>
+                <pathelement path="${icu4j.test-framework.jar}"/>
+                <pathelement path="${icu4j.core-tests.jar}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <target name="collateCheck" depends="info, core, collate, collate-tests" description="Run the only collation tests">
+        <java classname="com.ibm.icu.dev.test.TestAllCollate" fork="yes" failonerror="true">
+            <arg line="-n"/>
+            <classpath>
+                <pathelement path="${icu4j.core.jar}"/>
+                <pathelement path="${icu4j.collate.jar}"/>
+                <pathelement path="${icu4j.test-framework.jar}"/>
+                <pathelement path="${icu4j.collate-tests.jar}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <target name="translitCheck" depends="info, core, translit, translit-tests" description="Run the ICU4J Translit test suite">
+        <java classname="com.ibm.icu.dev.test.TestAllTranslit" fork="yes" failonerror="true">
+            <arg line="-n"/>
+            <classpath>
+                <pathelement path="${icu4j.core.jar}"/>
+                <pathelement path="${icu4j.translit.jar}"/>
+                <pathelement path="${icu4j.test-framework.jar}"/>
+                <pathelement path="${icu4j.translit-tests.jar}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <target name="localespiCheck" if="is.java6.plus" depends="info" description="Run the ICU4J Locale SPI test suite">
+        <antcall target="_runLocalespiCheck"/>
+    </target>
+
+    <target name="_runLocalespiCheck" depends="localespi, localespi-tests">
+        <java classname="com.ibm.icu.dev.test.localespi.TestAll" fork="yes" failonerror="true">
+            <jvmarg line="-Djava.ext.dirs=${icu4j.core.dir}/${jar.dir}${path.separator}${icu4j.localespi.dir}/${jar.dir}${path.separator}${icu4j.collate.dir}/${jar.dir}${path.separator}${java.ext.dirs}"/>
+            <arg value="-n"/>
+            <classpath>
+                <pathelement path="${icu4j.localespi-tests.jar}"/>
+                <pathelement path="${icu4j.test-framework.jar}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <target name="secureCheck" depends="main, jar, icu4jtestsJar" description="Run the secure (applet-like) ICU4J test suite">
+        <property name="securecheck.arg" value="-n -w"/>
+        <property name="securecheck.jvmarg"
+                value="${jvm_options} -Djava.security.manager -Djava.security.policy=${shared.dir}/data/security.policy -Djava.awt.headless=true"/>
+
+        <echo message="JVM argument:   ${securecheck.jvmarg}"/>
+        <echo message="Test argument:  ${securecheck.arg}"/>
+
+        <java classname="com.ibm.icu.dev.test.TestAll" fork="yes" failonerror="true">
+            <arg line="${securecheck.arg}"/>
+            <jvmarg line="${securecheck.jvmarg}"/>
+            <classpath>
+                <pathelement path="${icu4j.jar.file}"/>
+                <pathelement path="${icu4j-charsets.jar.file}"/>
+                <pathelement path="${icu4jtests.jar.file}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <!-- jar targets -->
+    <target name="jar" depends="main, icu4jJar" description="Build ICU4J API jar files">
+        <copy file="${icu4j.core.jar}" tofile="${icu4j-core.jar.file}"/>
+        <copy file="${icu4j.collate.jar}" tofile="${icu4j-collate.jar.file}"/>
+        <copy file="${icu4j.charset.jar}" tofile="${icu4j-charsets.jar.file}"/>
+        <copy file="${icu4j.localespi.jar}" tofile="${icu4j-localespi.jar.file}" failonerror="false"/>
+        <copy file="${icu4j.translit.jar}" tofile="${icu4j-translit.jar.file}"/>
+    </target>
+
+    <target name="icu4jJar" depends="info, core, collate, translit" description="Build ICU4J all-in-one core jar">
+        <mkdir dir="${out.dir}"/>
+
+        <!-- manifest -->
+        <copy file="${icu4j.core.dir}/manifest.stub" todir="${out.dir}">
+            <filterset>
+                <filter token="SPECVERSION" value="${jar.spec.version}"/>
+                <filter token="IMPLVERSION" value="${jar.impl.version}"/>
+                <filter token="COPYRIGHT" value="${jar.copyright.info}"/>
+            </filterset>
+        </copy>
+
+        <!-- jar -->
+        <jar jarfile="${icu4j.jar.file}"
+                compress="true"
+                manifest="${out.dir}/manifest.stub">
+            <fileset dir="${icu4j.core.dir}/${bin.dir}" includes="**/*"/>
+            <fileset dir="${icu4j.collate.dir}/${bin.dir}" includes="**/*"/>
+            <fileset dir="${icu4j.translit.dir}/${bin.dir}" includes="**/*"/>
+            <fileset dir="${shared.dir}/licenses">
+                <include name="license.html"/>
+                <include name="unicode-license.txt"/>
+            </fileset>
+        </jar>
+    </target>
+
+    <target name="icu4jtestsJar" depends="info, tests" description="Build ICU4J all-in-one test jar">
+        <jar jarfile="${icu4jtests.jar.file}"
+                compress="true">
+            <fileset dir="${icu4j.test-framework.dir}/${bin.dir}" includes="**/*"/>
+            <fileset dir="${icu4j.core-tests.dir}/${bin.dir}" includes="**/*"/>
+            <fileset dir="${icu4j.collate-tests.dir}/${bin.dir}" includes="**/*"/>
+            <fileset dir="${icu4j.translit-tests.dir}/${bin.dir}" includes="**/*"/>
+            <fileset dir="${icu4j.charset-tests.dir}/${bin.dir}" includes="**/*"/>
+        </jar>
+    </target>
+
+    <target name="jarDocs" depends="docs" description="Build ICU4J API doc jar file">
+        <jar jarfile="${icu4jdocs.jar.file}" compress="true" basedir="${doc.dir}"/>
+    </target>
+
+    <target name="jarSrc" description="Build ICU4J source jar file">
+        <jar jarfile="${icu4jsrc.jar.file}" compress="true">
+            <fileset dir=".">
+                <include name="main/**/*"/>
+                <include name="demos/**/*"/>
+                <include name="tools/**/*"/>
+                <include name="*.html"/>
+                <include name="*.xml"/>
+                <exclude name="**/out/**/*"/>
+            </fileset>
+        </jar>
+    </target>
+
+    <target name="jarDemos" depends="demos" description="Build ICU4J demo jar file">
+        <copy file="${icu4j.demos.jar}" tofile="${icu4jdemos.jar.file}"/>
+    </target>
+
+    <!-- compile targets -->
+    <target name="core" description="Build core classes">
+        <ant dir="${icu4j.core.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="collate" depends="core" description="Build collation classes">
+        <ant dir="${icu4j.collate.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="charset" depends="core" description="Build charset classes">
+        <ant dir="${icu4j.charset.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="localespi" if="is.java6.plus" description="Build Locale SPI classes">
+        <antcall target="_build-localespi"/>
+    </target>
+
+    <target name="_build-localespi" depends="core, collate">
+        <ant dir="${icu4j.localespi.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="translit" depends="core" description="Build translit classes">
+        <ant dir="${icu4j.translit.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="test-framework" depends="core" description="Build test framework classes">
+        <ant dir="${icu4j.test-framework.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="core-tests" depends="core, test-framework" description="Build core tests">
+        <ant dir="${icu4j.core-tests.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="collate-tests" depends="collate, test-framework" description="Build core tests">
+        <ant dir="${icu4j.collate-tests.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="charset-tests" depends="charset, test-framework" description="Build charset tests">
+        <ant dir="${icu4j.charset-tests.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="localespi-tests" if="is.java6.plus" description="Build Locale SPI tests">
+        <antcall target="_build-localespi-tests"/>
+    </target>
+
+    <target name="_build-localespi-tests" depends="localespi, test-framework">
+        <ant dir="${icu4j.localespi-tests.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="translit-tests" depends="translit, test-framework" description="Build translit tests">
+        <ant dir="${icu4j.translit-tests.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="demos" depends="core, charset, translit" description="Build demo classes">
+        <ant dir="${icu4j.demos.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="build-tools" description="Build build-tool classes">
+        <ant dir="${icu4j.build-tools.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="tools" depends="core, core-tests" description="Build tool classes">
+        <ant dir="${icu4j.tools.dir}" inheritAll="false"/>
+    </target>
+
+    <!-- doc targets -->
+    <target name="docs" depends="info, build-tools" description="Build API documents">
+        <javadoc
+                destdir="${doc.dir}"
+                nodeprecatedlist="true"
+                windowtitle="icu4j"
+                doctitle="icu4j"
+                encoding="iso-8859-1"
+                docencoding="iso-8859-1"
+                bottom="&lt;font size=-1&gt;Copyright (c) ${current.year} IBM Corporation and others.&lt;/font&gt;"
+                additionalparam="-breakiterator -use -tagletpath ${icu4j.build-tools.jar} -taglet com.ibm.icu.dev.tool.docs.ICUTaglet"
+                link="http://java.sun.com/javase/6/docs/api/"
+                source="1.5">
+            <packageset dir="${icu4j.core.dir}/src">
+                <include name="com/ibm/icu/lang/**"/>
+                <include name="com/ibm/icu/math/**"/>
+                <include name="com/ibm/icu/text/**"/>
+                <include name="com/ibm/icu/util/**"/>
+            </packageset>
+            <packageset dir="${icu4j.collate.dir}/src">
+                <include name="com/ibm/icu/text/**"/>
+            </packageset>
+            <packageset dir="${icu4j.translit.dir}/src">
+                <include name="com/ibm/icu/text/**"/>
+            </packageset>
+            <packageset dir="${icu4j.charset.dir}/src">
+                <include name="com/ibm/icu/charset/**"/>
+            </packageset>
+        </javadoc>
+    </target>
+
+    <!-- Code coverage target -->
+    <property name="clover.out.dir" value="${out.dir}/clover"/>
+    <property name="clover.jar" location="${env.CLOVER_DIR}/clover.jar"/>
+    <taskdef resource="cloverlib.xml" classpath="${clover.jar}" onerror="ignore"/>
+
+    <target name="codeCoverage" depends="clean" description="Generate code coverage report with clover">
+        <!-- Set up clover -->
+        <mkdir dir="${clover.out.dir}"/>
+        <clover-setup initstring="${clover.out.dir}/clover.db">
+            <files>
+                <exclude name="**/dev/**/*.java"/>
+            </files>
+            <methodContext name="API" regexp="(.* )?public .*"/>
+        </clover-setup>
+
+        <!-- Build components with clover instrumentation -->
+        <ant dir="${icu4j.core.dir}" inheritAll="false" inheritRefs="true">
+            <property name="build.compiler" value="${build.compiler}"/>
+        </ant>
+        <ant dir="${icu4j.collate.dir}" inheritAll="false" inheritRefs="true">
+            <property name="build.compiler" value="${build.compiler}"/>
+        </ant>
+        <ant dir="${icu4j.charset.dir}" inheritAll="false" inheritRefs="true">
+            <property name="build.compiler" value="${build.compiler}"/>
+        </ant>
+        <ant dir="${icu4j.translit.dir}" inheritAll="false" inheritRefs="true">
+            <property name="build.compiler" value="${build.compiler}"/>
+        </ant>
+        <ant dir="${icu4j.test-framework.dir}" inheritAll="false" inheritRefs="true">
+            <property name="build.compiler" value="${build.compiler}"/>
+        </ant>
+        <ant dir="${icu4j.core-tests.dir}" inheritAll="false" inheritRefs="true">
+            <property name="build.compiler" value="${build.compiler}"/>
+        </ant>
+        <ant dir="${icu4j.collate-tests.dir}" inheritAll="false" inheritRefs="true">
+            <property name="build.compiler" value="${build.compiler}"/>
+        </ant>
+        <ant dir="${icu4j.charset-tests.dir}" inheritAll="false" inheritRefs="true">
+            <property name="build.compiler" value="${build.compiler}"/>
+        </ant>
+        <ant dir="${icu4j.translit-tests.dir}" inheritAll="false" inheritRefs="true">
+            <property name="build.compiler" value="${build.compiler}"/>
+        </ant>
+
+        <!-- Run the test suites -->
+        <java classname="com.ibm.icu.dev.test.TestAll" fork="yes" failonerror="true">
+            <arg value="-n"/>
+            <classpath>
+                <pathelement path="${icu4j.core.jar}"/>
+                <pathelement path="${icu4j.collate.jar}"/>
+                <pathelement path="${icu4j.charset.jar}"/>
+                <pathelement path="${icu4j.translit.jar}"/>
+                <pathelement path="${icu4j.test-framework.jar}"/>
+                <pathelement path="${icu4j.core-tests.jar}"/>
+                <pathelement path="${icu4j.collate-tests.jar}"/>
+                <pathelement path="${icu4j.charset-tests.jar}"/>
+                <pathelement path="${icu4j.translit-tests.jar}"/>
+                <pathelement path="${clover.jar}"/>
+            </classpath>
+        </java>
+
+        <!-- Generate HTML coverage report -->
+        <clover-html-report outdir="${clover.out.dir}/html" title="ICU4J Code Coverage"/>
+    </target>
+
+    <!-- Release management targets -->
+    <target name="checktags" depends="info, build-tools" description="Check API tags before release">
+        <javadoc source="1.5">
+            <packageset dir="${icu4j.core.dir}/src">
+                <include name="com/ibm/icu/lang/**"/>
+                <include name="com/ibm/icu/math/**"/>
+                <include name="com/ibm/icu/text/**"/>
+                <include name="com/ibm/icu/util/**"/>
+            </packageset>
+            <packageset dir="${icu4j.collate.dir}/src">
+                <include name="com/ibm/icu/**"/>
+            </packageset>
+            <packageset dir="${icu4j.charset.dir}/src">
+                <include name="com/ibm/icu/charset/**"/>
+            </packageset>
+            <doclet name="com.ibm.icu.dev.tool.docs.CheckTags" path="${icu4j.build-tools.jar}"/>
+        </javadoc>
+    </target>
+
+    <target name="gatherapi" depends="info, build-tools" description="Run API database generator tool">
+        <mkdir dir="${out.dir}"/>
+        <javadoc source="1.5">
+            <packageset dir="${icu4j.core.dir}/src">
+                <include name="com/ibm/icu/lang/**"/>
+                <include name="com/ibm/icu/math/**"/>
+                <include name="com/ibm/icu/text/**"/>
+                <include name="com/ibm/icu/util/**"/>
+            </packageset>
+            <packageset dir="${icu4j.collate.dir}/src">
+                <include name="com/ibm/icu/**"/>
+            </packageset>
+            <packageset dir="${icu4j.charset.dir}/src">
+                <include name="com/ibm/icu/charset/**"/>
+            </packageset>
+            <packageset dir="${icu4j.translit.dir}/src">
+                <include name="com/ibm/icu/**"/>
+            </packageset>
+            <doclet name="com.ibm.icu.dev.tool.docs.GatherAPIData" path="${icu4j.build-tools.jar}">
+                <param name="-name" value="ICU4J ${icu4j.impl.version}"/>
+                <param name="-output" value="${out.dir}/icu4j${api.report.version}.api"/>
+                <param name="-internal"/>
+                <param name="-gzip"/>
+            </doclet>
+        </javadoc>
+    </target>
+
+    <target name="apireport" depends="info, gatherapi" description="Run API report generator tool">
+        <java classname="com.ibm.icu.dev.tool.docs.ReportAPI"
+                classpath="${icu4j.build-tools.jar}"
+                failonerror="true">
+            <arg value="-old:" />
+            <arg value="${icu4j.build-tools.dir}/icu4j${api.report.prev.version}.api.gz" />
+            <arg value="-new:" />
+            <arg value="${out.dir}/icu4j${api.report.version}.api.gz" />
+            <arg value="-html" />
+            <arg value="-internal" />
+            <arg value="-out:" />
+            <arg value="${out.dir}/icu4j_compare_${api.report.prev.version}_${api.report.version}.html" />
+        </java>
+    </target>
+
+    <target name="swatDeprecated" depends="build-tools" description="Convert @deprecated @draft tags to @provisional">
+        <antcall target="_runSwatDeprecated">
+            <param name="swat.deprecated.opt" value="-dep"/>
+        </antcall>
+    </target>
+
+    <target name="swatProvisional" depends="build-tools" description="Convert @provisional tags to @deprecated @draft">
+        <antcall target="_runSwatDeprecated">
+            <param name="swat.deprecated.opt" value="-prov"/>
+        </antcall>
+    </target>
+
+    <target name="_runSwatDeprecated">
+        <java classname="com.ibm.icu.dev.tool.docs.SwatDeprecated"
+                classpath="${icu4j.build-tools.jar}"
+                failonerror="true">
+            <arg value="${swat.deprecated.opt}"/>
+            <arg value="-src"/>
+            <arg value="${icu4j.core.dir}/src"/>
+            <arg value="-dst"/>
+            <arg value="${icu4j.core.dir}/src"/>
+            <arg value="-overwrite"/>
+            <arg value="-verbose"/>
+        </java>
+        <java classname="com.ibm.icu.dev.tool.docs.SwatDeprecated"
+                classpath="${icu4j.build-tools.jar}"
+                failonerror="true">
+            <arg value="${swat.deprecated.opt}"/>
+            <arg value="-src"/>
+            <arg value="${icu4j.charset.dir}/src"/>
+            <arg value="-dst"/>
+            <arg value="${icu4j.charset.dir}/src"/>
+            <arg value="-overwrite"/>
+            <arg value="-verbose"/>
+        </java>
+    </target>
+
+
+    <!-- Special packaging targets -->
+    <target name="translitIMEJar" depends="info" description="Build transliterator IME 'icutransime.jar' jar file">
+        <property name="translit.ime.out.dir" value="${out.dir}/translit_ime"/>
+ 
+        <mkdir dir="${translit.ime.out.dir}/bin"/>
+        <javac destdir="${translit.ime.out.dir}/bin"
+                source="${javac.source}"
+                target="${javac.target}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.translit.dir}/src"/>
+            <src path="${icu4j.tools.dir}/src"/>
+            <include name="com/ibm/icu/dev/tool/ime/translit/*.java"/>
+        </javac>
+
+        <copy file="${icu4j.tools.dir}/src/com/ibm/icu/dev/tool/ime/translit/Transliterator.properties"
+                todir="${translit.ime.out.dir}/bin/com/ibm/icu/dev/tool/ime/translit"/>
+
+        <mkdir dir="${translit.ime.out.dir}/lib"/>
+        <jar jarfile="${translit.ime.out.dir}/lib/icutransime.jar"
+                compress="true"
+                basedir="${translit.ime.out.dir}/bin"
+                includes="com/ibm/icu/dev/tool/ime/translit/**/*"
+                manifest="${icu4j.tools.dir}/src/com/ibm/icu/dev/tool/ime/translit/manifest.stub">
+            <metainf dir="${icu4j.tools.dir}/src/com/ibm/icu/dev/tool/ime/translit" includes="services/*" />
+        </jar>
+    </target>
+
+    <target name="indicIMEJar" depends="info" description="Build indic IME 'icuindicime.jar' jar file">
+        <property name="indic.ime.out.dir" value="${out.dir}/indic_ime"/>
+ 
+        <mkdir dir="${indic.ime.out.dir}/bin"/>
+        <javac destdir="${indic.ime.out.dir}/bin"
+                source="${javac.source}"
+                target="${javac.target}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.tools.dir}/src"/>
+            <include name="com/ibm/icu/dev/tool/ime/indic/*.java"/>
+        </javac>
+
+        <copy file="${icu4j.tools.dir}/src/com/ibm/icu/dev/tool/ime/indic/DisplayNames.properties"
+                todir="${indic.ime.out.dir}/bin/com/ibm/icu/dev/tool/ime/indic"/>
+
+        <mkdir dir="${indic.ime.out.dir}/lib"/>
+        <jar jarfile="${indic.ime.out.dir}/lib/icuindicime.jar"
+                compress="true"
+                basedir="${indic.ime.out.dir}/bin"
+                includes="com/ibm/icu/dev/tool/ime/indic/**/*"
+                manifest="${icu4j.tools.dir}/src/com/ibm/icu/dev/tool/ime/indic/manifest.stub">
+            <metainf dir="${icu4j.tools.dir}/src/com/ibm/icu/dev/tool/ime/indic" includes="services/*" />
+        </jar>
+    </target>
+
+    <target name="cldrUtil" depends="info" description="Build Utilities for CLDR">
+        <property name="cldr.util.out.dir" value="${out.dir}/cldr_util"/>
+        <mkdir dir="${cldr.util.out.dir}/bin"/>
+
+        <javac destdir="${cldr.util.out.dir}/bin"
+                source="${javac.source}"
+                target="${javac.target}"
+                debug="on" deprecation="off">
+
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.translit.dir}/src"/>
+            <src path="${icu4j.core-tests.dir}/src"/> <!-- still needed? -->
+            <src path="${icu4j.translit-tests.dir}/src"/>
+            <src path="${icu4j.test-framework.dir}/src"/>
+            <src path="${icu4j.tools.dir}/src"/>
+
+            <include name="com/ibm/icu/dev/test/TestFmwk.java" />
+            <include name="com/ibm/icu/dev/test/util/*.java" />
+            <include name="com/ibm/icu/dev/tool/UOption.java" />
+        </javac>
+
+        <mkdir dir="${cldr.util.out.dir}/lib"/>
+        <jar jarfile="${cldr.util.out.dir}/lib/utilities.jar"
+                compress="true"
+                basedir="${cldr.util.out.dir}/bin">
+            <include name="com/ibm/icu/dev/test/util/*.class"/>
+            <include name="com/ibm/icu/dev/test/TestFmwk*.class"/>
+            <include name="com/ibm/icu/dev/test/AbstractTest*.class"/>
+            <include name="com/ibm/icu/dev/test/TestLog*.class"/>
+            <include name="com/ibm/icu/dev/tool/UOption*.class"/>
+        </jar>
+    </target>
+
+    <target name="xliff" description="Build xliff converter tool">
+        <property name="xliff.out.dir" value="${out.dir}/xliff"/>
+
+        <mkdir dir="${xliff.out.dir}/bin"/>
+        <javac destdir="${xliff.out.dir}/bin"
+                source="1.3"
+                target="1.3"
+                debug="on" deprecation="off">
+            <src path="${icu4j.tools.dir}/src"/>
+            <include name="com/ibm/icu/dev/tool/localeconverter/CalculateCRC32.java"/>
+            <include name="com/ibm/icu/dev/tool/localeconverter/XLIFF2ICUConverter.java"/>
+            <include name="com/ibm/icu/dev/tool/UOption.java"/>
+       </javac>
+
+        <mkdir dir="${xliff.out.dir}/lib"/>
+
+        <jar jarfile="${xliff.out.dir}/lib/xliff-src.jar"
+                compress="true"
+                basedir="${icu4j.tools.dir}/src">
+            <include name="com/ibm/icu/dev/tool/localeconverter/CalculateCRC32.java"/>
+            <include name="com/ibm/icu/dev/tool/localeconverter/XLIFF2ICUConverter.java"/>
+            <include name="com/ibm/icu/dev/tool/UOption.java"/>
+        </jar>
+
+        <jar jarfile="${xliff.out.dir}/lib/xliff.jar"
+                compress="true"
+                basedir="${xliff.out.dir}/bin"
+                manifest="${icu4j.tools.dir}/src/com/ibm/icu/dev/tool/localeconverter/manifest.stub"/>
+    </target>
+
+
+    <!-- ICU4J modularization targets -->
+    <property name="module.dir" value="${out.dir}/module"/>
+    <property name="module.bin.dir" value="${module.dir}/bin"/>
+    <property name="module.tests.dir" value="${module.dir}/tests"/>
+    <property name="module.jar.dir" value="${module.dir}/lib"/>
+    <property name="module.jar" value="${module.jar.dir}/icu4j-module.jar"/>
+
+    <target name="moduleJar" description="Create a ICU4J module jar file">
+        <mkdir dir="${module.jar.dir}"/>
+        <jar jarfile="${module.jar}"
+                compress="true"
+                basedir="${module.bin.dir}">
+            <manifest>
+                <attribute name="Built-By" value="${corp}" />
+                <section name="com/ibm/icu">
+                    <attribute name="Specification-Title" value="ICU4J Modularized Build" />
+                    <attribute name="Specification-Version" value="${jar.spec.version}" />
+                    <attribute name="Specification-Vendor" value="ICU" />
+                    <attribute name="Implementation-Title" value=" ICU for Java Module" />
+                    <attribute name="Implementation-Version" value="${jar.impl.version}" />
+                    <attribute name="Implementation-Vendor" value="${corp}" />
+                    <attribute name="Implementation-Vendor-Id" value="com.ibm" />
+                    <attribute name="Copyright-Info" value="${jar.copyright.info}" />
+                    <attribute name="Sealed" value="false" />
+                </section>
+            </manifest>
+        </jar>
+        <copy file="${module.jar}" tofile="icu4j.jar"/>
+    </target>
+
+    <target name="moduleCheck" description="Run tests for a ICU4J module jar">
+        <java classname="com.ibm.icu.dev.test.TestAll" fork="yes" failonerror="true">
+            <arg value="-nothrow"/>
+            <arg value="-nodata"/>
+            <classpath>
+                <pathelement path="${module.jar}"/>
+                <pathelement location="${module.tests.dir}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <patternset id="common.test.sources">
+        <include name="com/ibm/icu/dev/test/TestFmwk.java"/>
+        <include name="com/ibm/icu/dev/test/TestLog.java"/>
+        <include name="com/ibm/icu/dev/test/TestUtil.java"/>
+        <include name="com/ibm/icu/dev/test/UTF16Util.java"/>
+        <include name="com/ibm/icu/dev/test/TestAll.java"/>
+        <include name="com/ibm/icu/dev/test/TestAllCore.java"/>
+    </patternset>
+
+    <!-- Break Iterator -->
+    <target name="breakIterator" depends="_copyFullPropsData" description="Modular build of break iterator services">
+        <mkdir dir="${module.bin.dir}"/>
+        <javac srcdir="${icu4j.core.dir}/src"
+                destdir="${module.bin.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                debug="on" deprecation="off">
+            <include name="com/ibm/icu/impl/UCharacterName.java"/>
+            <include name="com/ibm/icu/impl/data/*Break*.java"/>
+            <include name="com/ibm/icu/lang/**/*.java"/>
+            <include name="com/ibm/icu/text/*BreakIterator*.java"/>
+            <include name="com/ibm/icu/text/UnicodeSetIterator.java"/>
+        </javac>
+    </target>
+
+    <target name="breakIteratorTests" depends="breakIterator" description="Modular build of break iterator test suite">
+        <mkdir dir="${module.tests.dir}"/>
+        <javac destdir="${module.tests.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                classpath="${module.bin.dir}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.test-framework.dir}/src"/>
+            <src path="${icu4j.core-tests.dir}/src"/>
+
+            <patternset refid="common.test.sources"/>
+            <include name="com/ibm/icu/dev/test/rbbi/**/*.java"/>
+        </javac>
+
+        <copy file="${icu4j.core-tests.dir}/src/com/ibm/icu/dev/test/rbbi/rbbitst.txt"
+                todir="${module.tests.dir}/com/ibm/icu/dev/test/rbbi"/>
+    </target>
+
+    <!-- Calendar -->
+    <target name="calendar" description="Modular build of calendar services">
+        <mkdir dir="${module.bin.dir}"/>
+        <javac srcdir="${icu4j.core.dir}/src"
+                destdir="${module.bin.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                debug="on" deprecation="off">
+            <include name="com/ibm/icu/impl/data/*Holiday*.java"/>
+            <include name="com/ibm/icu/lang/UCharacter.java"/>
+            <include name="com/ibm/icu/text/UnicodeSetIterator.java"/>
+            <include name="com/ibm/icu/text/NumberFormatServiceShim.java"/>
+            <include name="com/ibm/icu/util/*Calendar*.java"/>
+        </javac>
+
+        <!-- Calendar does not require Collation data, BreakIterator data -->
+        <unjar src="${icu4j.data.jar}" dest="${module.bin.dir}">
+            <patternset>
+                <include name="**/pnames.icu" />
+                <include name="**/ucase.icu" />
+                <include name="**/unorm.icu" />
+                <include name="**/uprops.icu" />
+                <include name="**/unames.icu" />
+                <include name="**/*.res" />
+                <exclude name="**/coll/*.res" />
+                <exclude name="**/translit/*.res" />
+            </patternset>
+        </unjar>
+    </target>
+
+    <target name="calendarTests" depends="calendar" description="Modular build of calendar test suite">
+        <mkdir dir="${module.tests.dir}"/>
+        <javac destdir="${module.tests.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                classpath="${module.bin.dir}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.test-framework.dir}/src"/>
+            <src path="${icu4j.core-tests.dir}/src"/>
+
+            <patternset refid="common.test.sources"/>
+            <include name="com/ibm/icu/dev/test/calendar/**/*.java" />
+        </javac>
+
+        <unjar src="${icu4j.testdata.jar}" dest="${module.tests.dir}">
+            <patternset>
+                <include name="**/calendar.res"/>
+            </patternset>
+        </unjar>
+    </target>
+
+    <!-- Collator -->
+    <!-- this module will soon be obsolete, use the collate jar -->
+    <target name="collator" description="Modular build of collator services">
+        <mkdir dir="${module.bin.dir}"/>
+        <javac  destdir="${module.bin.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.collate.dir}/src"/>
+
+            <include name="com/ibm/icu/impl/data/*Break*.java"/>
+            <include name="com/ibm/icu/text/*BreakIterator*.java"/>
+            <include name="com/ibm/icu/text/*Collation*.java"/>
+            <include name="com/ibm/icu/text/*Collator*.java"/>
+            <include name="com/ibm/icu/text/Normalizer.java"/>
+            <include name="com/ibm/icu/text/Replaceable.java"/>
+            <include name="com/ibm/icu/text/ReplaceableString.java"/>
+            <include name="com/ibm/icu/text/UnicodeFilter.java"/>
+            <include name="com/ibm/icu/text/UnicodeSetIterator.java"/>
+            <include name="com/ibm/icu/text/UTF16.java"/>
+        </javac>
+
+        <unjar src="${icu4j.data.jar}" dest="${module.bin.dir}">
+            <patternset>
+                <include name="**/*.icu"/>
+                <include name="**/coll/*.res"/>
+                <include name="**/*.brk"/>
+                <include name="**/icudt${icu4j.data.version}b/res_index.res"/>
+            </patternset>
+        </unjar>
+    </target>
+
+    <target name="collatorTests" depends="collator" description="Modular build of collator test suite">
+        <mkdir dir="${module.tests.dir}"/>
+        <javac destdir="${module.tests.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                classpath="${module.bin.dir}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.test-framework.dir}/src"/>
+            <src path="${icu4j.collate-tests.dir}/src"/>
+
+            <patternset refid="common.test.sources"/>
+            <include name="com/ibm/icu/dev/test/TestAllCollate.java"/>
+            <include name="com/ibm/icu/dev/test/collator/**/*.java"/>
+            <include name="java,com/ibm/icu/dev/test/search/**/*.java"/>
+            <exclude name="com/ibm/icu/dev/test/collator/RandomCollator.java"/>
+            <exclude name="com/ibm/icu/dev/test/collator/IndexCharactersTest.java"/>
+        </javac>
+
+        <unjar src="${icu4j.testdata.jar}" dest="${module.tests.dir}">
+            <patternset>
+                <include name="**/DataDrivenCollationTest.res"/>
+            </patternset>
+        </unjar>
+        <copy todir="${module.tests.dir}">
+            <fileset dir="${icu4j.collate-tests.dir}/src">
+                <include name="com/ibm/icu/dev/data/riwords.txt"/>
+                <include name="com/ibm/icu/dev/data/CollationTest_*.txt"/>
+            </fileset>
+        </copy>
+    </target>
+
+    <!-- Compression -->
+    <target name="compression" description="Modular build of compression services">
+        <mkdir dir="${module.bin.dir}"/>
+        <javac srcdir="${icu4j.core.dir}/src"
+                destdir="${module.bin.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                debug="on" deprecation="off">
+            <include name="com/ibm/icu/text/SCSU.java"/>
+            <include name="com/ibm/icu/text/UnicodeCompressor.java"/>
+            <include name="com/ibm/icu/text/UnicodeDecompressor.java"/>
+        </javac>
+    </target>
+
+    <target name="compressionTests" depends="compression" description="Modular build of compression test suite">
+        <mkdir dir="${module.tests.dir}"/>
+        <javac destdir="${module.tests.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                classpath="${module.bin.dir}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.test-framework.dir}/src"/>
+            <src path="${icu4j.core-tests.dir}/src"/>
+
+            <patternset refid="common.test.sources"/>
+            <include name="com/ibm/icu/dev/test/compression/**/*.java"/>
+        </javac>
+    </target>
+
+    <!-- Format -->
+    <target name="format" description="Modular build of format services">
+        <mkdir dir="${module.bin.dir}"/>
+        <javac srcdir="${icu4j.core.dir}/src"
+                destdir="${module.bin.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                debug="on" deprecation="off">
+            <include name="com/ibm/icu/lang/UCharacter.java"/>
+            <include name="com/ibm/icu/text/*Collator*.java"/>
+            <include name="com/ibm/icu/text/*Format*.java"/>
+            <include name="com/ibm/icu/text/UnicodeSetIterator.java"/>
+            <include name="com/ibm/icu/util/CalendarServiceShim.java"/>
+        </javac>
+
+        <!-- Format does not require BreakIterator data -->
+        <unjar src="${icu4j.data.jar}" dest="${module.bin.dir}">
+            <patternset>
+                <include name="**/*.icu"/>
+                <include name="**/*.res"/>
+                <exclude name="**/translit/*.res"/>
+            </patternset>
+        </unjar>
+    </target>
+
+    <target name="formatTests" depends="format" description="Modular build of format test suite">
+        <mkdir dir="${module.tests.dir}"/>
+        <javac destdir="${module.tests.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                classpath="${module.bin.dir}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.test-framework.dir}/src"/>
+            <src path="${icu4j.core-tests.dir}/src"/>
+
+            <patternset refid="common.test.sources"/>
+            <include name="com/ibm/icu/dev/test/format/**/*.java"/>
+            <exclude name="com/ibm/icu/dev/test/format/GlobalizationPreferencesTest.java"/>
+        </javac>
+
+        <unjar src="${icu4j.testdata.jar}" dest="${module.tests.dir}">
+            <patternset>
+                <include name="**/format.res"/>
+            </patternset>
+        </unjar>
+
+        <copy file="${icu4j.core-tests.dir}/src/com/ibm/icu/dev/test/format/NumberFormatTestCases.txt"
+                todir="${module.tests.dir}/com/ibm/icu/dev/test/format"/>
+
+    </target>
+
+    <!-- Normalizer -->
+    <target name="normalizer" description="Modular build of normalizer services">
+        <mkdir dir="${module.bin.dir}"/>
+        <javac srcdir="${icu4j.core.dir}/src"
+                destdir="${module.bin.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                debug="on" deprecation="off">
+            <include name="com/ibm/icu/lang/**/*"/>
+            <include name="com/ibm/icu/text/CanonicalIterator.java"/>
+            <include name="com/ibm/icu/text/Normalizer.java"/>
+            <include name="com/ibm/icu/text/Replaceable.java"/>
+            <include name="com/ibm/icu/text/ReplaceableString.java"/>
+            <include name="com/ibm/icu/text/UCharacterIterator.java"/>
+            <include name="com/ibm/icu/text/UForwardCharacterIterator.java"/>
+            <include name="com/ibm/icu/text/UnicodeFilter.java"/>
+            <include name="com/ibm/icu/text/UnicodeSetIterator.java"/>
+            <include name="com/ibm/icu/text/UTF16.java"/>
+        </javac>
+
+        <unjar src="${icu4j.data.jar}" dest="${module.bin.dir}">
+            <patternset>
+                <include name="**/ucase.icu"/>
+                <include name="**/unorm.icu"/>
+                <include name="**/uprops.icu"/>
+                <include name="**/pnames.icu"/>
+                <include name="**/unames.icu"/>
+            </patternset>
+        </unjar>
+    </target>
+
+    <target name="normalizerTests" depends="normalizer" description="Modular build of normalizer test suite">
+        <mkdir dir="${module.tests.dir}"/>
+        <javac destdir="${module.tests.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                classpath="${module.bin.dir}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.test-framework.dir}/src"/>
+            <src path="${icu4j.core-tests.dir}/src"/>
+
+            <patternset refid="common.test.sources"/>
+            <include name="com/ibm/icu/dev/test/normalizer/**/*.java"/>
+            <exclude name="com/ibm/icu/dev/test/normalizer/TestDeprecatedNormalizerAPI.java"/>
+        </javac>
+
+        <copy todir="${module.tests.dir}">
+            <fileset dir="${icu4j.core-tests.dir}/src">
+                <include name="com/ibm/icu/dev/data/unicode/*.txt"/>
+                <exclude name="com/ibm/icu/dev/data/unicode/ucdterms.txt"/>
+            </fileset>
+        </copy>
+    </target>
+
+    <!-- Character Properties -->
+    <target name="_copyBasicPropsData">
+        <mkdir dir="${module.bin.dir}"/>
+        <unjar src="${icu4j.data.jar}" dest="${module.bin.dir}">
+            <patternset>
+                <include name="**/unorm.icu"/>
+                <include name="**/uprops.icu"/>
+                <include name="**/ubidi.icu"/>
+                <include name="**/ucase.icu"/>
+                <include name="**/pnames.icu"/>
+                <include name="**/unames.icu"/>
+            </patternset>
+        </unjar>
+    </target>
+
+    <target name="_copyFullPropsData">
+        <mkdir dir="${module.bin.dir}"/>
+        <unjar src="${icu4j.data.jar}" dest="${module.bin.dir}">
+            <patternset>
+                <include name="**/unorm.icu"/>
+                <include name="**/uprops.icu"/>
+                <include name="**/ubidi.icu"/>
+                <include name="**/ucase.icu"/>
+                <include name="**/unames.icu"/>
+                <include name="**/pnames.icu"/>
+                <include name="**/*.res"/>
+                <include name="**/*.brk"/>
+                <include name="**/*.ctd"/>
+                <exclude name="**/coll/*.res"/>
+                <exclude name="**/translit/*.res"/>
+                <exclude name="**/rbnf/*.res"/>
+            </patternset>
+        </unjar>
+    </target>
+
+    <target name="_propertiesClasses">
+        <mkdir dir="${module.bin.dir}"/>
+        <javac srcdir="${icu4j.core.dir}/src"
+                destdir="${module.bin.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                debug="on" deprecation="off">
+            <include name="com/ibm/icu/impl/data/*Break*.java"/>
+            <include name="com/ibm/icu/lang/**/*"/>
+            <include name="com/ibm/icu/text/*BreakDictionary*.java"/>
+            <include name="com/ibm/icu/text/*BreakIterator*.java"/>
+            <include name="com/ibm/icu/text/UnicodeSetIterator.java"/>
+        </javac>
+    </target>
+
+    <target name="_propertiesTests">
+        <mkdir dir="${module.tests.dir}"/>
+        <javac destdir="${module.tests.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                classpath="${module.bin.dir}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.test-framework.dir}/src"/>
+            <src path="${icu4j.core-tests.dir}/src"/>
+
+            <patternset refid="common.test.sources"/>
+            <include name="com/ibm/icu/dev/test/lang/**/*.java"/>
+            <exclude name="com/ibm/icu/dev/test/lang/TestUScriptRun.java"/>
+        </javac>
+
+        <copy todir="${module.tests.dir}">
+            <fileset dir="${icu4j.core-tests.dir}/src">
+                <include name="com/ibm/icu/dev/data/unicode/SpecialCasing.txt"/>
+                <include name="com/ibm/icu/dev/data/unicode/UnicodeData.txt"/>
+            </fileset>
+        </copy>
+    </target>
+
+    <target name="propertiesBasic" depends="_propertiesClasses, _copyBasicPropsData" description="Modular build of basic character properties"/>
+
+    <target name="propertiesBasicTests" depends="propertiesBasic, _propertiesTests" description="Modular build of basic character properties test suite"/>
+
+    <target name="propertiesFull" depends="_propertiesClasses, _copyFullPropsData" description="Modular build of full character properties"/>
+
+    <target name="propertiesFullTests" depends="propertiesFull, _propertiesTests" description="Modular build of full character properties test suite"/>
+
+    <!-- Transliterator -->
+    <!-- this module will soon be obsolete, use the translit jar -->
+    <target name="transliterator" depends="_propertiesClasses" description="Modular build of transliterator services">
+        <mkdir dir="${module.bin.dir}"/>
+        <javac  destdir="${module.bin.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.translit.dir}/src"/>
+
+            <include name="com/ibm/icu/impl/*Iterator*.java"/>
+            <include name="com/ibm/icu/impl/*Property*.java"/>
+            <include name="com/ibm/icu/impl/data/ResourceReader.java"/>
+            <include name="com/ibm/icu/impl/UtilityExtensions.java"/>
+            <include name="com/ibm/icu/text/*Transliterator*.java"/>
+            <include name="com/ibm/icu/text/UnicodeSetIterator.java"/>
+            <include name="com/ibm/icu/text/BreakIteratorFactory.java"/>
+        </javac>
+
+        <unjar src="${icu4j.data.jar}" dest="${module.bin.dir}">
+            <patternset>
+                <include name="**/unorm.icu"/>
+                <include name="**/uprops.icu"/>
+                <include name="**/ubidi.icu"/>
+                <include name="**/ucase.icu"/>
+                <include name="**/unames.icu"/>
+                <include name="**/pnames.icu"/>
+                <include name="**/*.brk"/>
+                <include name="**/*.ctd"/>
+                <include name="**/brkitr/*.res"/>
+                <include name="**/translit/*.res"/>
+            </patternset>
+        </unjar>
+    </target>
+
+    <target name="transliteratorTests" depends="transliterator" description="Modular build of transliterator test suite">
+        <mkdir dir="${module.tests.dir}"/>
+        <javac destdir="${module.tests.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                classpath="${module.bin.dir}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.test-framework.dir}/src"/>
+            <src path="${icu4j.translit-tests.dir}/src"/>
+
+            <patternset refid="common.test.sources"/>
+            <include name="com/ibm/icu/dev/test/TestAllTranslit.java"/>
+            <include name="com/ibm/icu/dev/test/translit/**/*.java"/>
+            <exclude name="com/ibm/icu/dev/test/translit/UnicodeFilterLogic*.java"/>
+        </javac>
+
+        <copy file="${icu4j.translit-tests.dir}/src/com/ibm/icu/dev/test/translit/langtagRegex.txt"
+                todir="${module.tests.dir}/com/ibm/icu/dev/test/translit"/>
+    </target>
+
+    <!-- StringPrep -->
+    <target name="stringPrep" depends="normalizer" description="Modular build of stringprep services">
+        <mkdir dir="${module.bin.dir}"/>
+        <javac srcdir="${icu4j.core.dir}/src"
+                destdir="${module.bin.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                debug="on" deprecation="off">
+            <include name="com/ibm/icu/impl/*StringPrep*.java"/>
+            <include name="com/ibm/icu/text/*IDNA*.java"/>
+            <include name="com/ibm/icu/text/*StringPrep*.java"/>
+        </javac>
+
+        <unjar src="${icu4j.data.jar}" dest="${module.bin.dir}">
+            <patternset>
+                <include name="**/*.spp"/>
+                <include name="**/ubidi.icu"/>
+                <include name="**/ucase.icu"/>
+                <include name="**/unorm.icu"/>
+                <include name="**/uprops.icu"/>
+                <include name="**/pnames.icu"/>
+                <include name="**/unames.icu"/>
+            </patternset>
+        </unjar>
+    </target>
+
+    <target name="stringPrepTests" depends="stringPrep" description="Modular build of stringprep test suite">
+        <mkdir dir="${module.tests.dir}"/>
+        <javac destdir="${module.tests.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                classpath="${module.bin.dir}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.test-framework.dir}/src"/>
+            <src path="${icu4j.core-tests.dir}/src"/>
+
+            <patternset refid="common.test.sources"/>
+            <include name="com/ibm/icu/dev/test/stringprep/**/*.java"/>
+        </javac>
+
+        <unjar src="${icu4j.testdata.jar}" dest="${module.tests.dir}">
+            <patternset>
+                <include name="**/*.spp"/>
+                <include name="**/idna_rules.res"/>
+            </patternset>
+        </unjar>
+
+        <copy file="${icu4j.core-tests.dir}/src/com/ibm/icu/dev/data/IDNATestInput.txt"
+                todir="${module.tests.dir}/com/ibm/icu/dev/data"/>
+    </target>
+
+</project>
diff --git a/demos/.classpath b/demos/.classpath
new file mode 100644
index 0000000..c13960c
--- /dev/null
+++ b/demos/.classpath
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/icu4j-charset"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/icu4j-core"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/icu4j-translit"/>
+	<classpathentry kind="output" path="out/bin"/>
+</classpath>
diff --git a/demos/.project b/demos/.project
new file mode 100644
index 0000000..69e0c1b
--- /dev/null
+++ b/demos/.project
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>icu4j-demos</name>
+	<comment></comment>
+	<projects>
+		<project>icu4j-charset</project>
+		<project>icu4j-core</project>
+		<project>icu4j-shared</project>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/demos/.settings/org.eclipse.jdt.core.prefs b/demos/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..1c6961a
--- /dev/null
+++ b/demos/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,330 @@
+#Fri Aug 28 16:05:27 EDT 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=ignore
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=ignore
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=120
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=120
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=space
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
diff --git a/demos/.settings/org.eclipse.jdt.ui.prefs b/demos/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..abf9d87
--- /dev/null
+++ b/demos/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,6 @@
+#Tue Jun 09 16:57:19 EDT 2009
+eclipse.preferences.version=1
+formatter_profile=_ICU4J Standard
+formatter_settings_version=11
+org.eclipse.jdt.ui.javadoc=false
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\r\n * @return the ${bare_field_name}\r\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\r\n * @param ${param} the ${bare_field_name} to set\r\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\r\n *******************************************************************************\r\n * Copyright (C) ${year}, International Business Machines Corporation and         *\r\n * others. All Rights Reserved.                                                *\r\n *******************************************************************************\r\n */</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\r\n * @author ${user}\r\n *\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\r\n * \r\n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\r\n * ${see_to_overridden}\r\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\r\n * ${tags}\r\n * ${see_to_target}\r\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\r\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\r\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\r\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\r\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\r\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\r\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\r\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
diff --git a/demos/build.properties b/demos/build.properties
new file mode 100644
index 0000000..f374881
--- /dev/null
+++ b/demos/build.properties
@@ -0,0 +1,5 @@
+#*******************************************************************************
+#* Copyright (C) 2009, International Business Machines Corporation and         *
+#* others. All Rights Reserved.                                                *
+#*******************************************************************************
+shared.dir = ../main/shared
diff --git a/demos/build.xml b/demos/build.xml
new file mode 100644
index 0000000..3187e79
--- /dev/null
+++ b/demos/build.xml
@@ -0,0 +1,29 @@
+<!--
+*******************************************************************************
+* Copyright (C) 2009, International Business Machines Corporation and         *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+-->
+<project name="demos" default="build" basedir=".">
+    <property file="build-local.properties"/>
+    <property file="build.properties"/>
+    <import file="${shared.dir}/build/common-targets.xml"/>
+
+    <path id="javac.classpathref">
+        <path refid="javac.classpathref.${ant.project.name}"/>
+    </path>
+    <property name="jar.file" value="${icu4j.demos.jar}"/>
+
+    <target name="build" depends="compile, copy, jar" description="Build the project"/>
+
+    <target name="build-all" depends="@build-all" description="Build the project including all dependencies"/>
+
+    <target name="clean" depends="@clean" description="Clean up the build outputs"/>
+
+    <target name="compile" depends="@compile" description="Compile java source files"/>
+
+    <target name="copy" depends="@copy" description="Copy non-java runtime files to the project's binary directory"/>
+
+    <target name="jar" depends="compile, copy, @jar" description="Create the project's jar file"/>
+
+</project>
\ No newline at end of file
diff --git a/demos/demos-build.launch b/demos/demos-build.launch
new file mode 100644
index 0000000..cead29e
--- /dev/null
+++ b/demos/demos-build.launch
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.ant.AntLaunchConfigurationType">
+<booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/icu4j-demos/build.xml"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="icu4j-demos"/>
+<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
+<mapAttribute key="org.eclipse.ui.externaltools.ATTR_ANT_PROPERTIES">
+<mapEntry key="eclipse.pdebuild.templates" value="/D:/eclipse-SDK-3.4.2-win32/eclipse/plugins/org.eclipse.pde.build_3.4.1.R34x_v20081217/templates/"/>
+<mapEntry key="eclipse.pdebuild.home" value="/D:/eclipse-SDK-3.4.2-win32/eclipse/plugins/org.eclipse.pde.build_3.4.1.R34x_v20081217/./"/>
+<mapEntry key="eclipse.pdebuild.scripts" value="/D:/eclipse-SDK-3.4.2-win32/eclipse/plugins/org.eclipse.pde.build_3.4.1.R34x_v20081217/scripts/"/>
+</mapAttribute>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_ANT_PROPERTY_FILES" value="${workspace_loc:/icu4j-shared/build/locations-eclipse.properties},"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/icu4j-demos/build.xml}"/>
+<stringAttribute key="process_factory_id" value="org.eclipse.ant.ui.remoteAntProcessFactory"/>
+</launchConfiguration>
diff --git a/demos/manifest.stub b/demos/manifest.stub
new file mode 100644
index 0000000..5180077
--- /dev/null
+++ b/demos/manifest.stub
@@ -0,0 +1,13 @@
+Manifest-Version: 1.0

+Main-Class: com.ibm.icu.dev.demo.Launcher

+Class-Path: icu4j.jar

+

+Name: com/ibm/icu/dev/demo

+Specification-Title: ICU for Java Demo

+Specification-Version: @SPECVERSION@

+Specification-Vendor: ICU

+Implementation-Title: ICU for Java Demo

+Implementation-Version: @IMPLVERSION@

+Implementation-Vendor: IBM Corporation

+Implementation-Vendor-Id: com.ibm

+Copyright-Info: @COPYRIGHT@

diff --git a/demos/src/com/ibm/icu/dev/demo/Launcher.java b/demos/src/com/ibm/icu/dev/demo/Launcher.java
new file mode 100644
index 0000000..2d88044
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/Launcher.java
@@ -0,0 +1,192 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2007, International Business Machines Corporation and         *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo;
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Color;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Label;
+import java.awt.Panel;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import com.ibm.icu.dev.demo.impl.DemoApplet;
+import com.ibm.icu.dev.demo.impl.DemoUtility;
+import com.ibm.icu.util.VersionInfo;
+
+
+/**
+ * @author srl
+ * Application to provide a panel of demos to launch
+ */
+public class Launcher extends DemoApplet {
+    private static final long serialVersionUID = -8054963875776183877L;
+    
+    /**
+     * base package of all demos
+     */
+    public static final String demoBase = "com.ibm.icu.dev.demo";
+    /**
+     * list of classes, relative to the demoBase. all must have a static void main(String[])
+     */
+    public static final String demoList[] = { 
+        "calendar.CalendarApp",
+        "charsetdet.DetectingViewer",
+        "holiday.HolidayCalendarDemo",
+//        "number.CurrencyDemo", -- console
+//        "rbbi.DBBIDemo",
+//        "rbbi.RBBIDemo",
+//        "rbbi.TextBoundDemo",
+        "rbnf.RbnfDemo",
+//        "timescale.PivotDemo",  -- console
+        "translit.Demo",
+    };
+
+    public class LauncherFrame extends Frame implements ActionListener {
+        private static final long serialVersionUID = -8054963875776183878L;
+        
+        public Button buttonList[] = new Button[demoList.length]; // one button for each demo
+        public Label statusLabel;
+        private DemoApplet applet;
+        
+        LauncherFrame(DemoApplet applet) {
+            init();
+            this.applet = applet;
+        }
+        
+        public void init() {
+            // close down when close is clicked.
+            // TODO: this should be factored..
+            addWindowListener(
+                    new WindowAdapter() {
+                        public void windowClosing(WindowEvent e) {
+                            setVisible(false);
+                            dispose();
+
+                            if (applet != null) {
+                                applet.demoClosed();
+                            } else System.exit(0);
+                        }
+                    } );
+
+            setBackground(DemoUtility.bgColor);
+            setLayout(new BorderLayout());
+
+            Panel topPanel = new Panel();
+            topPanel.setLayout(new GridLayout(5,3));
+
+            for(int i=0;i<buttonList.length;i++) {
+                String demo = demoList[i];
+                Button b = new Button(demo);
+                b.addActionListener(this);
+                buttonList[i]=b;
+                topPanel.add(b);
+            }
+            add(BorderLayout.CENTER,topPanel);
+            statusLabel = new Label("");
+            statusLabel.setAlignment(Label.LEFT);
+            String javaVersion = "";
+            try { 
+                javaVersion = "* Java: "+System.getProperty("java.version");
+            } catch (Throwable t) {
+                javaVersion = "";
+            }
+            add(BorderLayout.NORTH, new Label(
+                   "ICU Demos * ICU version "+VersionInfo.ICU_VERSION +
+                   " * http://icu-project.org "+javaVersion));
+            add(BorderLayout.SOUTH,statusLabel);
+            // set up an initial status.
+            showStatus(buttonList.length+" demos ready. ");
+        }
+        
+        /**
+         * Change the 'status' field, and set it to black
+         * @param status
+         */
+        void showStatus(String status) {
+            statusLabel.setText(status);
+            statusLabel.setForeground(Color.BLACK);
+            statusLabel.setBackground(Color.WHITE);
+//            statusLabel.setFont(Font.PLAIN);
+            doLayout();
+        }
+        void showStatus(String demo, String status) {
+            showStatus(demo+": "+status);
+        }
+        void showFailure(String status) {
+            statusLabel.setText(status);
+            statusLabel.setBackground(Color.GRAY);
+            statusLabel.setForeground(Color.RED);
+//            statusLabel.setFont(Font.BOLD);
+            doLayout();
+        }
+        void showFailure(String demo, String status) {
+            showFailure(demo+": "+status);
+        }
+
+        
+        public void actionPerformed(ActionEvent e) {
+            // find button
+            for(int i=0;i<buttonList.length;i++) {
+                if(e.getSource() == buttonList[i]) {
+                    String demoShort = demoList[i];
+                    String demo = demoBase+'.'+demoShort;
+                    showStatus(demoShort, "launching");
+                    try {
+                        Class c = Class.forName(demo);
+                        String args[] = new String[0];
+                        Class params[] = new Class[1];
+                        params[0] = args.getClass();
+                        Method m = c.getMethod("main", params );
+                        Object[] argList = { args };
+                        m.invoke(null, argList);
+                        showStatus(demoShort, "launched.");
+                    } catch (ClassNotFoundException e1) {
+                        showFailure(demoShort,e1.toString());
+                        e1.printStackTrace();
+                    } catch (SecurityException se) {
+                        showFailure(demoShort,se.toString());
+                        se.printStackTrace();
+                    } catch (NoSuchMethodException nsme) {
+                        showFailure(demoShort,nsme.toString());
+                        nsme.printStackTrace();
+                    } catch (IllegalArgumentException iae) {
+                        showFailure(demoShort,iae.toString());
+                        iae.printStackTrace();
+                    } catch (IllegalAccessException iae) {
+                        showFailure(demoShort,iae.toString());
+                        iae.printStackTrace();
+                    } catch (InvocationTargetException ite) {
+                        showFailure(demoShort,ite.toString());
+                        ite.printStackTrace();
+                    }
+                    repaint();
+                }
+            }
+        }
+
+    }
+    
+    /* This creates a Frame for the demo applet. */
+    protected Frame createDemoFrame(DemoApplet applet) {
+        return new LauncherFrame(applet);
+    }
+
+    /**
+     * The main function which defines the behavior of the Demo
+     * applet when an applet is started.
+     */
+    public static void main(String[] args) {
+        new Launcher().showDemo();
+    }
+}
diff --git a/demos/src/com/ibm/icu/dev/demo/calendar/CalendarApp.java b/demos/src/com/ibm/icu/dev/demo/calendar/CalendarApp.java
new file mode 100644
index 0000000..5b7d76c
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/calendar/CalendarApp.java
@@ -0,0 +1,37 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2007, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+
+package com.ibm.icu.dev.demo.calendar;
+
+import java.awt.Frame;
+
+import com.ibm.icu.dev.demo.impl.*;
+
+/**
+ * CalendarApp demonstrates how Calendar works.
+ */
+public class CalendarApp extends DemoApplet
+{
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = -4270137898405840825L;
+
+    /**
+     * 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/demos/src/com/ibm/icu/dev/demo/calendar/CalendarCalc.java b/demos/src/com/ibm/icu/dev/demo/calendar/CalendarCalc.java
new file mode 100644
index 0000000..ff9a75b
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/calendar/CalendarCalc.java
@@ -0,0 +1,595 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2008, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+
+package com.ibm.icu.dev.demo.calendar;
+
+import java.awt.Button;
+import java.awt.Checkbox;
+import java.awt.CheckboxGroup;
+import java.awt.Choice;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Label;
+import java.awt.Panel;
+import java.awt.TextField;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowEvent;
+import java.text.ParsePosition;
+import java.util.Date;
+import java.util.Locale;
+
+import javax.swing.JTextField;
+
+import com.ibm.icu.dev.demo.impl.DemoApplet;
+import com.ibm.icu.dev.demo.impl.DemoUtility;
+import com.ibm.icu.text.DateFormat;
+import com.ibm.icu.text.SimpleDateFormat;
+import com.ibm.icu.util.BuddhistCalendar;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.GregorianCalendar;
+import com.ibm.icu.util.HebrewCalendar;
+import com.ibm.icu.util.IslamicCalendar;
+import com.ibm.icu.util.JapaneseCalendar;
+import com.ibm.icu.util.TimeZone;
+
+/**
+ * CalendarCalc demonstrates how Date/Time formatter works.
+ */
+public class CalendarCalc extends DemoApplet
+{
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = 4540103433916539296L;
+
+    /**
+     * 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
+{
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = 8901485296258761846L;
+
+    static final Locale[] locales = DemoUtility.getG7Locales();
+
+    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 isUp) {
+        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, isUp ? 1 : -1);
+                } else {
+                    c.roll(field, isUp);
+                }
+
+                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;
+
+
+    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();
+            }
+            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/demos/src/com/ibm/icu/dev/demo/calendar/CalendarFrame.java b/demos/src/com/ibm/icu/dev/demo/calendar/CalendarFrame.java
new file mode 100644
index 0000000..fd76ec7
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/calendar/CalendarFrame.java
@@ -0,0 +1,442 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2007, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+
+package com.ibm.icu.dev.demo.calendar;
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Choice;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Label;
+import java.awt.Panel;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.Date;
+import java.util.Locale;
+
+import com.ibm.icu.dev.demo.impl.DemoApplet;
+import com.ibm.icu.dev.demo.impl.DemoUtility;
+import com.ibm.icu.text.DateFormat;
+import com.ibm.icu.util.BuddhistCalendar;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.GregorianCalendar;
+import com.ibm.icu.util.HebrewCalendar;
+import com.ibm.icu.util.IslamicCalendar;
+import com.ibm.icu.util.JapaneseCalendar;
+import com.ibm.icu.util.SimpleTimeZone;
+
+/**
+ * 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
+{
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = -4289697663503820619L;
+
+    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.icu.text.SimpleDateFormat) {
+                            com.ibm.icu.text.SimpleDateFormat f1 = (com.ibm.icu.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 {
+        /**
+         * For serialization
+         */
+        private static final long serialVersionUID = 5004484960341875722L;
+        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/demos/src/com/ibm/icu/dev/demo/calendar/CalendarPanel.java b/demos/src/com/ibm/icu/dev/demo/calendar/CalendarPanel.java
new file mode 100644
index 0000000..8ea94d3
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/calendar/CalendarPanel.java
@@ -0,0 +1,365 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2007, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+
+package com.ibm.icu.dev.demo.calendar;
+
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.util.Date;
+import java.util.Locale;
+
+import com.ibm.icu.dev.demo.impl.DemoUtility;
+import com.ibm.icu.text.DateFormatSymbols;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.SimpleTimeZone;
+
+class CalendarPanel extends Canvas {
+
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = 625400018027387141L;
+
+    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();
+        if(endOfMonth==null){
+         //do nothing
+        }
+        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/demos/src/com/ibm/icu/dev/demo/calendar/package.html b/demos/src/com/ibm/icu/dev/demo/calendar/package.html
new file mode 100644
index 0000000..c1bb105
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/calendar/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--  Copyright (C) 2000-2004, International Business Machines Corporation and
+  others. All Rights Reserved.
+
+-->
+</head>
+<body bgcolor="white">
+Calendar demo applications including date/time arithmetic.
+</body>
+</html>
\ No newline at end of file
diff --git a/demos/src/com/ibm/icu/dev/demo/charsetdet/DetectingViewer.java b/demos/src/com/ibm/icu/dev/demo/charsetdet/DetectingViewer.java
new file mode 100644
index 0000000..de4ef06
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/charsetdet/DetectingViewer.java
@@ -0,0 +1,404 @@
+/*
+ **************************************************************************
+ * Copyright (C) 2005-2007, International Business Machines Corporation   *
+ * and others. All Rights Reserved.                                       *
+ **************************************************************************
+ *
+ */
+
+package com.ibm.icu.dev.demo.charsetdet;
+
+import java.awt.event.*;
+import java.awt.*;
+import java.io.*;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.security.AccessControlException;
+
+import javax.swing.*;
+
+import com.ibm.icu.charset.CharsetICU;
+import com.ibm.icu.dev.demo.impl.DemoApplet;
+import com.ibm.icu.text.CharsetDetector;
+import com.ibm.icu.text.CharsetMatch;
+
+/**
+ * This simple application demonstrates how to use the CharsetDetector API. It
+ * opens a file or web page, detects the encoding, and then displays it using that
+ * encoding.
+ */
+public class DetectingViewer extends JFrame implements ActionListener
+{
+    
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = -2307065724464747775L;
+    private JTextPane text;
+    private JFileChooser fileChooser;
+    
+    /**
+     * @throws java.awt.HeadlessException
+     */
+    public DetectingViewer()
+    {
+        super();
+        DemoApplet.demoFrameOpened();
+        
+        try {
+            fileChooser = new JFileChooser();
+        } catch (AccessControlException ace) {
+            System.err.println("no file chooser - access control exception. Continuing without file browsing. "+ace.toString());
+            fileChooser = null; //
+        }
+        
+//        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        setSize(800, 800);
+
+        setJMenuBar(makeMenus());
+        text = new JTextPane();
+        text.setContentType("text/plain");
+        text.setText("");
+        text.setSize(800, 800);
+        
+        Font font = new Font("Arial Unicode MS", Font.PLAIN, 24);
+        text.setFont(font);
+        
+        JScrollPane scrollPane = new JScrollPane(text);
+        
+        getContentPane().add(scrollPane);
+        setVisible(true);
+
+        addWindowListener(
+                new WindowAdapter() {
+                    public void windowClosing(WindowEvent e) {
+//                        setVisible(false);
+//                        dispose();
+
+                          doQuit();
+                    }
+                } );
+
+    
+    }
+
+    public void actionPerformed(ActionEvent event)
+    {
+        String cmd = event.getActionCommand();
+        
+        if (cmd.equals("New...")) {
+           doNew();
+        } else if (cmd.equals("Open File...")) {
+           doOpenFile();
+        } else if (cmd.equals("Open URL...")) {
+            doOpenURL();
+        } else if (cmd.equals("Quit")) {
+           doQuit();
+        }
+    }
+
+    public static void main(String[] args)
+    {
+        new DetectingViewer();
+    }
+    
+    private void errorDialog(String title, String msg)
+    {
+        JOptionPane.showMessageDialog(this, msg, title, JOptionPane.ERROR_MESSAGE);
+    }
+    
+    private BufferedInputStream openFile(File file)
+    {
+        FileInputStream fileStream = null;
+        
+        try {
+            fileStream = new FileInputStream(file);
+        } catch (Exception e) {
+            errorDialog("Error Opening File", e.getMessage());
+            return null;
+        }
+        
+        return new BufferedInputStream(fileStream);
+    }
+    
+//    private void openFile(String directory, String filename)
+//    {
+//        openFile(new File(directory, filename));
+//    }
+    
+    
+    private BufferedInputStream openURL(String url)
+    {
+        InputStream s = null;
+
+        try {
+            URL aURL = new URL(url);
+            s = aURL.openStream();
+        } catch (Exception e) {
+            errorDialog("Error Opening URL", e.getMessage());
+            return null;
+        }
+        
+        return new BufferedInputStream(s);
+    }
+    
+    private String encodingName(CharsetMatch match)
+    {
+        return match.getName() + " (" + match.getLanguage() + ")";
+    }
+    
+    private void setMatchMenu(CharsetMatch[] matches)
+    {
+        JMenu menu = getJMenuBar().getMenu(1);
+        JMenuItem menuItem;
+        
+        menu.removeAll();
+        
+        for (int i = 0; i < matches.length; i += 1) {
+            CharsetMatch match = matches[i];
+            
+            menuItem = new JMenuItem(encodingName(match) + " " + match.getConfidence());
+            
+            menu.add(menuItem);
+        }
+    }
+    
+    private byte[] scriptTag = {(byte) 's', (byte) 'c', (byte) 'r', (byte) 'i', (byte) 'p', (byte) 't'};
+    private byte[] styleTag  = {(byte) 's', (byte) 't', (byte) 'y', (byte) 'l', (byte) 'e'};
+    private static int BUFFER_SIZE = 100000;
+    
+    private boolean openTag(byte[] buffer, int offset, int length, byte[] tag)
+    {
+        int tagLen = tag.length;
+        int bufRem = length - offset;
+        int b;
+        
+        for (b = 0; b < tagLen && b < bufRem; b += 1) {
+            if (buffer[b + offset] != tag[b]) {
+                return false;
+            }
+        }
+        
+        return b == tagLen;
+    }
+    
+    private boolean closedTag(byte[] buffer, int offset, int length, byte[] tag)
+    {
+        if (buffer[offset] != (byte) '/') {
+            return false;
+        }
+        
+        return openTag(buffer, offset + 1, length, tag);
+    }
+    
+    private byte[] filter(InputStream in)
+    {
+        byte[] buffer = new byte[BUFFER_SIZE];
+        int bytesRemaining = BUFFER_SIZE;
+        int bufLen = 0;
+        
+        in.mark(BUFFER_SIZE);
+        
+        try {
+            while (bytesRemaining > 0) {
+                int bytesRead = in.read(buffer, bufLen, bytesRemaining);
+                
+                if (bytesRead <= 0) {
+                    break;
+                }
+                
+                bufLen += bytesRead;
+                bytesRemaining -= bytesRead;
+            }
+        } catch (Exception e) {
+            // TODO: error handling?
+            return null;
+        }
+        
+        boolean inTag = false;
+        boolean skip  = false;
+        int out = 0;
+        
+        for (int i = 0; i < bufLen; i += 1) {
+            byte b = buffer[i];
+            
+            if (b == (byte) '<') {
+                inTag = true;
+                
+                if (openTag(buffer, i + 1, bufLen, scriptTag) ||
+                    openTag(buffer, i + 1, bufLen, styleTag)) {
+                    skip = true;
+                } else if (closedTag(buffer, i + 1, bufLen, scriptTag) ||
+                           closedTag(buffer, i + 1, bufLen, styleTag)) {
+                    skip = false;
+                }
+            } else if (b == (byte) '>') {
+                inTag = false;
+            } else if (! (inTag || skip)) {
+                buffer[out++] = b;
+            }
+        }
+
+        byte[] filtered = new byte[out];
+        
+        System.arraycopy(buffer, 0, filtered, 0, out);
+        return filtered;
+    }
+    
+    private CharsetMatch[] detect(byte[] bytes)
+    {
+        CharsetDetector det = new CharsetDetector();
+        
+        det.setText(bytes);
+        
+        return det.detectAll();
+    }
+    
+    private CharsetMatch[] detect(BufferedInputStream inputStream)
+    {
+        CharsetDetector det    = new CharsetDetector();
+        
+        try {
+            det.setText(inputStream);
+            
+            return det.detectAll();
+        } catch (Exception e) {
+            // TODO: error message?
+            return null;
+        }
+    }
+    
+    private void show(InputStream inputStream, CharsetMatch[] matches, String title)
+    {
+        InputStreamReader isr;
+        char[] buffer = new char[1024];
+        int bytesRead = 0;
+        
+        if (matches == null || matches.length == 0) {
+            errorDialog("Match Error", "No matches!");
+            return;
+        }
+        
+        try {
+            StringBuffer sb = new StringBuffer();
+            String encoding = matches[0].getName();
+            
+            inputStream.reset();
+            
+            if (encoding.startsWith("UTF-32")) {
+                byte[] bytes = new byte[1024];
+                int offset = 0;
+                int chBytes = 0;
+                Charset utf32 = CharsetICU.forNameICU(encoding);
+                
+                while ((bytesRead = inputStream.read(bytes, offset, 1024)) >= 0) {
+                    offset  = bytesRead % 4;
+                    chBytes = bytesRead - offset;
+                    
+                    sb.append(utf32.decode(ByteBuffer.wrap(bytes)).toString());
+                    
+                    if (offset != 0) {
+                        for (int i = 0; i < offset; i += 1) {
+                            bytes[i] = bytes[chBytes + i];
+                        }
+                    }
+                }
+            } else {
+                isr = new InputStreamReader(inputStream, encoding);
+                
+                while ((bytesRead = isr.read(buffer, 0, 1024)) >= 0) {
+                    sb.append(buffer, 0, bytesRead);
+                }
+                
+                isr.close();
+            }
+            
+            this.setTitle(title + " - " + encodingName(matches[0]));
+            
+            setMatchMenu(matches);
+            text.setText(sb.toString());
+        } catch (IOException e) {
+            errorDialog("IO Error", e.getMessage());
+        } catch (Exception e) {
+            errorDialog("Internal Error", e.getMessage());
+        }
+    }
+    
+    private void doNew()
+    {
+        // open a new window...
+    }
+    
+    private void doOpenFile()
+    {
+        int retVal = fileChooser.showOpenDialog(this);
+        
+        if (retVal == JFileChooser.APPROVE_OPTION) {
+            File file = fileChooser.getSelectedFile();
+            BufferedInputStream inputStream = openFile(file);
+            
+            if (inputStream != null) {
+                CharsetMatch[] matches = detect(inputStream);
+                
+                show(inputStream, matches, file.getName());                
+            }
+        }
+    }
+    
+    private void doOpenURL()
+    {
+        String url = (String) JOptionPane.showInputDialog(this, "URL to open:", "Open URL", JOptionPane.PLAIN_MESSAGE,
+                null, null, null);
+        
+        if (url != null && url.length() > 0) {
+            BufferedInputStream inputStream = openURL(url);
+            
+            if (inputStream != null) {
+                byte[] filtered = filter(inputStream);
+                CharsetMatch[] matches = detect(filtered);
+                
+                show(inputStream, matches, url);                
+            }
+        }
+}
+    
+    private void doQuit()
+    {
+        DemoApplet.demoFrameClosed();
+        this.setVisible(false);
+        this.dispose();
+    }
+    
+    private JMenuBar makeMenus()
+    {
+        JMenu menu = new JMenu("File");
+        JMenuItem mi;
+        
+        mi = new JMenuItem("Open File...");
+        mi.setAccelerator((KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK)));
+        mi.addActionListener(this);
+        menu.add(mi);
+        if(fileChooser == null) {
+            mi.setEnabled(false); // no file chooser.
+        }
+        
+        mi = new JMenuItem("Open URL...");
+        mi.setAccelerator((KeyStroke.getKeyStroke(KeyEvent.VK_U, ActionEvent.CTRL_MASK)));
+        mi.addActionListener(this);
+        menu.add(mi);
+        
+        mi = new JMenuItem("Quit");
+        mi.setAccelerator((KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK)));
+        mi.addActionListener(this);
+        menu.add(mi);
+        
+        JMenuBar mbar = new JMenuBar();
+        mbar.add(menu);
+        
+        menu = new JMenu("Detected Encodings");
+        mbar.add(menu);
+        
+        return mbar;
+    }
+}
diff --git a/demos/src/com/ibm/icu/dev/demo/holiday/HolidayBorderPanel.java b/demos/src/com/ibm/icu/dev/demo/holiday/HolidayBorderPanel.java
new file mode 100644
index 0000000..af6ce9b
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/holiday/HolidayBorderPanel.java
@@ -0,0 +1,546 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2008, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.holiday;
+
+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 {
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = 4669213306492461159L;
+    // 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
+        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;
+        }
+
+    /**
+     * 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/demos/src/com/ibm/icu/dev/demo/holiday/HolidayCalendarDemo.java b/demos/src/com/ibm/icu/dev/demo/holiday/HolidayCalendarDemo.java
new file mode 100644
index 0000000..5899b78
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/holiday/HolidayCalendarDemo.java
@@ -0,0 +1,744 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+
+package com.ibm.icu.dev.demo.holiday;
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Canvas;
+import java.awt.Choice;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Label;
+import java.awt.Panel;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.WindowEvent;
+import java.text.DateFormatSymbols;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Vector;
+
+import com.ibm.icu.dev.demo.impl.DemoApplet;
+import com.ibm.icu.dev.demo.impl.DemoTextBox;
+import com.ibm.icu.dev.demo.impl.DemoUtility;
+import com.ibm.icu.text.SimpleDateFormat;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.Holiday;
+import com.ibm.icu.util.SimpleTimeZone;
+
+/**
+ * CalendarDemo demonstrates how Calendar works.
+ */
+public class HolidayCalendarDemo extends DemoApplet 
+{
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = 4546085430817359372L;
+
+    /**
+     * 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
+    {
+        /**
+         * For serialization
+         */
+        private static final long serialVersionUID = -7023296782393042761L;
+
+        private static final boolean DEBUG = false;
+
+        //private Locale curLocale = Locale.US; // unused
+
+        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 {
+
+        /**
+         * For serialization
+         */
+        private static final long serialVersionUID = 1521099412250120821L;
+
+        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.icu.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/demos/src/com/ibm/icu/dev/demo/holiday/package.html b/demos/src/com/ibm/icu/dev/demo/holiday/package.html
new file mode 100644
index 0000000..d05e2f5
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/holiday/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--  Copyright (C) 2000-2004, International Business Machines Corporation and
+  others. All Rights Reserved.
+
+-->
+</head>
+<body bgcolor="white">
+Holiday demo application.
+</body>
+</html>
\ No newline at end of file
diff --git a/demos/src/com/ibm/icu/dev/demo/impl/AppletFrame.java b/demos/src/com/ibm/icu/dev/demo/impl/AppletFrame.java
new file mode 100644
index 0000000..1f6ad3d
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/AppletFrame.java
@@ -0,0 +1,144 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.impl;
+import java.applet.*;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * <p>A Frame that runs an Applet within itself, making it possible
+ * for an applet to run as an application.  Usage:
+ *
+ * <pre>
+ * public class MyApplet extends Applet {
+ *     public static void main(String args[]) {
+ *         MyApplet applet = new MyApplet();
+ *         new AppletFrame("My Applet Running As An App", applet, 640, 480);
+ *     }
+ *     ...
+ * }
+ * <pre>
+ *
+ * @author Alan Liu
+ */
+public class AppletFrame extends Frame implements AppletStub, AppletContext {
+
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = 818828281190757725L;
+    Applet applet;
+
+    /**
+     * Construct a Frame running the given Applet with the default size
+     * of 640 by 480.
+     * When the Frame is closed, the applet's stop() method is called,
+     * the Frame is dispose()d of, and System.exit(0) is called.
+     *
+     * @param name the Frame title
+     * @param applet the applet to be run
+     */
+    public AppletFrame(String name, Applet applet) {
+        this(name, applet, 640, 480);
+    }
+
+    /**
+     * Construct a Frame running the given Applet with the given size.
+     * When the Frame is closed, the applet's stop() method is called,
+     * the Frame is dispose()d of, and System.exit(0) is called.
+     *
+     * @param name the Frame title
+     * @param applet the applet to be run
+     * @param width width of the Frame
+     * @param height height of the Frame
+     */
+    public AppletFrame(String name, Applet applet, int width, int height) {
+        super(name);
+        this.applet = applet;
+        applet.setStub(this);
+
+        setSize(width, height);
+        add("Center", applet);
+        show();
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent e) {
+                AppletFrame.this.applet.stop();
+                dispose();
+                System.exit(0);
+            }
+        });
+
+        applet.init();
+        applet.start();
+    }
+
+    // AppletStub API
+    public void appletResize(int width, int height) {
+        setSize(width, height);
+    }
+
+    public AppletContext getAppletContext() {
+        return this;
+    }
+
+    public URL getCodeBase() {
+        return null;
+    }
+
+    public URL getDocumentBase() {
+        return null;
+    }
+    
+    public String getParameter(String name) {
+        return "PARAMETER";
+    }
+
+    public boolean isActive() {
+        return true;
+    }
+    
+    
+    // AppletContext API
+    public Applet getApplet(String name) {
+        return applet;
+    }
+
+    public Enumeration getApplets() {
+        return null;
+    }
+
+    public AudioClip getAudioClip(URL url) {
+        return null;
+    }
+
+    public Image getImage(URL url) {
+        return null;
+    }
+
+    public void showDocument(URL url) {}
+    public void showDocument(URL url, String target) {}
+
+    public void showStatus(String status) {
+        System.out.println(status);
+    }
+    
+    public void setStream(String key, InputStream stream) throws IOException {
+    }
+    
+    public InputStream getStream(String key) {
+        return null;
+    }
+    
+    public Iterator getStreamKeys() {
+        return null;
+    }
+}
diff --git a/demos/src/com/ibm/icu/dev/demo/impl/DemoApplet.java b/demos/src/com/ibm/icu/dev/demo/impl/DemoApplet.java
new file mode 100644
index 0000000..554cf9e
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/DemoApplet.java
@@ -0,0 +1,76 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2008, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+
+package com.ibm.icu.dev.demo.impl;
+
+import java.awt.*;
+import java.awt.event.*;
+
+public abstract class DemoApplet extends java.applet.Applet {
+    private static final long serialVersionUID = -8983602961925702071L;
+    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();
+    }
+
+    public static void demoFrameOpened() {
+        demoFrameCount++;
+        System.err.println("DemoFrameOpened, now at:"+demoFrameCount);
+    }
+    public static void demoFrameClosed() {
+        if (--demoFrameCount == 0) {
+            System.err.println("DemoFrameClosed, now at:"+demoFrameCount + " - quitting");
+            System.exit(0);
+        }
+        System.err.println("DemoFrameClosed, now at:"+demoFrameCount);
+    }
+}
+
diff --git a/demos/src/com/ibm/icu/dev/demo/impl/DemoTextBox.java b/demos/src/com/ibm/icu/dev/demo/impl/DemoTextBox.java
new file mode 100644
index 0000000..bdd28ad
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/DemoTextBox.java
@@ -0,0 +1,95 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2008, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.impl;
+
+
+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/demos/src/com/ibm/icu/dev/demo/impl/DemoUtility.java b/demos/src/com/ibm/icu/dev/demo/impl/DemoUtility.java
new file mode 100644
index 0000000..5c5c3f4
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/DemoUtility.java
@@ -0,0 +1,127 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2004, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.impl;
+
+import java.awt.*;
+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 =
+        "Copyright (C) IBM Corp and others. 1997 - 2002 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/demos/src/com/ibm/icu/dev/demo/impl/DumbTextComponent.java b/demos/src/com/ibm/icu/dev/demo/impl/DumbTextComponent.java
new file mode 100644
index 0000000..b854ff3
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/DumbTextComponent.java
@@ -0,0 +1,804 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2008, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.impl;
+import java.awt.*;
+import java.awt.event.*;
+import java.text.*;
+import java.awt.datatransfer.*;
+
+// LIU: Changed from final to non-final
+public class DumbTextComponent extends Canvas
+  implements KeyListener, MouseListener, MouseMotionListener, FocusListener
+{
+    
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = 8265547730738652151L;
+
+//    private transient static final String copyright =
+//      "Copyright \u00A9 1998, Mark Davis. All Rights Reserved.";
+    private transient static boolean DEBUG = false;
+
+    private String contents = "";
+    private Selection selection = new Selection();
+    private int activeStart = -1;
+    private boolean editable = true;
+
+    private transient Selection tempSelection = new Selection();
+    private transient boolean focus;
+    private transient BreakIterator lineBreaker = BreakIterator.getLineInstance();
+    private transient BreakIterator wordBreaker = BreakIterator.getWordInstance();
+    private transient BreakIterator charBreaker = BreakIterator.getCharacterInstance();
+    private transient int lineAscent;
+    private transient int lineHeight;
+    private transient int lineLeading;
+    private transient int lastHeight = 10;
+    private transient int lastWidth = 50;
+    private static final int MAX_LINES = 200; // LIU: Use symbolic name
+    private transient int[] lineStarts = new int[MAX_LINES]; // LIU
+    private transient int lineCount = 1;
+
+    private transient boolean valid = false;
+    private transient FontMetrics fm;
+    private transient boolean redoLines = true;
+    private transient boolean doubleClick = false;
+    private transient TextListener textListener;
+    private transient ActionListener selectionListener;
+    private transient Image cacheImage;
+    private transient Dimension mySize;
+    private transient int xInset = 5;
+    private transient int yInset = 5;
+    private transient Point startPoint = new Point();
+    private transient Point endPoint = new Point();
+    private transient Point caretPoint = new Point();
+    private transient Point activePoint = new Point();
+    
+    //private transient static String clipBoard;
+
+    private static final char CR = '\015'; // LIU
+
+    // ============================================
+
+    public DumbTextComponent() {
+        addMouseListener(this);
+        addMouseMotionListener(this);
+        addKeyListener(this);
+        addFocusListener(this);
+        setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
+
+    }
+
+// ================ Events ====================
+
+    // public boolean isFocusTraversable() { return true; }
+
+    public void addActionListener(ActionListener l) {
+        selectionListener = AWTEventMulticaster.add(selectionListener, l);
+    }
+
+    public void removeActionListener(ActionListener l) {
+        selectionListener = AWTEventMulticaster.remove(selectionListener, l);
+    }
+
+    public void addTextListener(TextListener l) {
+        textListener = AWTEventMulticaster.add(textListener, l);
+    }
+
+    public void removeTextListener(TextListener l) {
+        textListener = AWTEventMulticaster.remove(textListener, l);
+    }
+
+    private transient boolean pressed;
+
+    public void mousePressed(MouseEvent e) {
+        if (DEBUG) System.out.println("mousePressed");
+        if (pressed) {
+            select(e,false);
+        } else {
+            doubleClick = e.getClickCount() > 1;
+            requestFocus();
+            select(e, true);
+            pressed = true;
+        }
+    }
+
+    public void mouseDragged(MouseEvent e) {
+        if (DEBUG) System.out.println("mouseDragged");
+        select(e, false);
+    }
+
+    public void mouseReleased(MouseEvent e) {
+        if (DEBUG) System.out.println("mouseReleased");
+        pressed = false;
+    }
+
+    public void mouseEntered(MouseEvent e) {
+        //if (pressed) select(e, false);
+    }
+
+    public void mouseExited(MouseEvent e){
+        //if (pressed) select(e, false);
+    }
+
+    public void mouseClicked(MouseEvent e) {}
+    public void mouseMoved(MouseEvent e) {}
+
+
+    public void focusGained(FocusEvent e) {
+        if (DEBUG) System.out.println("focusGained");
+        focus = true;
+        valid = false;
+        repaint(16);
+    }
+    public void focusLost(FocusEvent e) {
+        if (DEBUG) System.out.println("focusLost");
+        focus = false;
+        valid = false;
+        repaint(16);
+    }
+
+    public void select(MouseEvent e, boolean first) {
+        setKeyStart(-1);
+        point2Offset(e.getPoint(), tempSelection);
+        if (first) {
+            if ((e.getModifiers() & InputEvent.SHIFT_MASK) == 0) {
+                tempSelection.anchor = tempSelection.caret;
+            }
+        }
+        // fix words
+        if (doubleClick) {
+            tempSelection.expand(wordBreaker);
+        }
+        select(tempSelection);
+    }
+    
+    public void keyPressed(KeyEvent e) {
+        int code = e.getKeyCode();
+        if (DEBUG) System.out.println("keyPressed "
+          + hex((char)code) + ", " + hex((char)e.getModifiers()));
+        int start = selection.getStart();
+        int end = selection.getEnd();
+        boolean shift = (e.getModifiers() & InputEvent.SHIFT_MASK) != 0;
+        boolean ctrl = (e.getModifiers() & InputEvent.CTRL_MASK) != 0;
+                
+        switch (code) {
+        case KeyEvent.VK_Q:
+            if (!ctrl || !editable) break;
+            setKeyStart(-1);
+            fixHex();
+            break;
+        case KeyEvent.VK_V:
+            if (!ctrl) break;
+            if (!editable) {
+                this.getToolkit().beep();
+            } else {
+                paste();
+            }
+            break;
+        case KeyEvent.VK_C:
+            if (!ctrl) break;
+            copy();
+            break;
+        case KeyEvent.VK_X:
+            if (!ctrl) break;
+            if (!editable) {
+                this.getToolkit().beep();
+            } else {
+                copy();
+                insertText("");
+            }
+            break;
+        case KeyEvent.VK_A:
+            if (!ctrl) break;
+            setKeyStart(-1);
+            select(Integer.MAX_VALUE, 0, false);
+            break;
+        case KeyEvent.VK_RIGHT:
+            setKeyStart(-1);
+            tempSelection.set(selection);
+            tempSelection.nextBound(ctrl ? wordBreaker : charBreaker, +1, shift);
+            select(tempSelection);
+            break;
+        case KeyEvent.VK_LEFT:
+            setKeyStart(-1);
+            tempSelection.set(selection);
+            tempSelection.nextBound(ctrl ? wordBreaker : charBreaker, -1, shift);
+            select(tempSelection);
+            break;
+        case KeyEvent.VK_UP: // LIU: Add support for up arrow
+            setKeyStart(-1);
+            tempSelection.set(selection);
+            tempSelection.caret = lineDelta(tempSelection.caret, -1);
+            if (!shift) {
+                tempSelection.anchor = tempSelection.caret;
+            }
+            select(tempSelection);
+            break;
+        case KeyEvent.VK_DOWN: // LIU: Add support for down arrow
+            setKeyStart(-1);
+            tempSelection.set(selection);
+            tempSelection.caret = lineDelta(tempSelection.caret, +1);
+            if (!shift) {
+                tempSelection.anchor = tempSelection.caret;
+            }
+            select(tempSelection);
+            break;
+        case KeyEvent.VK_DELETE: // LIU: Add delete key support
+            if (!editable) break;
+            setKeyStart(-1);
+            if (contents.length() == 0) break;
+            start = selection.getStart();
+            end = selection.getEnd();
+            if (start == end) {
+                ++end;
+                if (end > contents.length()) {
+                    getToolkit().beep();
+                    return;
+                }
+            }
+            replaceRange("", start, end);
+            break;            
+        }
+    }
+
+    void copy() {
+        Clipboard cb = this.getToolkit().getSystemClipboard();
+        StringSelection ss = new StringSelection(
+            contents.substring(selection.getStart(), selection.getEnd()));
+        cb.setContents(ss, ss);
+    }
+    
+    void paste () {
+        Clipboard cb = this.getToolkit().getSystemClipboard();
+        Transferable t = cb.getContents(this);
+        if (t == null) {
+            this.getToolkit().beep();
+            return;
+        }
+        try {
+            String temp = (String) t.getTransferData(DataFlavor.stringFlavor);
+            insertText(temp);
+        } catch (Exception e) {
+            this.getToolkit().beep();
+        }            
+    }
+
+    /**
+     * LIU: Given an offset into contents, moves up or down by lines,
+     * according to lineStarts[].
+     * @param off the offset into contents
+     * @param delta how many lines to move up (< 0) or down (> 0)
+     * @return the new offset into contents
+     */
+    private int lineDelta(int off, int delta) {
+        int line = findLine(off, false);
+        int posInLine = off - lineStarts[line];
+        // System.out.println("off=" + off + " at " + line + ":" + posInLine);
+        line += delta;
+        if (line < 0) {
+            line = posInLine = 0;
+        } else if (line >= lineCount) {
+            return contents.length();
+        }
+        off = lineStarts[line] + posInLine;
+        if (off >= lineStarts[line+1]) {
+            off = lineStarts[line+1] - 1;
+        }
+        return off;
+    }
+      
+    public void keyReleased(KeyEvent e) {
+        int code = e.getKeyCode();
+        if (DEBUG) System.out.println("keyReleased "
+          + hex((char)code) + ", " + hex((char)e.getModifiers()));
+    }
+
+    public void keyTyped(KeyEvent e) {
+        char ch = e.getKeyChar();
+        if (DEBUG) System.out.println("keyTyped "
+          + hex((char)ch) + ", " + hex((char)e.getModifiers()));
+        if ((e.getModifiers() & InputEvent.CTRL_MASK) != 0) return;
+        int start, end;
+        switch (ch) {
+        case KeyEvent.CHAR_UNDEFINED:
+            break;
+        case KeyEvent.VK_BACK_SPACE:
+            //setKeyStart(-1);
+            if (!editable) break;
+            if (contents.length() == 0) break;
+            start = selection.getStart();
+            end = selection.getEnd();
+            if (start == end) {
+                --start;
+                if (start < 0) {
+                    getToolkit().beep(); // LIU: Add audio feedback of NOP
+                    return;
+                }
+            }
+            replaceRange("", start, end);
+            break;        
+        case KeyEvent.VK_DELETE:
+            //setKeyStart(-1);
+            if (!editable) break;
+            if (contents.length() == 0) break;
+            start = selection.getStart();
+            end = selection.getEnd();
+            if (start == end) {
+                ++end;
+                if (end > contents.length()) {
+                    getToolkit().beep(); // LIU: Add audio feedback of NOP
+                    return;
+                }
+            }
+            replaceRange("", start, end);
+            break;
+        default:
+            if (!editable) break;
+            // LIU: Dispatch to subclass API
+            handleKeyTyped(e);
+            break;
+        }
+    }
+
+    // LIU: Subclass API for handling of key typing
+    protected void handleKeyTyped(KeyEvent e) {
+        insertText(String.valueOf(e.getKeyChar()));
+    }
+    
+    protected void setKeyStart(int keyStart) {
+        if (activeStart != keyStart) {
+            activeStart = keyStart;
+            repaint(10);
+        }
+    }
+    
+    protected void validateKeyStart() {
+        if (activeStart > selection.getStart()) {
+            activeStart = selection.getStart();
+            repaint(10);
+        }
+    }
+    
+    protected int getKeyStart() {
+        return activeStart;
+    }
+
+// ===================== Control ======================
+
+    public synchronized void setEditable(boolean b) {
+        editable = b;
+    }
+
+    public boolean isEditable() {
+        return editable;
+    }
+
+    public void select(Selection newSelection) {
+        newSelection.pin(contents);
+        if (!selection.equals(newSelection)) {
+            selection.set(newSelection);
+            if (selectionListener != null) {
+                selectionListener.actionPerformed(
+                  new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
+                    "Selection Changed", 0));
+            }
+            repaint(10);
+            valid = false;
+        }
+    }
+
+    public void select(int start, int end) {
+        select(start, end, false);
+    }
+
+    public void select(int start, int end, boolean clickAfter) {
+        tempSelection.set(start, end, clickAfter);
+        select(tempSelection);
+    }
+
+    public int getSelectionStart() {
+        return selection.getStart();
+    }
+
+    public int getSelectionEnd() {
+        return selection.getEnd();
+    }
+
+    public void setBounds(int x, int y, int w, int h) {
+        super.setBounds(x,y,w,h);
+        redoLines = true;
+    }
+
+    public Dimension getPreferredSize() {
+        return new Dimension(lastWidth,lastHeight);
+    }
+
+    public Dimension getMaximumSize() {
+        return new Dimension(lastWidth,lastHeight);
+    }
+
+    public Dimension getMinimumSize() {
+        return new Dimension(lastHeight,lastHeight);
+    }
+
+    public void setText(String text) {
+        setText2(text);
+        select(tempSelection.set(selection).pin(contents));
+    }
+
+    public void setText2(String text) {
+        contents = text;
+        charBreaker.setText(text);
+        wordBreaker.setText(text);
+        lineBreaker.setText(text);
+        redoLines = true;
+        if (textListener != null)
+            textListener.textValueChanged(
+              new TextEvent(this, TextEvent.TEXT_VALUE_CHANGED));
+        repaint(16);
+    }
+
+    public void insertText(String text) {
+        if (activeStart == -1) activeStart = selection.getStart();
+        replaceRange(text, selection.getStart(), selection.getEnd());
+    }
+
+    public void replaceRange(String s, int start, int end) {
+        setText2(contents.substring(0,start) + s
+          + contents.substring(end));
+        select(tempSelection.set(selection).
+          fixAfterReplace(start, end, s.length()));
+        validateKeyStart();
+    }
+
+    public String getText() {
+        return contents;
+    }
+
+    public void setFont(Font font) {
+        super.setFont(font);
+        redoLines = true;
+        repaint(16);
+    }
+
+    // ================== Graphics ======================
+
+    public void update(Graphics g) {
+        if (DEBUG) System.out.println("update");
+        paint(g);
+    }
+
+    public void paint(Graphics g) {
+        mySize = getSize();
+        if (cacheImage == null
+          || cacheImage.getHeight(this) != mySize.height
+          || cacheImage.getWidth(this) != mySize.width) {
+            cacheImage = createImage(mySize.width, mySize.height);
+            valid = false;
+        }
+        if (!valid || redoLines) {
+            if (DEBUG) System.out.println("painting");
+            paint2(cacheImage.getGraphics());
+            valid = true;
+        }
+        //getToolkit().sync();
+        if (DEBUG) System.out.println("copying");
+        g.drawImage(cacheImage,
+          0, 0, mySize.width, mySize.height,
+          0, 0, mySize.width, mySize.height,
+          this);
+    }
+
+    public void paint2(Graphics g) {
+        g.clearRect(0, 0, mySize.width, mySize.height);
+        if (DEBUG) System.out.println("print");
+        if (focus) g.setColor(Color.black);
+        else g.setColor(Color.gray);
+        g.drawRect(0,0,mySize.width-1,mySize.height-1);
+        g.setClip(1,1,
+          mySize.width-2,mySize.height-2);
+        g.setColor(Color.black);
+        g.setFont(getFont());
+        fm = g.getFontMetrics();
+        lineAscent = fm.getAscent();
+        lineLeading = fm.getLeading();
+        lineHeight = lineAscent + fm.getDescent() + lineLeading;
+        int y = yInset + lineAscent;
+        String lastSubstring = "";
+        if (redoLines) fixLineStarts(mySize.width-xInset-xInset);
+        for (int i = 0; i < lineCount; y += lineHeight, ++i) {
+            // LIU: Don't display terminating ^M characters
+            int lim = lineStarts[i+1];
+            if (lim > 0 && contents.length() > 0 &&
+                contents.charAt(lim-1) == CR) --lim;
+            lastSubstring = contents.substring(lineStarts[i],lim);
+            g.drawString(lastSubstring, xInset, y);
+        }
+        drawSelection(g, lastSubstring);
+        lastHeight = y + yInset - lineHeight + yInset;
+        lastWidth = mySize.width-xInset-xInset;
+    }
+
+    void paintRect(Graphics g, int x, int y, int w, int h) {
+        if (focus) {
+            g.fillRect(x, y, w, h);
+        } else {
+            g.drawRect(x, y, w-1, h-1);
+        }
+    }
+
+    public void drawSelection(Graphics g, String lastSubstring) {
+        g.setXORMode(Color.black);
+        if (activeStart != -1) {
+            offset2Point(activeStart, false, activePoint);
+            g.setColor(Color.magenta);
+            int line = activePoint.x - 1;
+            g.fillRect(line, activePoint.y, 1, lineHeight);
+        }
+        if (selection.isCaret()) {
+            offset2Point(selection.caret, selection.clickAfter, caretPoint);
+        } else {
+            if (focus) g.setColor(Color.blue);
+            else g.setColor(Color.yellow);
+            offset2Point(selection.getStart(), true, startPoint);
+            offset2Point(selection.getEnd(), false, endPoint);
+            if (selection.getStart() == selection.caret)
+                caretPoint.setLocation(startPoint);
+            else caretPoint.setLocation(endPoint);
+            if (startPoint.y == endPoint.y) {
+                paintRect(g, startPoint.x, startPoint.y,
+                  Math.max(1,endPoint.x-startPoint.x), lineHeight);
+            } else {
+                paintRect(g, startPoint.x, startPoint.y,
+                  (mySize.width-xInset)-startPoint.x, lineHeight);
+                if (startPoint.y + lineHeight < endPoint.y)
+                  paintRect(g, xInset, startPoint.y + lineHeight,
+                  (mySize.width-xInset)-xInset, endPoint.y - startPoint.y - lineHeight);
+                paintRect(g, xInset, endPoint.y, endPoint.x-xInset, lineHeight);
+            }
+        }
+        if (focus || selection.isCaret()) {
+            if (focus) g.setColor(Color.green);
+            else g.setColor(Color.red);
+            int line = caretPoint.x - (selection.clickAfter ? 0 : 1);
+            g.fillRect(line, caretPoint.y, 1, lineHeight);
+            int w = lineHeight/12 + 1;
+            int braces = line - (selection.clickAfter ? -1 : w);
+            g.fillRect(braces, caretPoint.y, w, 1);
+            g.fillRect(braces, caretPoint.y + lineHeight - 1, w, 1);
+        }
+    }
+
+    public Point offset2Point(int off, boolean start, Point p) {
+        int line = findLine(off, start);
+        int width = 0;
+        try {
+            width = fm.stringWidth(
+              contents.substring(lineStarts[line], off));
+        } catch (Exception e) {
+            System.out.println(e);
+        }
+        p.x = width + xInset;
+        if (p.x > mySize.width - xInset)
+            p.x = mySize.width - xInset;
+        p.y = lineHeight * line + yInset;
+        return p;
+    }
+
+    private int findLine(int off, boolean start) {
+        // if it is start, then go to the next line!
+        if (start) ++off;
+        for (int i = 1; i < lineCount; ++i) {
+            // LIU: This was <= ; changed to < to make caret after
+            // final CR in line appear at START of next line.
+            if (off < lineStarts[i]) return i-1;
+        }
+        // LIU: Check for special case; after CR at end of the last line
+        if (off == lineStarts[lineCount] &&
+            off > 0 && contents.length() > 0 && contents.charAt(off-1) == CR) {
+            return lineCount;
+        }
+        return lineCount-1;
+    }
+
+    // offsets on any line will go from start,true to end,false
+    // excluding start,false and end,true
+    public Selection point2Offset(Point p, Selection o) {
+        if (p.y < yInset) {
+            o.caret = 0;
+            o.clickAfter = true;
+            return o;
+        }
+        int line = (p.y - yInset)/lineHeight;
+        if (line >= lineCount) {
+            o.caret = contents.length();
+            o.clickAfter = false;
+            return o;
+        }
+        int target = p.x - xInset;
+        if (target <= 0) {
+            o.caret = lineStarts[line];
+            o.clickAfter = true;
+            return o;
+        }
+        int lowGuess = lineStarts[line];
+        int lowWidth = 0;
+        int highGuess = lineStarts[line+1];
+        int highWidth = fm.stringWidth(contents.substring(lineStarts[line],highGuess));
+        if (target >= highWidth) {
+            o.caret = lineStarts[line+1];
+            o.clickAfter = false;
+            return o;
+        }
+        while (lowGuess < highGuess - 1) {
+            int guess = (lowGuess + highGuess)/2;
+            int width = fm.stringWidth(contents.substring(lineStarts[line],guess));
+            if (width <= target) {
+                lowGuess = guess;
+                lowWidth = width;
+                if (width == target) break;
+            } else {
+                highGuess = guess;
+                highWidth = width;
+            }
+        }
+        // at end, either lowWidth < target < width(low+1), or lowWidth = target
+        int highBound = charBreaker.following(lowGuess);
+        int lowBound = charBreaker.previous();
+        // we are now at character boundaries
+        if (lowBound != lowGuess)
+            lowWidth = fm.stringWidth(contents.substring(lineStarts[line],lowBound));
+        if (highBound != highGuess)
+            highWidth = fm.stringWidth(contents.substring(lineStarts[line],highBound));
+        // we now have the right widths
+        if (target - lowWidth < highWidth - target) {
+            o.caret = lowBound;
+            o.clickAfter = true;
+        } else {
+            o.caret = highBound;
+            o.clickAfter = false;
+        }
+        // we now have the closest!
+        return o;
+    }
+
+    private void fixLineStarts(int width) {
+        lineCount = 1;
+        lineStarts[0] = 0;
+        if (contents.length() == 0) {
+            lineStarts[1] = 0;
+            return;
+        }
+        int end = 0;
+        // LIU: Add check for MAX_LINES
+        for (int start = 0; start < contents.length() && lineCount < MAX_LINES;
+             start = end) {
+            end = nextLine(fm, start, width);
+            lineStarts[lineCount++] = end;
+            if (end == start) { // LIU: Assertion
+                throw new RuntimeException("nextLine broken");
+            }
+        }
+        --lineCount;
+        redoLines = false;
+    }
+
+    // LIU: Enhanced to wrap long lines.  Bug with return of start fixed.
+    public int nextLine(FontMetrics fMtr, int start, int width) {
+        int len = contents.length();
+        for (int i = start; i < len; ++i) {
+            // check for line separator
+            char ch = (contents.charAt(i));
+            if (ch >= 0x000A && ch <= 0x000D || ch == 0x2028 || ch == 0x2029) {
+                len = i + 1;
+                if (ch == 0x000D && i+1 < len && contents.charAt(i+1) == 0x000A) // crlf
+                    ++len; // grab extra char
+                break;
+            }
+        }
+        String subject = contents.substring(start,len);
+        if (visibleWidth(fMtr, subject) <= width)
+          return len;
+
+        // LIU: Remainder of this method rewritten to accomodate lines
+        // longer than the component width by first trying to break
+        // into lines; then words; finally chars.
+        int n = findFittingBreak(fMtr, subject, width, lineBreaker);
+        if (n == 0) {
+            n = findFittingBreak(fMtr, subject, width, wordBreaker);
+        }
+        if (n == 0) {
+            n = findFittingBreak(fMtr, subject, width, charBreaker);
+        }
+        return n > 0 ? start + n : len;
+    }
+
+    /**
+     * LIU: Finds the longest substring that fits a given width
+     * composed of subunits returned by a BreakIterator.  If the smallest
+     * subunit is too long, returns 0.
+     * @param fMtr metrics to use
+     * @param line the string to be fix into width
+     * @param width line.substring(0, result) must be <= width
+     * @param breaker the BreakIterator that will be used to find subunits
+     * @return maximum characters, at boundaries returned by breaker,
+     * that fit into width, or zero on failure
+     */
+    private int findFittingBreak(FontMetrics fMtr, String line, int width,
+                                 BreakIterator breaker) {
+        breaker.setText(line);
+        int last = breaker.first();
+        int end = breaker.next();
+        while (end != BreakIterator.DONE &&
+               visibleWidth(fMtr, line.substring(0, end)) <= width) {
+            last = end;
+            end = breaker.next();
+        }
+        return last;
+    }
+
+    public int visibleWidth(FontMetrics fMtr, String s) {
+        int i;
+        for (i = s.length()-1; i >= 0; --i) {
+            char ch = s.charAt(i);
+            if (!(ch == ' ' || ch >= 0x000A && ch <= 0x000D || ch == 0x2028 || ch == 0x2029))
+                return fMtr.stringWidth(s.substring(0,i+1));
+        }
+        return 0;
+    }
+
+// =============== Utility ====================
+
+    private void fixHex() {
+        if (selection.getEnd() == 0) return;
+        int store = 0;
+        int places = 1;
+        int count = 0;
+        int min = Math.min(8,selection.getEnd());
+        for (int i = 0; i < min; ++i) {
+            char ch = contents.charAt(selection.getEnd()-1-i);
+            int value = Character.getNumericValue(ch);
+            if (value < 0 || value > 15) break;
+            store += places * value;
+            ++count;
+            places *= 16;
+        }
+        String add = "";
+        int bottom = store & 0xFFFF;
+        if (store >= 0xD8000000 && store < 0xDC000000
+          && bottom >= 0xDC00 && bottom < 0xE000) { // surrogates
+            add = "" + (char)(store >> 16) + (char)bottom;
+        } else if (store > 0xFFFF && store <= 0x10FFFF) {
+            store -= 0x10000;
+            add = "" + (char)(((store >> 10) & 0x3FF) + 0xD800)
+              + (char)((store & 0x3FF) + 0xDC00);
+              
+        } else if (count >= 4) {
+            count = 4;
+            add = ""+(char)(store & 0xFFFF);
+        } else {
+            count = 1;
+            char ch = contents.charAt(selection.getEnd()-1);
+            add = hex(ch);
+            if (ch >= 0xDC00 && ch <= 0xDFFF && selection.getEnd() > 1) {
+                ch = contents.charAt(selection.getEnd()-2);
+                if (ch >= 0xD800 && ch <= 0xDBFF) {
+                    count = 2;
+                    add = hex(ch) + add;
+                }
+            }
+        }
+        replaceRange(add, selection.getEnd()-count, selection.getEnd());
+    }
+
+    public static String hex(char ch) {
+        String result = Integer.toString(ch,16).toUpperCase();
+        result = "0000".substring(result.length(),4) + result;
+        return result;
+    }
+}
diff --git a/demos/src/com/ibm/icu/dev/demo/impl/Selection.java b/demos/src/com/ibm/icu/dev/demo/impl/Selection.java
new file mode 100644
index 0000000..7f80a4d
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/Selection.java
@@ -0,0 +1,161 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2004, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.impl;
+import java.text.*;
+
+public final class Selection {
+
+    public int anchor;
+    public int caret;
+    public boolean clickAfter;
+
+    public int getStart() {
+        return anchor < caret ? anchor : caret;
+    }
+
+    public int getEnd() {
+        return anchor > caret ? anchor : caret;
+    }
+
+    public boolean isCaret() {
+        return anchor == caret;
+    }
+
+    public Selection set(Selection other) {
+        anchor = other.anchor;
+        caret = other.caret;
+        clickAfter = other.clickAfter;
+        return this;
+    }
+
+    public Selection set(int anchor, int caret, boolean clickAfter) {
+        this.anchor = anchor;
+        this.caret = caret;
+        this.clickAfter = clickAfter;
+        return this;
+    }
+
+    public boolean equals(Object other) {
+        Selection other2 = (Selection)other;
+        return anchor == other2.anchor
+          && caret == other2.caret
+          && clickAfter == other2.clickAfter;
+    }
+
+    public boolean isLessThan(Selection other) {
+        return getStart() < other.getEnd();
+    }
+
+    public Selection pin(String text) {
+        if (anchor > text.length()) {
+            anchor = text.length();
+        } else if (anchor < 0) {
+            anchor = 0;
+        }
+        if (caret > text.length()) {
+            caret = text.length();
+            clickAfter = true;
+        } else if (caret < 0) {
+            caret = 0;
+            clickAfter = false;
+        }
+        return this;
+    }
+
+    public Selection swap(Selection after) {
+        int temp = anchor;
+        anchor = after.anchor;
+        after.anchor = temp;
+        temp = caret;
+        caret = after.caret;
+        after.caret = temp;
+        boolean b = clickAfter;
+        clickAfter = after.clickAfter;
+        after.clickAfter = b;
+        return this;
+    }
+
+    public Selection fixAfterReplace(int start, int end, int len) {
+        if (anchor >= start) {
+            if (anchor < end) anchor = end;
+            anchor = start + len + anchor - end;
+        }
+        if (caret >= start) {
+            if (caret < end) caret = end;
+            caret = start + len + caret - end;
+        }
+        return this;
+    }
+
+        // Mac & Windows considerably different
+        // Mac: end++. If start!=end, start=end
+        //  SHIFT: move end right
+        //  CTL: no different
+        // Windows:
+        //  UNSHIFTED: if start!=end, start = end, else start=end=end+1;
+        //       anchor = tip = start
+        //  SHIFT: tip++
+        //  CTL: if start!=end, start = end = nextbound(end-1),
+        //   else start=end=nextbound(end)
+        //       anchor = tip = start
+        //  CTL/SHIFT: tip = nextbound(tip)
+
+    public Selection nextBound(BreakIterator breaker,
+      int direction, boolean extend) {
+        if (!extend && anchor != caret) caret -= direction;
+        caret = next(caret, breaker, direction, true);
+        if (!extend) anchor = caret;
+        clickAfter = false;
+        return this;
+    }
+
+    // expand start and end to word breaks--if they are not already on one
+    public void expand(BreakIterator breaker) {
+        if (anchor <= caret) {
+            anchor = next(anchor,breaker,-1,false);
+            caret = next(caret,breaker,1,false);
+            /*
+            try {
+                breaker.following(anchor);
+                anchor = breaker.previous();
+            } catch (Exception e) {}
+            try {
+                caret = breaker.following(caret-1);
+            } catch (Exception e) {}
+            */
+        } else {
+            anchor = next(anchor,breaker,1,false);
+            caret = next(caret,breaker,-1,false);
+            /*
+            try {
+                breaker.following(caret);
+                caret = breaker.previous();
+            } catch (Exception e) {}
+            try {
+                anchor = breaker.following(anchor-1);
+            } catch (Exception e) {}
+            */
+        }
+    }
+
+    // different = false - move to next boundary, unless on one
+    // true - move to next boundary, even if on one
+    public static int next(int position, BreakIterator breaker,
+      int direction, boolean different) {
+        if (!different) position -= direction;
+        try {
+            if (direction > 0) {
+                position = breaker.following(position);
+            } else {
+                breaker.following(position-1);
+                position = breaker.previous();
+            }
+        } catch (Exception e) {}
+        return position;
+    }
+}
+
diff --git a/demos/src/com/ibm/icu/dev/demo/impl/package.html b/demos/src/com/ibm/icu/dev/demo/impl/package.html
new file mode 100644
index 0000000..a7e8d35
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--  Copyright (C) 2000-2004, International Business Machines Corporation and
+  others. All Rights Reserved.
+
+-->
+</head>
+<body bgcolor="white">
+Shared utilities for demo applications and Applets.
+</body>
+</html>
\ No newline at end of file
diff --git a/demos/src/com/ibm/icu/dev/demo/number/CurrencyDemo.java b/demos/src/com/ibm/icu/dev/demo/number/CurrencyDemo.java
new file mode 100644
index 0000000..4912a06
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/number/CurrencyDemo.java
@@ -0,0 +1,113 @@
+/*
+**********************************************************************
+* Copyright (c) 2003, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+* Author: Mark Davis
+* Created: May 22 2003
+* Since: ICU 2.6
+**********************************************************************
+*/
+package com.ibm.icu.dev.demo.number;
+import com.ibm.icu.util.Currency;
+import com.ibm.icu.text.NumberFormat;
+import com.ibm.icu.text.DecimalFormat;
+import com.ibm.icu.text.DecimalFormatSymbols;
+import com.ibm.icu.impl.Utility;
+import java.util.Locale;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Demonstration code to illustrate how to obtain ICU 2.6-like currency
+ * behavior using pre-ICU 2.6 ICU4J.
+ * @author Mark Davis
+ */
+public class CurrencyDemo {
+
+    public static void main(String[] args) {
+        testFormatHack(true);
+    }
+
+    static NumberFormat getCurrencyFormat(Currency currency,
+                                          Locale displayLocale,
+                                          boolean ICU26) {
+        // code for ICU 2.6
+        if (ICU26) {
+            NumberFormat result = NumberFormat.getCurrencyInstance(displayLocale);
+            result.setCurrency(currency);
+            return result;
+        }
+
+        // ugly work-around for 2.4
+        DecimalFormat result = (DecimalFormat)NumberFormat.getCurrencyInstance(displayLocale);
+        HackCurrencyInfo hack = (HackCurrencyInfo)(hackData.get(currency.getCurrencyCode()));
+        result.setMinimumFractionDigits(hack.decimals);
+        result.setMaximumFractionDigits(hack.decimals);
+        result.setRoundingIncrement(hack.rounding);
+        DecimalFormatSymbols symbols = result.getDecimalFormatSymbols();
+        symbols.setCurrencySymbol(hack.symbol);
+        result.setDecimalFormatSymbols(symbols);
+        return result;
+    }
+        
+    static Map hackData = new HashMap();
+    static class HackCurrencyInfo {
+        int decimals;
+        double rounding;
+        String symbol;
+        HackCurrencyInfo(int decimals, double rounding, String symbol) {
+            this.decimals = decimals;
+            this.rounding = rounding;
+            this.symbol = symbol;
+        }
+    }
+    static {
+        hackData.put("USD", new HackCurrencyInfo(2, 0, "$"));
+        hackData.put("GBP", new HackCurrencyInfo(2, 0, "\u00A3"));
+        hackData.put("JPY", new HackCurrencyInfo(0, 0, "\u00A5"));
+        hackData.put("EUR", new HackCurrencyInfo(2, 0, "\u20AC"));
+    }
+
+    /**
+     * Walk through all locales and compare the output of the ICU26
+     * currency format with the "hacked" currency format.
+     * @param quiet if true, only display discrepancies.  Otherwise,
+     * display all results.
+     */
+    static void testFormatHack(boolean quiet) {
+        String[] testCurrencies = {"USD","GBP","JPY","EUR"};
+        Locale[] testLocales = NumberFormat.getAvailableLocales();
+        for (int i = 0; i < testLocales.length; ++i) {
+            // since none of this should vary by country, we'll just do by language
+            if (!testLocales[i].getCountry().equals("")) continue;
+            boolean noOutput = true;
+            if (!quiet) {
+                System.out.println(testLocales[i].getDisplayName());
+                noOutput = false;
+            }
+            for (int j = 0; j < testCurrencies.length; ++j) {
+                NumberFormat nf26 = getCurrencyFormat(Currency.getInstance(testCurrencies[j]), testLocales[i], true);
+                String str26 = nf26.format(1234.567);
+                if (!quiet) {
+                    System.out.print("\t" + Utility.escape(str26));
+                }
+                NumberFormat nf24 = getCurrencyFormat(Currency.getInstance(testCurrencies[j]), testLocales[i], false);
+                String str24 = nf24.format(1234.567);
+                if (!str24.equals(str26)) {
+                    if (noOutput) {
+                        System.out.println(testLocales[i].getDisplayName());
+                        noOutput = false;
+                    }
+                    if (quiet) {
+                        System.out.print("\t" + Utility.escape(str26));
+                    }
+                    System.out.print(" (" + Utility.escape(str24) + ")");
+                }
+            }
+            if (!noOutput) {
+                System.out.println();
+            }
+        }
+    }
+}
diff --git a/demos/src/com/ibm/icu/dev/demo/rbnf/RbnfDemo.java b/demos/src/com/ibm/icu/dev/demo/rbnf/RbnfDemo.java
new file mode 100644
index 0000000..1b67c06
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/rbnf/RbnfDemo.java
@@ -0,0 +1,550 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.rbnf;
+
+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.icu.dev.demo.impl.*;
+import com.ibm.icu.text.RuleBasedNumberFormat;
+
+public class RbnfDemo extends DemoApplet {
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = -9119861296873763536L;
+
+    /**
+     * 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();
+        final DemoApplet theApplet = applet;
+        window.addWindowListener(
+                new WindowAdapter() {
+                    public void windowClosing(WindowEvent e) {
+                        setVisible(false);
+                        window.dispose();
+
+                        if (theApplet != null) {
+                            theApplet.demoClosed();
+                        } else System.exit(0);
+                    }
+                } );
+        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 {
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = -7947090021239472658L;
+    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 txt = getText();
+        BreakIterator bi = BreakIterator.getLineInstance();
+        bi.setText(txt);
+        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 < txt.length()) {
+            maxLineEnd = txt.indexOf('\n', lineStart);
+            if (maxLineEnd == -1)
+                maxLineEnd = Integer.MAX_VALUE;
+            while (tempLineEnd != BreakIterator.DONE && fm.stringWidth(txt.substring(
+                            lineStart, tempLineEnd)) < width) {
+                lineEnd = tempLineEnd;
+                tempLineEnd = bi.next();
+            }
+            if (lineStart >= lineEnd) {
+                if (tempLineEnd == BreakIterator.DONE)
+                    lineEnd = txt.length();
+                else
+                    lineEnd = tempLineEnd;
+            }
+            if (lineEnd > maxLineEnd)
+                lineEnd = maxLineEnd;
+            g.drawString(txt.substring(lineStart, lineEnd), 0, penY);
+            penY += lineHeight;
+            totalHeight += lineHeight;
+            lineStart = lineEnd;
+            if (lineStart < txt.length() && txt.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 {
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = 7514498764062569858L;
+    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/demos/src/com/ibm/icu/dev/demo/rbnf/RbnfSampleRuleSets.java b/demos/src/com/ibm/icu/dev/demo/rbnf/RbnfSampleRuleSets.java
new file mode 100644
index 0000000..c03ed71
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/rbnf/RbnfSampleRuleSets.java
@@ -0,0 +1,1941 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.rbnf;
+
+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
+ */
+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
+    // decimals.
+
+    /**
+     * 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/demos/src/com/ibm/icu/dev/demo/rbnf/package.html b/demos/src/com/ibm/icu/dev/demo/rbnf/package.html
new file mode 100644
index 0000000..8a0507f
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/rbnf/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--  Copyright (C) 2000-2004, International Business Machines Corporation and
+  others. All Rights Reserved.
+
+-->
+</head>
+<body bgcolor="white">
+RuleBasedNumberFormat demo appliation.
+</body>
+</html>
\ No newline at end of file
diff --git a/demos/src/com/ibm/icu/dev/demo/timescale/PivotDemo.java b/demos/src/com/ibm/icu/dev/demo/timescale/PivotDemo.java
new file mode 100644
index 0000000..72d8304
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/timescale/PivotDemo.java
@@ -0,0 +1,78 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2008, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ */
+
+package com.ibm.icu.dev.demo.timescale;
+
+import java.util.Locale;
+
+import com.ibm.icu.text.MessageFormat;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.SimpleTimeZone;
+import com.ibm.icu.util.TimeZone;
+import com.ibm.icu.util.UniversalTimeScale;
+
+/**
+ * This class demonstrates how to use <code>UniversalTimeScale</code> to
+ * convert from one local time scale to another.
+ * 
+ * @see UniversalTimeScale
+ */
+public class PivotDemo {
+
+    /**
+     * The default constructor.
+     */
+    public PivotDemo()
+    {
+    }
+
+    /**
+     * The <code>main()</code> method uses <code>UniversalTimeScale</code> to
+     * convert from the Java and Unix time scales to the ICU time scale. It uses
+     * a <code>Calendar</code> object to display the ICU time values.
+     * 
+     * @param args the command line arguments.
+     */
+    public static void main(String[] args)
+    {
+        TimeZone utc = new SimpleTimeZone(0, "UTC");
+        Calendar cal = Calendar.getInstance(utc, Locale.ENGLISH);
+        MessageFormat fmt = new MessageFormat("{1} = {0, date, full} {0, time, full}");
+        Object arguments[] = {cal, null};
+        
+        arguments[0] = cal;
+        
+        System.out.println("\nJava test:");
+        cal.setTimeInMillis(UniversalTimeScale.toLong(UniversalTimeScale.from(0, UniversalTimeScale.JAVA_TIME), UniversalTimeScale.ICU4C_TIME));
+        arguments[1] = " 000000000000000";
+        System.out.println(fmt.format(arguments));
+        
+        cal.setTimeInMillis(UniversalTimeScale.toLong(UniversalTimeScale.from(-62164684800000L, UniversalTimeScale.JAVA_TIME), UniversalTimeScale.ICU4C_TIME));
+        arguments[1] = "-62164684800000L";
+        System.out.println(fmt.format(arguments));
+        
+        cal.setTimeInMillis(UniversalTimeScale.toLong(UniversalTimeScale.from(-62135769600000L, UniversalTimeScale.JAVA_TIME), UniversalTimeScale.ICU4C_TIME));
+        arguments[1] = "-62135769600000L";
+        System.out.println(fmt.format(arguments));
+        
+        System.out.println("\nUnix test:");
+        
+        cal.setTimeInMillis(UniversalTimeScale.toLong(UniversalTimeScale.from(0x80000000, UniversalTimeScale.UNIX_TIME), UniversalTimeScale.ICU4C_TIME));
+        arguments[1] = "0x80000000";
+        System.out.println(fmt.format(arguments));
+        
+        cal.setTimeInMillis(UniversalTimeScale.toLong(UniversalTimeScale.from(0, UniversalTimeScale.UNIX_TIME), UniversalTimeScale.ICU4C_TIME));
+        arguments[1] = "0x00000000";
+        System.out.println(fmt.format(arguments));
+        
+        cal.setTimeInMillis(UniversalTimeScale.toLong(UniversalTimeScale.from(0x7FFFFFFF, UniversalTimeScale.UNIX_TIME), UniversalTimeScale.ICU4C_TIME));
+        arguments[1] = "0x7FFFFFFF";
+        System.out.println(fmt.format(arguments));
+        
+    }
+}
diff --git a/demos/src/com/ibm/icu/dev/demo/translit/AnyTransliterator.java b/demos/src/com/ibm/icu/dev/demo/translit/AnyTransliterator.java
new file mode 100644
index 0000000..0386dc6
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/translit/AnyTransliterator.java
@@ -0,0 +1,299 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2008, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.translit;
+import com.ibm.icu.lang.*;
+import com.ibm.icu.text.*;
+import java.util.*;
+
+public class AnyTransliterator extends Transliterator {
+    
+    static final boolean DEBUG = false;
+    private String targetName;
+    private RunIterator it;
+    private Position run;
+    
+    
+    public AnyTransliterator(String targetName, UnicodeFilter filter, RunIterator it){
+        super("Any-" + targetName, filter);
+        this.targetName = targetName;
+        this.it = it;
+        run = new Position();
+    }
+    
+    public AnyTransliterator(String targetName, UnicodeFilter filter){
+        this(targetName, filter, new ScriptRunIterator());
+    }
+    
+    static private Transliterator hex = Transliterator.getInstance("[^\\u0020-\\u007E] hex");
+    
+    protected void handleTransliterate(Replaceable text,
+                                       Position offsets, boolean isIncremental) {
+        if (DEBUG) {
+            System.out.println("- handleTransliterate " + hex.transliterate(text.toString())
+                + ", " + toString(offsets));
+        }
+        it.reset(text, offsets);
+        
+        while (it.next(run)) {
+            if (targetName.equalsIgnoreCase(it.getName())) {
+                if (DEBUG) System.out.println("Skipping identical: " + targetName);
+                run.start = run.limit; // show we processed
+                continue; // skip if same
+            }
+            
+            Transliterator t;
+            String id = it.getName() + '-' + targetName;
+            try {
+                t = Transliterator.getInstance(id);
+            } catch (IllegalArgumentException ex) {
+                if (DEBUG) System.out.println("Couldn't find: " + id + ", Trying Latin as Pivot");
+                id = it.getName() + "-Latin; Latin-" + targetName;
+                try {
+                    t = Transliterator.getInstance(id);
+                } catch (IllegalArgumentException ex2) {
+                    if (DEBUG) System.out.println("Couldn't find: " + id);
+                    continue;
+                }
+            }
+            // TODO catch error later!!
+                
+            if (DEBUG) {
+                System.out.println(t.getID());
+                System.out.println("input: " + hex.transliterate(text.toString())
+                 + ", " + toString(run));
+            }
+            
+            if (isIncremental && it.atEnd()) {
+                t.transliterate(text, run);
+            } else {
+                t.finishTransliteration(text, run);
+            }
+            // adjust the offsets in line with the changes
+            it.adjust(run.limit);
+            
+            if (DEBUG) {
+                System.out.println("output: " + hex.transliterate(text.toString())
+                 + ", " + toString(run));
+            }
+        }
+
+        // show how far we got!
+        it.getExpanse(offsets);
+        if (run.start == run.limit) offsets.start = offsets.limit;
+        else offsets.start = run.start;
+        if (DEBUG) {
+            System.out.println("+ handleTransliterate: " + ", " + toString(offsets));
+            System.out.println();
+        }
+    }
+    
+    // should be method on Position
+    public static String toString(Position offsets) {
+        return "[cs: " + offsets.contextStart
+                + ", s: " + offsets.start
+                + ", l: " + offsets.limit
+                + ", cl: " + offsets.contextLimit
+                + "]";
+    }
+    
+    public interface RunIterator {
+        public void reset(Replaceable text, Position expanse);
+        public void getExpanse(Position run);
+        public void reset();
+        public boolean next(Position run);
+        public void getCurrent(Position run);
+        public String getName();
+        public void adjust(int newCurrentLimit);
+        public boolean atEnd();
+    }
+    
+    /**
+     * Returns a series of ranges corresponding to scripts. They will be of the form:
+     * ccccSScSSccccTTcTcccc    - where c is common, S is the first script and T is the second
+     *|            |            - first run
+     *         |            |    - second run
+     * That is, the runs will overlap. The reason for this is so that a transliterator can
+     * consider common characters both before and after the scripts.
+     * The only time that contextStart != start is for the first run 
+     *    (the context is the start context of the entire expanse)
+     * The only time that contextLimit != limit is for the last run 
+     *    (the context is the end context of the entire expanse)
+     */
+    public static class ScriptRunIterator implements RunIterator {
+        private Replaceable text;
+        private Position expanse = new Position();
+        private Position current = new Position();
+        private int script;
+        private boolean done = true;
+        
+
+        public void reset(Replaceable repText, Position expansePos) {
+            set(this.expanse, expansePos);
+            this.text = repText;
+            reset();
+        }
+            
+        public void reset() {
+            done = false;
+            //this.expanse = expanse;
+            script = UScript.INVALID_CODE;
+            // set up first range to be empty, at beginning
+            current.contextStart = expanse.contextStart;
+            current.start = current.limit = current.contextLimit = expanse.start;            
+        }
+            
+        public boolean next(Position run) {
+            if (done) return false;
+            if (DEBUG) {
+                System.out.println("+cs: " + current.contextStart
+                    + ", s: " + current.start
+                    + ", l: " + current.limit
+                    + ", cl: " + current.contextLimit);
+            }
+            // reset start context run to the last end
+            current.start = current.limit;
+            
+            // Phase 1. Backup the START value through COMMON until we get to expanse.start or a real script.
+            int i, cp;
+            int limit = expanse.start;
+            for (i = current.start; i > limit; i -= UTF16.getCharCount(cp)) {
+                cp = text.char32At(i);
+                int scrpt = UScript.getScript(cp);
+                if (scrpt != UScript.COMMON && scrpt != UScript.INHERITED) break;
+            }
+            current.start = i;
+            current.contextStart = (i == limit) ? expanse.contextStart : i; // extend at start
+            
+            // PHASE 2. Move up the LIMIT value through COMMON or single script until we get to expanse.limit
+            int lastScript = UScript.COMMON;
+            //int veryLastScript = UScript.COMMON;
+            limit = expanse.limit; 
+            for (i = current.limit; i < limit; i += UTF16.getCharCount(cp)) {
+                cp = text.char32At(i);
+                int scrpt = UScript.getScript(cp);
+                if (scrpt == UScript.INHERITED) scrpt = UScript.COMMON;
+                if (scrpt != UScript.COMMON) {
+                    // if we find a real script:
+                    //   if we already had a script, bail
+                    //   otherwise set our script
+                    if (lastScript == UScript.COMMON) lastScript = scrpt;
+                    else if (lastScript != scrpt) break;
+                }
+            }
+            current.limit = i;
+            current.contextLimit = (i == limit) ? expanse.contextLimit : i; // extend at end
+            done = (i == limit);
+            script = lastScript;
+            
+            if (DEBUG) {
+                System.out.println("-cs: " + current.contextStart
+                    + ", s: " + current.start
+                    + ", l: " + current.limit
+                    + ", cl: " + current.contextLimit);
+            }
+            
+            set(run, current);
+            return true;
+        }
+        
+        // SHOULD BE METHOD ON POSITION
+        public static void set(Position run, Position current) {
+            run.contextStart = current.contextStart;
+            run.start = current.start;
+            run.limit = current.limit;
+            run.contextLimit = current.contextLimit;
+        }
+        
+        public boolean atEnd() {
+            return current.limit == expanse.limit;
+        }
+        
+        public void getCurrent(Position run) {
+            set(run, current);
+        }
+        
+        public void getExpanse(Position run) {
+            set(run, expanse);
+        }
+        
+        public String getName() {
+            return UScript.getName(script);
+        }
+        
+        public void adjust(int newCurrentLimit) {
+            if (expanse == null) {
+                throw new IllegalArgumentException("Must reset() before calling");
+            }
+            int delta = newCurrentLimit - current.limit;
+            current.limit += delta;
+            current.contextLimit += delta;
+            expanse.limit += delta;
+            expanse.contextLimit += delta;
+        }
+        
+        // register Any-Script for every script.
+        
+        private static Set scriptList = new HashSet();
+        
+        public static void registerAnyToScript() {
+            synchronized (scriptList) {
+                Enumeration sources = Transliterator.getAvailableSources();
+                while(sources.hasMoreElements()) {
+                    String source = (String) sources.nextElement();
+                    if (source.equals("Any")) continue; // to keep from looping
+                    
+                    Enumeration targets = Transliterator.getAvailableTargets(source);
+                    while(targets.hasMoreElements()) {
+                        String target = (String) targets.nextElement();
+                        if (UScript.getCode(target) == null) continue; // SKIP unless we have a script (or locale)
+                        if (scriptList.contains(target)) continue; // already encountered
+                        scriptList.add(target); // otherwise add for later testing
+                        
+                        Set variantSet = add(new TreeSet(), Transliterator.getAvailableVariants(source, target));
+                        if (variantSet.size() < 2) {
+                            AnyTransliterator at = new AnyTransliterator(target, null);
+                            DummyFactory.add(at.getID(), at);
+                        } else {
+                            Iterator variants = variantSet.iterator();
+                            while(variants.hasNext()) {
+                                String variant = (String) variants.next();
+                                AnyTransliterator at = new AnyTransliterator(
+                                    (variant.length() > 0) ? target + "/" + variant : target, null);
+                                DummyFactory.add(at.getID(), at);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        
+        static class DummyFactory implements Transliterator.Factory {
+            static DummyFactory singleton = new DummyFactory();
+            static HashMap m = new HashMap();
+
+            // Since Transliterators are immutable, we don't have to clone on set & get
+            static void add(String ID, Transliterator t) {
+                m.put(ID, t);
+                System.out.println("Registering: " + ID + ", " + t.toRules(true));
+                Transliterator.registerFactory(ID, singleton);
+            }
+            public Transliterator getInstance(String ID) {
+                return (Transliterator) m.get(ID);
+            }
+        }
+        
+        // Nice little Utility for converting Enumeration to collection
+        static Set add(Set s, Enumeration enumeration) {
+            while(enumeration.hasMoreElements()) {
+                s.add(enumeration.nextElement());
+            }
+            return s;
+        }
+        
+        
+    }
+}
diff --git a/demos/src/com/ibm/icu/dev/demo/translit/CaseIterator.java b/demos/src/com/ibm/icu/dev/demo/translit/CaseIterator.java
new file mode 100644
index 0000000..0e70659
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/translit/CaseIterator.java
@@ -0,0 +1,554 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2007, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*/
+
+package com.ibm.icu.dev.demo.translit;
+import java.util.*;
+import com.ibm.icu.lang.UCharacter;
+import com.ibm.icu.text.UTF16;
+import com.ibm.icu.text.Transliterator;
+import com.ibm.icu.text.UnicodeSet;
+
+/**
+ * Incrementally returns the set of all strings that case-fold to the same value.
+ */
+public class CaseIterator {
+    
+    // testing stuff
+    static Transliterator toName = Transliterator.getInstance("[:^ascii:] Any-Name");
+    static Transliterator toHex = Transliterator.getInstance("[:^ascii:] Any-Hex");
+    static Transliterator toHex2 = Transliterator.getInstance("[[^\u0021-\u007F]-[,]] Any-Hex");
+    
+    // global tables (could be precompiled)
+    private static Map fromCaseFold = new HashMap();
+    private static Map toCaseFold = new HashMap();
+    private static int maxLength = 0;
+    
+    // This exception list is generated on the console by turning on the GENERATED flag, 
+    // which MUST be false for normal operation.
+    // Once the list is generated, it is pasted in here.
+    // A bit of a cludge, but this bootstrapping is the easiest way 
+    // to get around certain complications in the data.
+    
+    private static final boolean GENERATE = false;
+
+    private static final boolean DUMP = false;
+    
+    private static String[][] exceptionList = {
+        // a\N{MODIFIER LETTER RIGHT HALF RING}
+        {"a\u02BE","A\u02BE","a\u02BE",},
+        // ff
+        {"ff","FF","Ff","fF","ff",},
+        // ffi
+        {"ffi","FFI","FFi","FfI","Ffi","F\uFB01","fFI","fFi","ffI","ffi","f\uFB01","\uFB00I","\uFB00i",},
+        // ffl
+        {"ffl","FFL","FFl","FfL","Ffl","F\uFB02","fFL","fFl","ffL","ffl","f\uFB02","\uFB00L","\uFB00l",},
+        // fi
+        {"fi","FI","Fi","fI","fi",},
+        // fl
+        {"fl","FL","Fl","fL","fl",},
+        // h\N{COMBINING MACRON BELOW}
+        {"h\u0331","H\u0331","h\u0331",},
+        // i\N{COMBINING DOT ABOVE}
+        {"i\u0307","I\u0307","i\u0307",},
+        // j\N{COMBINING CARON}
+        {"j\u030C","J\u030C","j\u030C",},
+        // ss
+        {"ss","SS","Ss","S\u017F","sS","ss","s\u017F","\u017FS","\u017Fs","\u017F\u017F",},
+        // st
+        {"st","ST","St","sT","st","\u017FT","\u017Ft",},
+        // t\N{COMBINING DIAERESIS}
+        {"t\u0308","T\u0308","t\u0308",},
+        // w\N{COMBINING RING ABOVE}
+        {"w\u030A","W\u030A","w\u030A",},
+        // y\N{COMBINING RING ABOVE}
+        {"y\u030A","Y\u030A","y\u030A",},
+        // \N{MODIFIER LETTER APOSTROPHE}n
+        {"\u02BCn","\u02BCN","\u02BCn",},
+        // \N{GREEK SMALL LETTER ALPHA WITH TONOS}\N{GREEK SMALL LETTER IOTA}
+        {"\u03AC\u03B9","\u0386\u0345","\u0386\u0399","\u0386\u03B9","\u0386\u1FBE","\u03AC\u0345","\u03AC\u0399","\u03AC\u03B9","\u03AC\u1FBE",},
+        // \N{GREEK SMALL LETTER ETA WITH TONOS}\N{GREEK SMALL LETTER IOTA}
+        {"\u03AE\u03B9","\u0389\u0345","\u0389\u0399","\u0389\u03B9","\u0389\u1FBE","\u03AE\u0345","\u03AE\u0399","\u03AE\u03B9","\u03AE\u1FBE",},
+        // \N{GREEK SMALL LETTER ALPHA}\N{COMBINING GREEK PERISPOMENI}
+        {"\u03B1\u0342","\u0391\u0342","\u03B1\u0342",},
+        // \N{GREEK SMALL LETTER ALPHA}\N{COMBINING GREEK PERISPOMENI}\N{GREEK SMALL LETTER IOTA}
+        {"\u03B1\u0342\u03B9","\u0391\u0342\u0345","\u0391\u0342\u0399","\u0391\u0342\u03B9","\u0391\u0342\u1FBE",
+            "\u03B1\u0342\u0345","\u03B1\u0342\u0399","\u03B1\u0342\u03B9","\u03B1\u0342\u1FBE","\u1FB6\u0345",
+            "\u1FB6\u0399","\u1FB6\u03B9","\u1FB6\u1FBE",},
+        // \N{GREEK SMALL LETTER ALPHA}\N{GREEK SMALL LETTER IOTA}
+        {"\u03B1\u03B9","\u0391\u0345","\u0391\u0399","\u0391\u03B9","\u0391\u1FBE","\u03B1\u0345","\u03B1\u0399","\u03B1\u03B9","\u03B1\u1FBE",},
+        // \N{GREEK SMALL LETTER ETA}\N{COMBINING GREEK PERISPOMENI}
+        {"\u03B7\u0342","\u0397\u0342","\u03B7\u0342",},
+        // \N{GREEK SMALL LETTER ETA}\N{COMBINING GREEK PERISPOMENI}\N{GREEK SMALL LETTER IOTA}
+        {"\u03B7\u0342\u03B9","\u0397\u0342\u0345","\u0397\u0342\u0399","\u0397\u0342\u03B9","\u0397\u0342\u1FBE",
+            "\u03B7\u0342\u0345","\u03B7\u0342\u0399","\u03B7\u0342\u03B9","\u03B7\u0342\u1FBE","\u1FC6\u0345","\u1FC6\u0399",
+            "\u1FC6\u03B9","\u1FC6\u1FBE",},
+        // \N{GREEK SMALL LETTER ETA}\N{GREEK SMALL LETTER IOTA}
+        {"\u03B7\u03B9","\u0397\u0345","\u0397\u0399","\u0397\u03B9","\u0397\u1FBE","\u03B7\u0345","\u03B7\u0399","\u03B7\u03B9","\u03B7\u1FBE",},
+        // \N{GREEK SMALL LETTER IOTA}\N{COMBINING DIAERESIS}\N{COMBINING GRAVE ACCENT}
+        {"\u03B9\u0308\u0300","\u0345\u0308\u0300","\u0399\u0308\u0300","\u03B9\u0308\u0300","\u1FBE\u0308\u0300",},
+        // \N{GREEK SMALL LETTER IOTA}\N{COMBINING DIAERESIS}\N{COMBINING ACUTE ACCENT}
+        {"\u03B9\u0308\u0301","\u0345\u0308\u0301","\u0399\u0308\u0301","\u03B9\u0308\u0301","\u1FBE\u0308\u0301",},
+        // \N{GREEK SMALL LETTER IOTA}\N{COMBINING DIAERESIS}\N{COMBINING GREEK PERISPOMENI}
+        {"\u03B9\u0308\u0342","\u0345\u0308\u0342","\u0399\u0308\u0342","\u03B9\u0308\u0342","\u1FBE\u0308\u0342",},
+        // \N{GREEK SMALL LETTER IOTA}\N{COMBINING GREEK PERISPOMENI}
+        {"\u03B9\u0342","\u0345\u0342","\u0399\u0342","\u03B9\u0342","\u1FBE\u0342",},
+        // \N{GREEK SMALL LETTER RHO}\N{COMBINING COMMA ABOVE}
+        {"\u03C1\u0313","\u03A1\u0313","\u03C1\u0313","\u03F1\u0313",},
+        // \N{GREEK SMALL LETTER UPSILON}\N{COMBINING DIAERESIS}\N{COMBINING GRAVE ACCENT}
+        {"\u03C5\u0308\u0300","\u03A5\u0308\u0300","\u03C5\u0308\u0300",},
+        // \N{GREEK SMALL LETTER UPSILON}\N{COMBINING DIAERESIS}\N{COMBINING ACUTE ACCENT}
+        {"\u03C5\u0308\u0301","\u03A5\u0308\u0301","\u03C5\u0308\u0301",},
+        // \N{GREEK SMALL LETTER UPSILON}\N{COMBINING DIAERESIS}\N{COMBINING GREEK PERISPOMENI}
+        {"\u03C5\u0308\u0342","\u03A5\u0308\u0342","\u03C5\u0308\u0342",},
+        // \N{GREEK SMALL LETTER UPSILON}\N{COMBINING COMMA ABOVE}
+        {"\u03C5\u0313","\u03A5\u0313","\u03C5\u0313",},
+        // \N{GREEK SMALL LETTER UPSILON}\N{COMBINING COMMA ABOVE}\N{COMBINING GRAVE ACCENT}
+        {"\u03C5\u0313\u0300","\u03A5\u0313\u0300","\u03C5\u0313\u0300","\u1F50\u0300",},
+        // \N{GREEK SMALL LETTER UPSILON}\N{COMBINING COMMA ABOVE}\N{COMBINING ACUTE ACCENT}
+        {"\u03C5\u0313\u0301","\u03A5\u0313\u0301","\u03C5\u0313\u0301","\u1F50\u0301",},
+        // \N{GREEK SMALL LETTER UPSILON}\N{COMBINING COMMA ABOVE}\N{COMBINING GREEK PERISPOMENI}
+        {"\u03C5\u0313\u0342","\u03A5\u0313\u0342","\u03C5\u0313\u0342","\u1F50\u0342",},
+        // \N{GREEK SMALL LETTER UPSILON}\N{COMBINING GREEK PERISPOMENI}
+        {"\u03C5\u0342","\u03A5\u0342","\u03C5\u0342",},
+        // \N{GREEK SMALL LETTER OMEGA}\N{COMBINING GREEK PERISPOMENI}
+        {"\u03C9\u0342","\u03A9\u0342","\u03C9\u0342","\u2126\u0342",},
+        // \N{GREEK SMALL LETTER OMEGA}\N{COMBINING GREEK PERISPOMENI}\N{GREEK SMALL LETTER IOTA}
+        {"\u03C9\u0342\u03B9","\u03A9\u0342\u0345","\u03A9\u0342\u0399","\u03A9\u0342\u03B9","\u03A9\u0342\u1FBE","\u03C9\u0342\u0345","\u03C9\u0342\u0399","\u03C9\u0342\u03B9","\u03C9\u0342\u1FBE","\u1FF6\u0345",
+            "\u1FF6\u0399","\u1FF6\u03B9","\u1FF6\u1FBE","\u2126\u0342\u0345","\u2126\u0342\u0399","\u2126\u0342\u03B9","\u2126\u0342\u1FBE",},
+        // \N{GREEK SMALL LETTER OMEGA}\N{GREEK SMALL LETTER IOTA}
+        {"\u03C9\u03B9","\u03A9\u0345","\u03A9\u0399","\u03A9\u03B9","\u03A9\u1FBE","\u03C9\u0345","\u03C9\u0399","\u03C9\u03B9","\u03C9\u1FBE","\u2126\u0345","\u2126\u0399","\u2126\u03B9","\u2126\u1FBE",},
+        // \N{GREEK SMALL LETTER OMEGA WITH TONOS}\N{GREEK SMALL LETTER IOTA}
+        {"\u03CE\u03B9","\u038F\u0345","\u038F\u0399","\u038F\u03B9","\u038F\u1FBE","\u03CE\u0345","\u03CE\u0399","\u03CE\u03B9","\u03CE\u1FBE",},
+        // \N{ARMENIAN SMALL LETTER ECH}\N{ARMENIAN SMALL LETTER YIWN}
+        {"\u0565\u0582","\u0535\u0552","\u0535\u0582","\u0565\u0552","\u0565\u0582",},
+        // \N{ARMENIAN SMALL LETTER MEN}\N{ARMENIAN SMALL LETTER ECH}
+        {"\u0574\u0565","\u0544\u0535","\u0544\u0565","\u0574\u0535","\u0574\u0565",},
+        // \N{ARMENIAN SMALL LETTER MEN}\N{ARMENIAN SMALL LETTER INI}
+        {"\u0574\u056B","\u0544\u053B","\u0544\u056B","\u0574\u053B","\u0574\u056B",},
+        // \N{ARMENIAN SMALL LETTER MEN}\N{ARMENIAN SMALL LETTER XEH}
+        {"\u0574\u056D","\u0544\u053D","\u0544\u056D","\u0574\u053D","\u0574\u056D",},
+        // \N{ARMENIAN SMALL LETTER MEN}\N{ARMENIAN SMALL LETTER NOW}
+        {"\u0574\u0576","\u0544\u0546","\u0544\u0576","\u0574\u0546","\u0574\u0576",},
+        // \N{ARMENIAN SMALL LETTER VEW}\N{ARMENIAN SMALL LETTER NOW}
+        {"\u057E\u0576","\u054E\u0546","\u054E\u0576","\u057E\u0546","\u057E\u0576",},
+        // \N{GREEK SMALL LETTER ALPHA WITH PSILI}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F00\u03B9","\u1F00\u0345","\u1F00\u0399","\u1F00\u03B9","\u1F00\u1FBE","\u1F08\u0345","\u1F08\u0399","\u1F08\u03B9","\u1F08\u1FBE",},
+        // \N{GREEK SMALL LETTER ALPHA WITH DASIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F01\u03B9","\u1F01\u0345","\u1F01\u0399","\u1F01\u03B9","\u1F01\u1FBE","\u1F09\u0345","\u1F09\u0399","\u1F09\u03B9","\u1F09\u1FBE",},
+        // \N{GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F02\u03B9","\u1F02\u0345","\u1F02\u0399","\u1F02\u03B9","\u1F02\u1FBE","\u1F0A\u0345","\u1F0A\u0399","\u1F0A\u03B9","\u1F0A\u1FBE",},
+        // \N{GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F03\u03B9","\u1F03\u0345","\u1F03\u0399","\u1F03\u03B9","\u1F03\u1FBE","\u1F0B\u0345","\u1F0B\u0399","\u1F0B\u03B9","\u1F0B\u1FBE",},
+        // \N{GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F04\u03B9","\u1F04\u0345","\u1F04\u0399","\u1F04\u03B9","\u1F04\u1FBE","\u1F0C\u0345","\u1F0C\u0399","\u1F0C\u03B9","\u1F0C\u1FBE",},
+        // \N{GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F05\u03B9","\u1F05\u0345","\u1F05\u0399","\u1F05\u03B9","\u1F05\u1FBE","\u1F0D\u0345","\u1F0D\u0399","\u1F0D\u03B9","\u1F0D\u1FBE",},
+        // \N{GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F06\u03B9","\u1F06\u0345","\u1F06\u0399","\u1F06\u03B9","\u1F06\u1FBE","\u1F0E\u0345","\u1F0E\u0399","\u1F0E\u03B9","\u1F0E\u1FBE",},
+        // \N{GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F07\u03B9","\u1F07\u0345","\u1F07\u0399","\u1F07\u03B9","\u1F07\u1FBE","\u1F0F\u0345","\u1F0F\u0399","\u1F0F\u03B9","\u1F0F\u1FBE",},
+        // \N{GREEK SMALL LETTER ETA WITH PSILI}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F20\u03B9","\u1F20\u0345","\u1F20\u0399","\u1F20\u03B9","\u1F20\u1FBE","\u1F28\u0345","\u1F28\u0399","\u1F28\u03B9","\u1F28\u1FBE",},
+        // \N{GREEK SMALL LETTER ETA WITH DASIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F21\u03B9","\u1F21\u0345","\u1F21\u0399","\u1F21\u03B9","\u1F21\u1FBE","\u1F29\u0345","\u1F29\u0399","\u1F29\u03B9","\u1F29\u1FBE",},
+        // \N{GREEK SMALL LETTER ETA WITH PSILI AND VARIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F22\u03B9","\u1F22\u0345","\u1F22\u0399","\u1F22\u03B9","\u1F22\u1FBE","\u1F2A\u0345","\u1F2A\u0399","\u1F2A\u03B9","\u1F2A\u1FBE",},
+        // \N{GREEK SMALL LETTER ETA WITH DASIA AND VARIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F23\u03B9","\u1F23\u0345","\u1F23\u0399","\u1F23\u03B9","\u1F23\u1FBE","\u1F2B\u0345","\u1F2B\u0399","\u1F2B\u03B9","\u1F2B\u1FBE",},
+        // \N{GREEK SMALL LETTER ETA WITH PSILI AND OXIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F24\u03B9","\u1F24\u0345","\u1F24\u0399","\u1F24\u03B9","\u1F24\u1FBE","\u1F2C\u0345","\u1F2C\u0399","\u1F2C\u03B9","\u1F2C\u1FBE",},
+        // \N{GREEK SMALL LETTER ETA WITH DASIA AND OXIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F25\u03B9","\u1F25\u0345","\u1F25\u0399","\u1F25\u03B9","\u1F25\u1FBE","\u1F2D\u0345","\u1F2D\u0399","\u1F2D\u03B9","\u1F2D\u1FBE",},
+        // \N{GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F26\u03B9","\u1F26\u0345","\u1F26\u0399","\u1F26\u03B9","\u1F26\u1FBE","\u1F2E\u0345","\u1F2E\u0399","\u1F2E\u03B9","\u1F2E\u1FBE",},
+        // \N{GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F27\u03B9","\u1F27\u0345","\u1F27\u0399","\u1F27\u03B9","\u1F27\u1FBE","\u1F2F\u0345","\u1F2F\u0399","\u1F2F\u03B9","\u1F2F\u1FBE",},
+        // \N{GREEK SMALL LETTER OMEGA WITH PSILI}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F60\u03B9","\u1F60\u0345","\u1F60\u0399","\u1F60\u03B9","\u1F60\u1FBE","\u1F68\u0345","\u1F68\u0399","\u1F68\u03B9","\u1F68\u1FBE",},
+        // \N{GREEK SMALL LETTER OMEGA WITH DASIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F61\u03B9","\u1F61\u0345","\u1F61\u0399","\u1F61\u03B9","\u1F61\u1FBE","\u1F69\u0345","\u1F69\u0399","\u1F69\u03B9","\u1F69\u1FBE",},
+        // \N{GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F62\u03B9","\u1F62\u0345","\u1F62\u0399","\u1F62\u03B9","\u1F62\u1FBE","\u1F6A\u0345","\u1F6A\u0399","\u1F6A\u03B9","\u1F6A\u1FBE",},
+        // \N{GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F63\u03B9","\u1F63\u0345","\u1F63\u0399","\u1F63\u03B9","\u1F63\u1FBE","\u1F6B\u0345","\u1F6B\u0399","\u1F6B\u03B9","\u1F6B\u1FBE",},
+        // \N{GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F64\u03B9","\u1F64\u0345","\u1F64\u0399","\u1F64\u03B9","\u1F64\u1FBE","\u1F6C\u0345","\u1F6C\u0399","\u1F6C\u03B9","\u1F6C\u1FBE",},
+        // \N{GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F65\u03B9","\u1F65\u0345","\u1F65\u0399","\u1F65\u03B9","\u1F65\u1FBE","\u1F6D\u0345","\u1F6D\u0399","\u1F6D\u03B9","\u1F6D\u1FBE",},
+        // \N{GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F66\u03B9","\u1F66\u0345","\u1F66\u0399","\u1F66\u03B9","\u1F66\u1FBE","\u1F6E\u0345","\u1F6E\u0399","\u1F6E\u03B9","\u1F6E\u1FBE",},
+        // \N{GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F67\u03B9","\u1F67\u0345","\u1F67\u0399","\u1F67\u03B9","\u1F67\u1FBE","\u1F6F\u0345","\u1F6F\u0399","\u1F6F\u03B9","\u1F6F\u1FBE",},
+        // \N{GREEK SMALL LETTER ALPHA WITH VARIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F70\u03B9","\u1F70\u0345","\u1F70\u0399","\u1F70\u03B9","\u1F70\u1FBE","\u1FBA\u0345","\u1FBA\u0399","\u1FBA\u03B9","\u1FBA\u1FBE",},
+        // \N{GREEK SMALL LETTER ETA WITH VARIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F74\u03B9","\u1F74\u0345","\u1F74\u0399","\u1F74\u03B9","\u1F74\u1FBE","\u1FCA\u0345","\u1FCA\u0399","\u1FCA\u03B9","\u1FCA\u1FBE",},
+        // \N{GREEK SMALL LETTER OMEGA WITH VARIA}\N{GREEK SMALL LETTER IOTA}
+        {"\u1F7C\u03B9","\u1F7C\u0345","\u1F7C\u0399","\u1F7C\u03B9","\u1F7C\u1FBE","\u1FFA\u0345","\u1FFA\u0399","\u1FFA\u03B9","\u1FFA\u1FBE",},
+    };
+    
+    // this initializes the data used to generated the case-equivalents
+
+    static {
+        
+        // Gather up the exceptions in a form we can use
+        
+        if (!GENERATE) {
+            for (int i = 0; i < exceptionList.length; ++i) {
+                String[] exception = exceptionList[i];
+                Set s = new HashSet();
+                // there has to be some method to do the following, but I can't find it in the collections
+                for (int j = 0; j < exception.length; ++j) {
+                    s.add(exception[j]);
+                }
+                fromCaseFold.put(exception[0], s);
+            }
+        }
+        
+        // walk through all the characters, and at every case fold result,
+        // put a set of all the characters that map to that result
+
+        boolean defaultmapping = true; // false for turkish
+        for (int i = 0; i <= 0x10FFFF; ++i) {
+            int cat = UCharacter.getType(i);
+            if (cat == Character.UNASSIGNED || cat == Character.PRIVATE_USE) continue;
+            
+            String cp = UTF16.valueOf(i);
+            String mapped = UCharacter.foldCase(cp, defaultmapping);
+            if (mapped.equals(cp)) continue;
+            
+            if (maxLength < mapped.length()) maxLength = mapped.length();
+            
+            // at this point, have different case folding
+            
+            Set s = (Set) fromCaseFold.get(mapped);
+            if (s == null) {
+                s = new HashSet();
+                s.add(mapped); // add the case fold result itself
+                fromCaseFold.put(mapped, s);
+            }
+            s.add(cp);
+            toCaseFold.put(cp, mapped);
+            toCaseFold.put(mapped, mapped); // add mapping to self
+        }
+        
+        // Emit the final data
+
+        if (DUMP) {
+            System.out.println("maxLength = " + maxLength);
+
+            System.out.println("\nfromCaseFold:");
+            Iterator it = fromCaseFold.keySet().iterator();
+            while (it.hasNext()) {
+                Object key = it.next();
+                System.out.print(" " + toHex2.transliterate((String)key) + ": ");
+                Set s = (Set) fromCaseFold.get(key);
+                Iterator it2 = s.iterator();
+                boolean first = true;
+                while (it2.hasNext()) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        System.out.print(", ");
+                    }
+                    System.out.print(toHex2.transliterate((String)it2.next()));
+                }
+                System.out.println("");
+            }
+
+            System.out.println("\ntoCaseFold:");
+            it = toCaseFold.keySet().iterator();
+            while (it.hasNext()) {
+                String key = (String) it.next();
+                String value = (String) toCaseFold.get(key);
+                System.out.println(" " + toHex2.transliterate(key) + ": " + toHex2.transliterate(value));
+            }            
+        }
+        
+        // Now convert all those sets into linear arrays
+        // We can't do this in place in Java, so make a temporary target array
+        
+        // Note: This could be transformed into a single array, with offsets into it.
+        // Might be best choice in C.
+        
+        
+        Map fromCaseFold2 = new HashMap();
+        Iterator it = fromCaseFold.keySet().iterator();
+        while (it.hasNext()) {
+            Object key = it.next();
+            Set s = (Set) fromCaseFold.get(key);
+            String[] temp = new String[s.size()];
+            s.toArray(temp);
+            fromCaseFold2.put(key, temp);
+        }
+        fromCaseFold = fromCaseFold2;
+
+        // We have processed everything, so the iterator will now work
+        // The following is normally OFF. 
+        // It is here to generate (under the GENERATE flag) the static exception list.
+        // It must be at the very end of initialization, so that the iterator is functional.
+        // (easiest to do it that way)
+            
+        if (GENERATE) {
+
+            // first get small set of items that have multiple characters
+            
+            Set multichars = new TreeSet();
+            it = fromCaseFold.keySet().iterator();
+            while (it.hasNext()) {
+                String key = (String) it.next();
+                if (UTF16.countCodePoint(key) < 2) continue;
+                multichars.add(key);
+            }            
+            
+            // now we will go through each of them.
+            
+            CaseIterator ci = new CaseIterator();
+            it = multichars.iterator();
+            
+            while (it.hasNext()) {
+                String key = (String) it.next();
+                
+                // here is a nasty complication. Take 'ffi' ligature. We
+                // can't just close it, since we would miss the combination
+                // that includes the 'fi' => "fi" ligature
+                // so first do a pass through, and add substring combinations
+                // we call this a 'partial closure'
+                
+                Set partialClosure = new TreeSet();
+                partialClosure.add(key);
+                
+                if (UTF16.countCodePoint(key) > 2) {
+                    Iterator multiIt2 = multichars.iterator();
+                    while (multiIt2.hasNext()) {
+                        String otherKey = (String) multiIt2.next();
+                        if (otherKey.length() >= key.length()) continue;
+                        int pos = -1;
+                        while (true) {
+                            // The following is not completely general
+                            // but works for the actual cased stuff,
+                            // and should work for future characters, since we won't have
+                            // more ligatures & other oddities.
+                            pos = key.indexOf(otherKey, pos+1);
+                            if (pos < 0) break;
+                            int endPos = pos + otherKey.length();
+                            // we know we have a proper substring,
+                            // so get the combinations
+                            String[] choices = (String[]) fromCaseFold.get(otherKey);
+                            for (int ii = 0; ii < choices.length; ++ii) {
+                                String patchwork = key.substring(0, pos)
+                                    + choices[ii]
+                                    + key.substring(endPos);
+                                partialClosure.add(patchwork);
+                            }
+                        }
+                    }
+                }
+                
+                // now, for each thing in the partial closure, get its
+                // case closure and add it to the final result.
+                
+                Set closure = new TreeSet(); // this will be the real closure
+                Iterator partialIt = partialClosure.iterator();
+                while (partialIt.hasNext()) {
+                    String key2 = (String) partialIt.next();
+                    ci.reset(key2);
+                    for (String temp = ci.next(); temp != null; temp = ci.next()) {
+                        closure.add(temp);
+                    }
+                    // form closure
+                    /*String[] choices = (String[]) fromCaseFold.get(key2);
+                    for (int i = 0; i < choices.length; ++i) {
+                        ci.reset(choices[i]);
+                        String temp;
+                        while (null != (temp = ci.next())) {
+                            closure.add(temp);
+                        }
+                    }
+                    */
+                }
+                
+                // print it out, so that it can be cut and pasted back into this document.
+                
+                Iterator it2 = closure.iterator();
+                System.out.println("\t// " + toName.transliterate(key));
+                System.out.print("\t{\"" + toHex.transliterate(key) + "\",");
+                while (it2.hasNext()) {
+                    String item = (String)it2.next();
+                    System.out.print("\"" + toHex.transliterate(item) + "\",");
+                }
+                System.out.println("},");
+            }
+        }
+    }
+    
+    // ============ PRIVATE CLASS DATA ============ 
+    
+    // pieces that we will put together
+    // is not changed during iteration
+    private int count = 0;
+    private String[][] variants;
+    
+    // state information, changes during iteration
+    private boolean done = false;
+    private int[] counts;
+    
+    // internal buffer for efficiency
+    private StringBuffer nextBuffer = new StringBuffer();
+    
+    // ========================  
+
+    /**
+     * Reset to different source. Once reset, the iteration starts from the beginning.
+     * @param source The string to get case variants for
+     */
+    public void reset(String source) {
+        
+        // allocate arrays to store pieces
+        // using length might be slightly too long, but we don't care much
+        
+        counts = new int[source.length()];
+        variants = new String[source.length()][];
+        
+        // walk through the source, and break up into pieces
+        // each piece becomes an array of equivalent values
+        // TODO: could optimized this later to coalesce all single string pieces
+        
+        String piece = null;
+        count = 0;
+        for (int i = 0; i < source.length(); i += piece.length()) {
+            
+            // find *longest* matching piece
+            String caseFold = null;
+            
+            if (GENERATE) {
+                // do exactly one CP
+                piece = UTF16.valueOf(source, i);
+                caseFold = (String) toCaseFold.get(piece);
+            } else {               
+                int max = i + maxLength;
+                if (max > source.length()) max = source.length();
+                for (int j = max; j > i; --j) {
+                    piece = source.substring(i, j);
+                    caseFold = (String) toCaseFold.get(piece);
+                    if (caseFold != null) break;
+                }
+            }
+            
+            // if we fail, pick one code point
+            if (caseFold == null) {
+                piece = UTF16.valueOf(source, i);
+                variants[count++] = new String[] {piece}; // single item string
+            } else {
+                variants[count++] = (String[])fromCaseFold.get(caseFold);
+            }
+        }
+        reset();
+    }
+    
+    /**
+     * Restart the iteration from the beginning, but with same source
+     */
+    public void reset() {
+        done = false;
+        for (int i = 0; i < count; ++i) {
+            counts[i] = 0;
+        }
+    }
+    
+    /**
+     * Iterates through the case variants.
+     * @return next case variant. Each variant will case-fold to the same value as the source will.
+     * When the iteration is done, null is returned.
+     */
+    public String next() {
+        
+        if (done) return null;
+        int i;
+        
+        // TODO Optimize so we keep the piece before and after the current position
+        // so we don't have so much concatenation
+        
+        // get the result, a concatenation
+        
+        nextBuffer.setLength(0);
+        for (i = 0; i < count; ++i) {
+            nextBuffer.append(variants[i][counts[i]]);
+        }
+        
+        // find the next right set of pieces to concatenate
+        
+        for (i = count-1; i >= 0; --i) {
+            counts[i]++;
+            if (counts[i] < variants[i].length) break;
+            counts[i] = 0;
+        }
+        
+        // if we go too far, bail
+        
+        if (i < 0) {
+            done = true;
+        }
+        
+        return nextBuffer.toString();            
+    }
+        
+        
+    /**
+     * Temporary test, just to see how the stuff works.
+     */
+    static public void main(String[] args) {
+        String[] testCases = {"fiss", "h\u03a3"};
+        CaseIterator ci = new CaseIterator();
+        
+        for (int i = 0; i < testCases.length; ++i) {
+            String item = testCases[i];
+            System.out.println();
+            System.out.println("Testing: " + toName.transliterate(item));
+            System.out.println();
+            ci.reset(item);
+            int count = 0;
+            for (String temp = ci.next(); temp != null; temp = ci.next()) {
+                System.out.println(toName.transliterate(temp));
+                count++;
+            }
+            System.out.println("Total: " + count);
+        }
+
+        // generate a list of all caseless characters -- characters whose
+        // case closure is themselves.
+
+        UnicodeSet caseless = new UnicodeSet();
+
+        for (int i = 0; i <= 0x10FFFF; ++i) {
+            String cp = UTF16.valueOf(i);
+            ci.reset(cp);
+            int count = 0;
+            String fold = null;
+            for (String temp = ci.next(); temp != null; temp = ci.next()) {
+                fold = temp;
+                if (++count > 1) break;
+            }
+            if (count==1 && fold.equals(cp)) {
+                caseless.add(i);
+            }
+        }
+
+        System.out.println("caseless = " + caseless.toPattern(true));
+
+        UnicodeSet not_lc = new UnicodeSet("[:^lc:]");
+        
+        UnicodeSet a = new UnicodeSet();
+        a.set(not_lc);
+        a.removeAll(caseless);
+        System.out.println("[:^lc:] - caseless = " + a.toPattern(true));
+
+        a.set(caseless);
+        a.removeAll(not_lc);
+        System.out.println("caseless - [:^lc:] = " + a.toPattern(true));
+    }
+}
diff --git a/demos/src/com/ibm/icu/dev/demo/translit/Demo.java b/demos/src/com/ibm/icu/dev/demo/translit/Demo.java
new file mode 100644
index 0000000..718065e
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/translit/Demo.java
@@ -0,0 +1,1381 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2009, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.translit;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.text.CharacterIterator;
+
+import com.ibm.icu.impl.Differ;
+import com.ibm.icu.lang.*;
+import com.ibm.icu.text.*;
+
+import java.io.*;
+
+/**
+ * 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
+ */
+public class Demo extends Frame {
+
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = 1L;
+    static final boolean DEBUG = false;
+    static final String START_TEXT = "(cut,\u03BA\u03C5\u03C4,\u05D0,\u30AF\u30C8,\u4E80,\u091A\u0941\u0924\u094D)";
+
+    Transliterator translit = null;
+    String fontName = "Arial Unicode MS";
+    int fontSize = 18;
+    
+    
+
+    /*
+    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) {
+                com.ibm.icu.dev.demo.impl.DemoApplet.demoFrameClosed();
+//                System.exit(0);
+            }
+        });
+        f.setVisible(true);
+        com.ibm.icu.dev.demo.impl.DemoApplet.demoFrameOpened();
+    }
+
+    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(fontName, Font.PLAIN, fontSize);
+        text.setFont(font);
+        text.setSize(width, height);
+        text.setVisible(true);
+        text.setText(START_TEXT);
+        add(text);
+
+        setSize(width, height);
+        setTransliterator("Latin-Greek", null);
+    }
+
+    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());
+                }
+            }
+        };
+*/
+        /*
+        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);
+        }
+        */
+        
+        Menu fontMenu = new Menu("Font");
+        String[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
+        for (int i = 0; i < fonts.length; ++i) {
+            MenuItem mItem = new MenuItem(fonts[i]);
+            mItem.addActionListener(new FontActionListener(fonts[i]));
+            fontMenu.add(mItem);
+        }
+        mbar.add(fontMenu);
+        
+        Menu sizeMenu = new Menu("Size");
+        int[] sizes = {9, 10, 12, 14, 18, 24, 36, 48, 72};
+        for (int i = 0; i < sizes.length; ++i) {
+            MenuItem mItem = new MenuItem("" + sizes[i]);
+            mItem.addActionListener(new SizeActionListener(sizes[i]));
+            sizeMenu.add(mItem);
+        }
+        mbar.add(sizeMenu);
+        
+        translit = null;
+        
+        mbar.add(translitMenu = new Menu("Transliterator"));
+        
+        translitMenu.add(convertSelectionItem = new MenuItem("Transliterate", 
+            new MenuShortcut(KeyEvent.VK_K)));
+        convertSelectionItem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                handleBatchTransliterate(translit);
+            }
+        });
+        
+        translitMenu.add(swapSelectionItem = new MenuItem("Reverse", 
+            new MenuShortcut(KeyEvent.VK_S)));
+        swapSelectionItem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                Transliterator inv;
+                try {
+                    inv = translit.getInverse();
+                } catch (Exception x) {
+                    inv = Transliterator.getInstance("null");
+                }
+                setTransliterator(inv.getID(), null);
+            }
+        });
+        
+        translitMenu.add(convertTypingItem = new MenuItem("No Typing Conversion",
+            new MenuShortcut(KeyEvent.VK_T)));
+        convertTypingItem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                if (!transliterateTyping) {
+                    text.setTransliterator(translit);
+                    convertTypingItem.setLabel("No Typing Conversion");
+                } else {
+                    text.flush();
+                    text.setTransliterator(null);
+                    convertTypingItem.setLabel("Convert Typing");
+                }
+                transliterateTyping = !transliterateTyping;
+            }
+        });
+        
+        translitMenu.add(historyMenu = new Menu("Recent"));
+        
+        helpDialog = new InfoDialog(this, "Simple Demo", "Instructions",
+           "CTL A, X, C, V have customary meanings.\n"
+         + "Arrow keys, delete and backspace work.\n"
+         + "To get a character from its control point, type the hex, then hit CTL Q"
+        );
+        helpDialog.getArea().setEditable(false);
+        
+       
+        Menu helpMenu;
+        mbar.add(helpMenu = new Menu("Extras"));
+        helpMenu.add(mitem = new MenuItem("Help"));
+        mitem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                helpDialog.show();
+            }
+        });   
+        
+        hexDialog = new InfoDialog(this, "Hex Entry", "Use U+..., \\u..., \\x{...}, or &#x...;",
+           "\\u00E1"
+        );
+        Button button = new Button("Insert");
+        button.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                String hexValue = hexDialog.getArea().getText();
+                text.insertText(fromHex.transliterate(hexValue));
+            }
+        });
+        hexDialog.getBottom().add(button);
+        
+        helpMenu.add(mitem = new MenuItem("Hex...", 
+            new MenuShortcut(KeyEvent.VK_H)));
+        mitem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                hexDialog.show();
+            }
+        });
+        
+        // Compound Transliterator
+        
+        compoundDialog = new InfoDialog(this, "Compound Transliterator", "",
+           "[^\\u0000-\\u00FF] hex"
+        );
+        button = new Button("Set");
+        button.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                String compound = "";
+                try {
+                    compound = compoundDialog.getArea().getText();
+                    setTransliterator(compound, null);
+                } catch (RuntimeException ex) {
+                    compoundDialog.getArea().setText(compound + "\n" + ex.getMessage());
+                }
+            }
+        });
+        compoundDialog.getBottom().add(button);
+        
+        translitMenu.add(mitem = new MenuItem("Multiple...", 
+            new MenuShortcut(KeyEvent.VK_M)));
+        mitem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                compoundDialog.show();
+            }
+        });
+        
+        // RuleBased Transliterator
+        
+        rulesDialog = new InfoDialog(this, "Rule-Based Transliterator", "",
+           "([A-Z]) > &Hex($1) &Name($1);\r\n" 
+            + "&Hex-Any($1) < ('\\' [uU] [a-fA-F0-9]*);\r\n" 
+            + "&Name-Any($1) < ('{' [^\\}]* '}');"
+        );
+        button = new Button("Set");
+        button.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                String compound = "";
+                try {
+                    compound = rulesDialog.getArea().getText();
+                    String id = ruleId.getText();
+                    setTransliterator(compound, id);
+                } catch (RuntimeException ex) {
+                    rulesDialog.getArea().setText(compound + "\n#" + ex.getMessage());
+                }
+            }
+        });
+        rulesDialog.getBottom().add(button);
+        ruleId = new TextField("test1", 20);
+        Label temp = new Label(" Name:");
+        rulesDialog.getBottom().add(temp);
+        rulesDialog.getBottom().add(ruleId);
+        
+        
+        translitMenu.add(mitem = new MenuItem("From Rules...", 
+            new MenuShortcut(KeyEvent.VK_R)));
+        mitem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                rulesDialog.show();
+            }
+        });
+        
+        
+        translitMenu.add(mitem = new MenuItem("From File...", 
+            new MenuShortcut(KeyEvent.VK_F)));
+        mitem.addActionListener(new FileListener(this, RULE_FILE));
+        
+        translitMenu.add(mitem = new MenuItem("Test File..."));
+        mitem.addActionListener(new FileListener(this, TEST_FILE));
+        
+        // Flesh out the menu with the installed transliterators
+        
+        translitMenu.addSeparator();
+        
+        Iterator sources = add(new TreeSet(), Transliterator.getAvailableSources()).iterator();
+        while(sources.hasNext()) {
+            String source = (String) sources.next();
+            Iterator targets = add(new TreeSet(), Transliterator.getAvailableTargets(source)).iterator();
+            Menu targetMenu = new Menu(source);
+            while(targets.hasNext()) {
+                String target = (String) targets.next();
+                Set variantSet = add(new TreeSet(), Transliterator.getAvailableVariants(source, target));
+                if (variantSet.size() < 2) {
+                    mitem = new MenuItem(target);
+                    mitem.addActionListener(new TransliterationListener(source + "-" + target));
+                    targetMenu.add(mitem);
+                } else {
+                    Iterator variants = variantSet.iterator();
+                    Menu variantMenu = new Menu(target);
+                    while(variants.hasNext()) {
+                        String variant = (String) variants.next();
+                        String menuName = variant.length() == 0 ? "<default>" : variant;
+                        //System.out.println("<" + source + "-" + target + "/" + variant + ">, <" + menuName + ">");
+                        mitem = new MenuItem(menuName);
+                        mitem.addActionListener(new TransliterationListener(source + "-" + target + "/" + variant));
+                        variantMenu.add(mitem);
+                    }
+                    targetMenu.add(variantMenu);
+                }
+            }
+            translitMenu.add(targetMenu);
+        }
+        
+        
+    }
+    
+    static final int RULE_FILE = 0, TEST_FILE = 1;
+    //
+    static class FileListener implements ActionListener {
+        Demo frame;
+        int choice;
+        
+        FileListener(Demo frame, int choice) {
+            this.frame = frame;
+            this.choice = choice;
+        }
+        
+        public void actionPerformed(ActionEvent e) {
+            String id = frame.translit.getID();
+            int slashPos = id.indexOf('/');
+            String variant = "";
+            if (slashPos >= 0) {
+                variant = "_" + id.substring(slashPos+1);
+                id = id.substring(0, slashPos);
+            }
+            
+            FileDialog fileDialog = new FileDialog(frame, "Input File");
+            fileDialog.setFile("Test_" + id + ".txt");
+            fileDialog.show();
+            String fileName = fileDialog.getFile();
+            String fileDirectory = fileDialog.getDirectory();
+            if (fileName != null) {
+                try {
+                    File f = new File(fileDirectory, fileName);
+                    if (choice == RULE_FILE) {
+                        
+                        // read stuff into buffer
+                        
+                        StringBuffer buffer = new StringBuffer();
+                        FileInputStream fis = new FileInputStream(f);
+                        InputStreamReader isr = new InputStreamReader(fis, "UTF8");
+                        BufferedReader br = new BufferedReader(isr, 32*1024);
+                        while (true) {
+                            String line = br.readLine();
+                            if (line == null) break;
+                            if (line.length() > 0 && line.charAt(0) == '\uFEFF') line = line.substring(1); // strip BOM
+                            buffer.append('\n');
+                            buffer.append(line);
+                        }
+                        br.close();
+                        
+                        // Transform file name into id
+                        if (fileName.startsWith("Transliterator_")) {
+                            fileName = fileName.substring("Transliterator_".length());
+                        }
+                        int pos = fileName.indexOf('_');
+                        if (pos < 0) {
+                            id = fileName;
+                        } else {
+                            id = fileName.substring(0, pos) + "-";
+                            int pos2 = fileName.indexOf('_', pos+1);
+                            if (pos2 < 0) {
+                                id += fileName.substring(pos+1);
+                            } else {
+                                id += fileName.substring(pos+1, pos2) + "/" + fileName.substring(pos2 + 1);
+                            }
+                        }                        
+                        pos = id.lastIndexOf('.');
+                        if (pos >= 0) id = id.substring(0, pos);
+                        
+                        // Now set
+                        
+                        frame.setTransliterator(buffer.toString(), id);
+                    } else if (choice == TEST_FILE) {
+                        genTestFile(f, frame.translit, variant);
+                    }
+                } catch (Exception e2) {
+                    e2.printStackTrace();
+                    System.out.println("Problem opening/reading: " + fileDirectory + ", " + fileName);
+                }
+            }
+            fileDialog.dispose();
+        }
+    }
+    
+
+    boolean transliterateTyping = true;
+    Transliterator fromHex = Transliterator.getInstance("Hex-Any");
+    InfoDialog helpDialog;
+    InfoDialog hexDialog;
+    InfoDialog compoundDialog;
+    InfoDialog rulesDialog;
+    TextField ruleId;
+    MenuItem convertSelectionItem = null;
+    MenuItem swapSelectionItem = null;
+    MenuItem convertTypingItem = null;
+    Menu historyMenu;
+    Map historyMap = new HashMap();
+    Set historySet = new TreeSet(new Comparator() {
+            public int compare(Object a, Object b) {
+                MenuItem aa = (MenuItem)a;
+                MenuItem bb = (MenuItem)b;
+                return aa.getLabel().compareTo(bb.getLabel());
+            }
+        });
+        
+    // ADD Factory since otherwise getInverse blows out
+    static class DummyFactory implements Transliterator.Factory {
+        static DummyFactory singleton = new DummyFactory();
+        static HashMap m = new HashMap();
+
+        // Since Transliterators are immutable, we don't have to clone on set & get
+        static void add(String ID, Transliterator t) {
+            m.put(ID, t);
+            System.out.println("Registering: " + ID + ", " + t.toRules(true));
+            Transliterator.registerFactory(ID, singleton);
+        }
+        public Transliterator getInstance(String ID) {
+            return (Transliterator) m.get(ID);
+        }
+    }
+    
+    static void printBreaks(int num, String testSource, BreakIterator brkItr) {
+        String result = "";
+        int lastPos = 0;
+        while (true) {
+            int pos = brkItr.next();
+            if (pos == BreakIterator.DONE) break;
+            result += testSource.substring(lastPos, pos) + "&";
+            lastPos = pos;
+            System.out.println(pos);
+        }
+        System.out.println("Test" + num + ": " + result);
+    }
+    
+    static void printIteration(int num, String testSource, CharacterIterator ci) {
+        String result = "";
+        while (true) {
+            char ch = ci.next();
+            if (ch == CharacterIterator.DONE) break;
+            result += ch + "(" + ci.getIndex() + ")";
+        }
+        System.out.println("Test" + num + ": " + result);
+    }
+    
+    static void printSources() {
+        String[] list = {"Latin-ThaiLogical", "ThaiLogical-Latin", "Thai-ThaiLogical", "ThaiLogical-Thai"};
+        UnicodeSet all = new UnicodeSet();
+        for (int i = 0; i < list.length; ++i) {
+            Transliterator tr = Transliterator.getInstance(list[i]);
+            UnicodeSet src = tr.getSourceSet();
+            System.out.println(list[i] + ": " + src.toPattern(true));
+            all.addAll(src);
+        }
+        System.out.println("All: " + all.toPattern(true));
+        UnicodeSet rem = new UnicodeSet("[[:latin:][:thai:]]");
+        System.out.println("missing from [:latin:][:thai:]: " + all.removeAll(rem).toPattern(true));
+    }
+    
+    // 200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;;
+
+    static Transliterator title = Transliterator.getInstance("title");
+    static String hexAndNameRules = "    ([:c:]) > \\u200E &hex/unicode($1) ' ( ) ' &name($1) \\u200E ' ';"
+        + "([:mark:]) > \\u200E &hex/unicode($1) ' ( ' \\u200E \u25CC $1 \\u200E ' ) ' &name($1) \\u200E ' ';"
+        + "(.) > \\u200E &hex/unicode($1) ' ( ' \\u200E $1 \\u200E ' ) ' &name($1) ' ' \\u200E;";
+
+    static Transliterator hexAndName = Transliterator.createFromRules("any-hexAndName", 
+        hexAndNameRules, Transliterator.FORWARD);
+    
+
+
+    //static Transliterator upper = Transliterator.getInstance("upper");
+     
+    static final byte NONE = 0, TITLEWORD = 1, TITLELINE = 2;
+    
+    static void genTestFile(File sourceFile, Transliterator translit, String variant) {
+        try {
+            
+            System.out.println("Reading: " + sourceFile.getCanonicalPath());
+            BufferedReader in = new BufferedReader(
+                new InputStreamReader(
+                    new FileInputStream(sourceFile), "UTF-8"));
+            String targetFile = sourceFile.getCanonicalPath();
+            int dotPos = targetFile.lastIndexOf('.');
+            if (dotPos >= 0) targetFile = targetFile.substring(0,dotPos);
+            targetFile += variant;
+            
+            File outFile = new File(targetFile + ".html");
+            System.out.println("Writing: " + outFile.getCanonicalPath());
+            
+            PrintWriter out = new PrintWriter(
+                new BufferedWriter(
+                    new OutputStreamWriter(
+                        new FileOutputStream(outFile), "UTF-8")));
+                        
+            String direction = "";
+            String id = translit.getID();
+            if (id.indexOf("Arabic") >= 0 || id.indexOf("Hebrew") >= 0) {
+                direction = " direction: rtl;";
+            }
+            boolean testRoundTrip = true;
+            boolean generateSets = true;
+            if (id.startsWith("Han-") || id.startsWith("ja-")) {
+                testRoundTrip = false;
+                generateSets = false;
+            }
+            out.println("<head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'>");
+            out.println("<style><!--");
+            out.println("td, th       { vertical-align: top; border: 1px solid black }");
+            out.println("td.s       { background-color: #EEEEEE;" + direction + " }");
+            out.println("td.r       { background-color: #CCCCCC;" + direction + " }");
+            out.println("td.n       { background-color: #FFFFCC; }");
+            out.println("td.title       { border: 0px solid black}");
+            out.println("span.d       { background-color: #FF6666 }");
+            out.println("span.r       { background-color: #66FF66 }");
+
+            out.println("body         { font-family: 'Arial Unicode MS', 'Lucida Sans Unicode', Arial, sans-serif; margin: 5 }");
+            out.println("--></style>");
+            out.println("<title>" + id + " Transliteration Check</title></head>");
+            out.println("<body bgcolor='#FFFFFF'><p>See <a href='Test_Instructions.html'>Test_Instructions.html</a> for details.</p>");
+            out.println("<table>");
+            
+            //out.println("<tr><th width='33%'>Thai</th><th width='33%'>Latin</th><th width='33%'>Thai</th></tr>");
+  
+            Transliterator tl = translit;
+            Transliterator lt = tl.getInverse();
+            
+            Transliterator ltFilter = tl.getInverse();
+            ltFilter.setFilter(new UnicodeSet("[:^Lu:]"));
+            Transliterator tlFilter = lt.getInverse();
+            tlFilter.setFilter(new UnicodeSet("[:^Lu:]"));
+            
+            //Transliterator.getInstance("[:^Lu:]" +  lt.getID());
+            
+            BreakIterator sentenceBreak = BreakIterator.getSentenceInstance();
+            
+            byte titleSetting = TITLELINE;
+            //boolean upperfilter = false;
+            boolean first = true;
+            while (true) {
+                String line = in.readLine();
+                if (line == null) break;
+                line = line.trim();
+                if (line.length() == 0) continue;
+                if (line.charAt(0) == '\uFEFF') line = line.substring(1); // remove BOM
+                
+                if (line.charAt(0) == '#') continue; // comments
+                
+                if (line.equals("@TITLECASE@")) {
+                    titleSetting = TITLEWORD;
+                    out.println("<tr><td colspan='2' class='title'><b>Names</b></td></tr>");
+                    continue;
+                } else if (line.equals("@UPPERFILTER@")) {
+                    //upperfilter = true;
+                    continue;
+                } else if (line.startsWith("@SET")) {
+                    UnicodeSet s = new UnicodeSet(line.substring(4).trim());
+                    out.println("<tr><td colspan='2' class='title'><b>Characters</b></td></tr>");
+                    UnicodeSetIterator it = new UnicodeSetIterator(s);
+                    while (it.next()) {
+                        addSentenceToTable(out, it.codepoint != UnicodeSetIterator.IS_STRING 
+                            ? UTF16.valueOf(it.codepoint)
+                            : it.string,
+                            NONE, true, testRoundTrip, first, tl, lt);
+                    }
+                    continue;
+                }
+                        
+                sentenceBreak.setText(line);
+                int start = 0;
+                while (true) {
+                    int end = sentenceBreak.next();
+                    if (end == BreakIterator.DONE) break;
+                    String coreSentence = line.substring(start, end);
+                    //System.out.println("Core: " + hex.transliterate(coreSentence));
+                    end = start;
+                    
+                    int oldPos = 0;
+                    while (oldPos < coreSentence.length()) {
+                        // hack, because sentence doesn't seem to be working right
+                        int pos = coreSentence.indexOf(". ", oldPos);
+                        if (pos < 0) pos = coreSentence.length(); else pos = pos+2;
+                        int pos2 = coreSentence.indexOf('\u3002', oldPos);
+                        if (pos2 < 0) pos2 = coreSentence.length(); else pos2 = pos2 + 1;
+                        if (pos > pos2) pos = pos2;
+                        String sentence = coreSentence.substring(oldPos, pos).trim();
+                        //System.out.println("Sentence: " + hex.transliterate(coreSentence));
+                        oldPos = pos;
+                        
+                        addSentenceToTable(out, sentence,
+                            titleSetting, false, testRoundTrip, first, tl, lt);
+                        
+                        first = false;
+                    }
+                }
+            }
+            out.println("</table></body>");
+            out.close();
+            
+            // Now write the source/target sets
+            if (generateSets) {
+                outFile = new File(targetFile + "_Sets.html");
+                System.out.println("Writing: " + outFile.getCanonicalPath());
+                
+                out = new PrintWriter(
+                    new BufferedWriter(
+                        new OutputStreamWriter(
+                            new FileOutputStream(outFile), "UTF-8")));
+                out.println("<head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'>");
+                out.println("<style><!--");
+                out.println("body         { font-family: 'Arial Unicode MS', 'Lucida Sans Unicode', Arial, sans-serif; margin: 5 }");
+                out.println("--></style>");
+                out.println("<title>" + id + " Transliteration Sets</title></head>");
+                out.println("<body bgcolor='#FFFFFF'>");
+                
+                int dashPos = id.indexOf('-');
+                int slashPos = id.indexOf('/');
+                if (slashPos < 0) slashPos = id.length();
+                UnicodeSet sourceSuper = null;
+                try {
+                    String temp = id.substring(0,dashPos);
+                    if (temp.equals("ja")) sourceSuper = new UnicodeSet("[[:Han:][:hiragana:][:katakana:]]");
+                    else sourceSuper = new UnicodeSet("[[:" + temp + ":][:Mn:][:Me:]]");
+                } catch (Exception e) {}
+                
+                UnicodeSet targetSuper = null;
+                try {
+                    targetSuper = new UnicodeSet("[[:" + id.substring(dashPos+1, slashPos) + ":][:Mn:][:Me:]]");
+                } catch (Exception e) {}
+                
+                int nfdStyle = CLOSE_CASE | CLOSE_FLATTEN | CLOSE_CANONICAL;
+                int nfkdStyle = nfdStyle | CLOSE_COMPATIBILITY;
+                out.println("<ul>");
+                out.println("<p><b>None</b></p>");
+                showSets(out, translit, lt, null, null, 0);
+                out.println("<p><b>NFD</b></p>");
+                showSets(out, translit, lt, sourceSuper, targetSuper, nfdStyle);
+                out.println("<p><b>NFKD</b></p>");
+                showSets(out, translit, lt, sourceSuper, targetSuper, nfkdStyle);
+                out.println("</ul></body>");
+                out.close();
+            }
+            System.out.println("Done Writing");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    
+    static void addSentenceToTable(PrintWriter out, String sentence, 
+            byte titleSetting, boolean addName, boolean testRoundTrip, boolean first,
+            Transliterator tl, Transliterator lt) {
+        if (sentence.length() == 0) return; // skip empty lines
+        
+        String originalShow = sentence;
+        String latin;
+        latin = tl.transliterate(saveAscii.transliterate(sentence));
+
+        String latinShow = latin;
+        if (titleSetting == TITLEWORD) {
+            latinShow = title.transliterate(latin);
+        } else if (titleSetting == TITLELINE) {
+            latinShow = titlecaseFirstWord(latinShow);
+        }
+        latinShow = restoreAscii.transliterate(latinShow);
+                        
+        String reverse;
+        reverse = restoreAscii.transliterate(lt.transliterate(latin));
+                        
+        String NFKDSentence = Normalizer.normalize(sentence, Normalizer.NFKD);
+        String NFKDLatin = Normalizer.normalize(latin, Normalizer.NFKD);
+        String NFKDReverse = Normalizer.normalize(reverse, Normalizer.NFKD);
+        
+        if (latinShow.length() == 0) {
+            latinShow = "<i>empty</i>";
+        } else if (NFKDSentence.equals(NFKDLatin)) {
+            latinShow = "<span class='r'>" + latinShow + "</span>";
+        }
+        String reverseShow = reverse;
+        
+        if (testRoundTrip && !NFKDReverse.equals(NFKDSentence)) {
+            int minLen = reverse.length();
+            if (minLen > sentence.length()) minLen = sentence.length();
+            int i;
+            for (i = 0; i < minLen; ++i) {
+                if (reverse.charAt(i) != sentence.charAt(i)) break;
+            }
+            //originalShow = sentence.substring(0,i) + "<span class='d'>" + sentence.substring(i) + "</span>";
+            reverseShow = reverseShow.length() == 0 
+                ? "<i>empty</i>" 
+                //: reverse.substring(0,i) + "<span class='d'>" + reverse.substring(i) + "</span>";
+                : showDifference(sentence, reverse);
+            out.println("<tr><td class='s'" + (first ? " width='50%'>" : ">") + originalShow 
+                + "</td><td rowSpan='2'>" + latinShow
+                + "</td></tr><tr><td class='r'>" + reverseShow
+                + "</td></tr>");
+        } else {
+            out.println("<tr><td class='s'" + (first ? " width='50%'>" : ">") + originalShow 
+                + "</td><td>" + latinShow
+                + "</td></tr>");
+        }
+        if (addName) {
+            latinShow = hexAndName.transliterate(latin);
+            if (latinShow.length() == 0) latinShow = "<i>empty</i>";
+            originalShow = hexAndName.transliterate(sentence);
+            if (originalShow.length() == 0) originalShow = "<i>empty</i>";
+
+            out.println("<tr><td class='n'>" + originalShow
+                + "</td><td class='n'>" + latinShow
+                + "</td></tr>");
+        }
+        out.println("<tr><td></td></tr>");
+        
+    }
+    
+    static String showDifference(String as, String bs) {
+        Differ differ = new Differ(300, 3);
+        StringBuffer out = new StringBuffer();
+        int max = as.length();
+        if (max < bs.length()) max = bs.length();
+        for (int j = 0; j <= max; ++j) {
+            if (j < as.length()) differ.addA(as.substring(j, j+1));
+            if (j < bs.length()) differ.addB(bs.substring(j, j+1));
+            differ.checkMatch(j == max);
+
+            if (differ.getACount() != 0 || differ.getBCount() != 0) {
+                out.append("...");
+                if (differ.getACount() != 0) {
+                    out.append("<span class='r'>");
+                    for (int i = 0; i < differ.getACount(); ++i) {
+                        out.append(differ.getA(i));
+                    }
+                    out.append("</span>");
+                }
+                if (differ.getBCount() != 0) {
+                    out.append("<span class='d'>");
+                    for (int i = 0; i < differ.getBCount(); ++i) {
+                        out.append(differ.getB(i));
+                    }
+                    out.append("</span>");
+                }
+                out.append("...");
+            }
+        }
+        return out.toString();
+    }
+    
+    static void showSets(PrintWriter out, Transliterator translit, Transliterator inverse,
+      UnicodeSet sourceSuper, UnicodeSet targetSuper, int options) {
+        out.println("<li>Source Set:<ul><li>" +         toPattern(closeUnicodeSet(translit.getSourceSet(), options), sourceSuper) + "</li></ul></li>");
+        out.println("<li>Reverse Target Set:<ul><li>" + toPattern(closeUnicodeSet(inverse.getTargetSet(),  options), sourceSuper) + "</li></ul></li>");
+        out.println("<li>Target Set:<ul><li>" +         toPattern(closeUnicodeSet(translit.getTargetSet(), options), targetSuper) + "</li></ul></li>");
+        out.println("<li>Reverse Source Set:<ul><li>" + toPattern(closeUnicodeSet(inverse.getSourceSet(),  options), targetSuper) + "</li></ul></li>");
+    }
+        
+    static final int CLOSE_CASE = 1, CLOSE_FLATTEN = 2, CLOSE_CANONICAL = 4, CLOSE_COMPATIBILITY = 8;
+    
+    static UnicodeSet closeUnicodeSet(UnicodeSet source, int options) {
+        if (options == 0) return source;
+        
+        UnicodeSetIterator it = new UnicodeSetIterator(source);
+        UnicodeSet additions = new UnicodeSet(); // to avoid messing up iterator
+        UnicodeSet removals = new UnicodeSet(); // to avoid messing up iterator
+        String base;
+        int cp;
+        
+        // Add all case equivalents
+        if ((options & CLOSE_CASE) != 0) {
+            while (it.next()) {
+                cp = it.codepoint;
+                if (cp == UnicodeSetIterator.IS_STRING) continue;
+                int type = UCharacter.getType(cp);
+                if (type == Character.UPPERCASE_LETTER || type == Character.LOWERCASE_LETTER || type == Character.TITLECASE_LETTER) {
+                    additions.add(UCharacter.toLowerCase(UTF16.valueOf(cp)));
+                    additions.add(UCharacter.toUpperCase(UTF16.valueOf(cp)));
+                }
+            }
+            source.addAll(additions);
+        }
+       
+        // Add the canonical closure of all strings and characters in source
+        if ((options & CLOSE_CANONICAL) != 0) {
+            it.reset();
+            additions.clear();
+            CanonicalIterator ci = new CanonicalIterator(".");
+            while (it.next()) {
+                if (it.codepoint == UnicodeSetIterator.IS_STRING) base = it.string;
+                else base = UTF16.valueOf(it.codepoint);
+                ci.setSource(base);
+                while (true) {
+                    String trial = ci.next();
+                    if (trial == null) break;
+                    if (trial.equals(base)) continue;
+                    additions.add(trial);
+                }
+            }
+            source.addAll(additions);
+        }
+
+        // flatten strings
+        if ((options & CLOSE_FLATTEN) != 0) {
+            it.reset();
+            additions.clear();
+            while (it.next()) {
+                if (it.codepoint != UnicodeSetIterator.IS_STRING) continue;
+                additions.addAll(it.string);
+                removals.add(it.string);
+                //System.out.println("flattening '" + hex.transliterate(it.string) + "'");
+            }
+            source.addAll(additions);
+            source.removeAll(removals);
+        }
+       
+        // Now add decompositions of characters in source
+        if ((options & CLOSE_COMPATIBILITY) != 0) {
+            it.reset(source);
+            additions.clear();
+            while (it.next()) {
+                if (it.codepoint == UnicodeSetIterator.IS_STRING) base = it.string;
+                else base = UTF16.valueOf(it.codepoint);
+                if (Normalizer.isNormalized(base, Normalizer.NFKD,0)) continue;
+                String decomp = Normalizer.normalize(base, Normalizer.NFKD);
+                additions.add(decomp);
+            }
+            source.addAll(additions);
+            
+            // Now add any other character that decomposes to a character in source
+            for (cp = 0; cp < 0x10FFFF; ++cp) {
+                if (!UCharacter.isDefined(cp)) continue;
+                if (Normalizer.isNormalized(cp, Normalizer.NFKD,0)) continue;
+                if (source.contains(cp)) continue;
+                
+                String decomp = Normalizer.normalize(cp, Normalizer.NFKD);
+                if (source.containsAll(decomp)) {
+                    // System.out.println("Adding: " + Integer.toString(cp,16) + " " + UCharacter.getName(cp));
+                    source.add(cp);
+                }
+            }
+        }
+        
+        return source;
+    }
+    
+    static String toPattern(UnicodeSet source, UnicodeSet superset) {
+        if (superset != null) {
+            source.removeAll(superset);
+            return "[" + superset.toPattern(true) + " " + source.toPattern(true) + "]";
+        }
+        return source.toPattern(true);
+    }
+    
+    static BreakIterator bi = BreakIterator.getWordInstance();
+    
+    static String titlecaseFirstWord(String line) {
+        // search for first word with letters. If the first letter is lower, then titlecase it.
+        bi.setText(line);
+        int start = 0;
+        while (true) {
+            int end = bi.next();
+            if (end == BreakIterator.DONE) break;
+            int firstLetterType = getFirstLetterType(line, start, end);
+            if (firstLetterType != Character.UNASSIGNED) {
+                if (firstLetterType != Character.LOWERCASE_LETTER) break;
+                line = line.substring(0, start) 
+                    + UCharacter.toTitleCase(line.substring(start, end), bi)
+                    + line.substring(end);
+                break;
+            }
+            end = start;
+        }
+        return line;
+    }
+    
+    static final int LETTER_MASK = 
+          (1<<Character.UPPERCASE_LETTER)
+        | (1<<Character.LOWERCASE_LETTER)
+        | (1<<Character.TITLECASE_LETTER)
+        | (1<<Character.MODIFIER_LETTER)
+        | (1<<Character.OTHER_LETTER)
+        ;
+    
+    static int getFirstLetterType(String line, int start, int end) {
+        int cp;
+        for (int i = start; i < end; i += UTF16.getCharCount(cp)) {
+            cp = UTF16.charAt(line, i);
+            int type = UCharacter.getType(cp);
+            if (((1<<type) & LETTER_MASK) != 0) return type;
+        }
+        return Character.UNASSIGNED;
+    }
+    
+    static void printNames(UnicodeSet s, String targetFile) {
+        try {
+            File outFile = new File(targetFile);
+            System.out.println("Writing: " + outFile.getCanonicalPath());
+                
+            PrintWriter out = new PrintWriter(
+                new BufferedWriter(
+                    new OutputStreamWriter(
+                        new FileOutputStream(outFile), "UTF-8")));
+            UnicodeSet main = new UnicodeSet();
+            
+            UnicodeSet others = new UnicodeSet();
+            UnicodeSetIterator it = new UnicodeSetIterator(s);
+            while (it.next()) {
+                if (!UCharacter.isDefined(it.codepoint)) continue;
+                if (!Normalizer.isNormalized(it.codepoint, Normalizer.NFD,0)) {
+                    String decomp = Normalizer.normalize(it.codepoint, Normalizer.NFD);
+                    others.addAll(decomp);
+                    continue;
+                }
+                out.println(" " + UTF16.valueOf(it.codepoint) + " <> XXX # " + UCharacter.getName(it.codepoint));
+                main.add(it.codepoint);
+            }
+            
+            if (others.size() != 0) {
+                out.println("Decomposed characters found above: ");
+                others.removeAll(main);
+                it.reset(others);
+                while (it.next()) {
+                    out.println(" " + UTF16.valueOf(it.codepoint) + " <> XXX # " + UCharacter.getName(it.codepoint));
+                }
+            }
+            
+            out.close();
+            System.out.println("Done Writing");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    
+    static Transliterator hex = Transliterator.getInstance("[^\\u0020-\\u007E] hex");
+    static final String saveRules = 
+          "A <> \uEA41; B <> \uEA42; C <> \uEA43; D <> \uEA44; E <> \uEA45; F <> \uEA46; G <> \uEA47; H <> \uEA48; I <> \uEA49; "
+        + "J <> \uEA4A; K <> \uEA4B; L <> \uEA4C; M <> \uEA4D; N <> \uEA4E; O <> \uEA4F; P <> \uEA50; Q <> \uEA51; R <> \uEA52; "
+        + "S <> \uEA53; T <> \uEA54; U <> \uEA55; V <> \uEA56; W <> \uEA57; X <> \uEA58; Y <> \uEA59; Z <> \uEA5A; "
+        + "a <> \uEA61; b <> \uEA62; c <> \uEA63; d <> \uEA64; e <> \uEA65; f <> \uEA66; g <> \uEA67; h <> \uEA68; i <> \uEA69; "
+        + "j <> \uEA6A; k <> \uEA6B; l <> \uEA6C; m <> \uEA6D; n <> \uEA6E; o <> \uEA6F; p <> \uEA70; q <> \uEA71; r <> \uEA72; "
+        + "s <> \uEA73; t <> \uEA74; u <> \uEA75; v <> \uEA76; w <> \uEA77; x <> \uEA78; y <> \uEA79; z <> \uEA7A;";
+        
+    static Transliterator saveAscii = Transliterator.createFromRules("ascii-saved", saveRules, Transliterator.FORWARD);
+    static Transliterator restoreAscii = Transliterator.createFromRules("ascii-saved", saveRules, Transliterator.REVERSE);
+    
+    static {
+        
+        if (false) {
+        
+        for (char i = 'A'; i <= 'z'; ++i) {
+            System.out.print(i + " <> " + hex.transliterate(String.valueOf((char)(0xEA00 + i))) + "; ");
+        }
+
+        UnicodeSet x = new UnicodeSet("[[:^ccc=0:]&[:^ccc=230:]]");
+        x = x.complement();
+        x = x.complement();
+        System.out.println("Test: " + x.toPattern(true));
+        
+        Transliterator y = Transliterator.createFromRules("xxx", "$notAbove = [[:^ccc=0:]&[:^ccc=230:]]; u ($notAbove*) \u0308 > XXX | $1; ", Transliterator.FORWARD);
+        
+        String[] testList = {"u\u0308", "u\u0316\u0308", "u\u0308\u0316", "u\u0301\u0308", "u\u0308\u0301"};
+        for (int i = 0; i < testList.length; ++i) {
+            String yy = y.transliterate(testList[i]);
+            System.out.println(hex.transliterate(testList[i]) + " => " + hex.transliterate(yy));
+        }
+        
+        //printNames(new UnicodeSet("[\u0600-\u06FF]"), "Arabic-Latin.txt");
+        
+        
+        /*  
+        BreakTransliterator.register();
+        
+        BreakTransliterator testTrans = new BreakTransliterator("Any-XXX", null, null, "$");
+        String testSource = "The Quick:   Brown fox--jumped.";
+        BreakIterator bi = testTrans.getBreakIterator();
+        bi.setText(new StringCharacterIterator(testSource));
+        printBreaks(0, testSource, bi);
+        //bi.setText(UCharacterIterator.getInstance(testSource));
+        //printBreaks(1, testSource, bi);
+        
+        printIteration(2, testSource, new StringCharacterIterator(testSource));
+        //printIteration(3, testSource, UCharacterIterator.getInstance(testSource));
+        
+        
+        
+        String test = testTrans.transliterate(testSource);
+        System.out.println("Test3: " + test);
+        DummyFactory.add(testTrans.getID(), testTrans);
+        */
+        
+        // AnyTransliterator.ScriptRunIterator.registerAnyToScript();
+        
+        AnyTransliterator at = new AnyTransliterator("Greek", null);
+        at.transliterate("(cat,\u03b1,\u0915)");
+        DummyFactory.add(at.getID(), at);
+        
+        at = new AnyTransliterator("Devanagari", null);
+        at.transliterate("(cat,\u03b1,\u0915)");
+        DummyFactory.add(at.getID(), at);
+        
+        at = new AnyTransliterator("Latin", null);
+        at.transliterate("(cat,\u03b1,\u0915)");
+        DummyFactory.add(at.getID(), at);
+        
+        DummyFactory.add("Any-gif", Transliterator.createFromRules("gif", "'\\'u(..)(..) > '<img src=\"http://www.unicode.org/gifs/24/' $1 '/U' $1$2 '.gif\">';", Transliterator.FORWARD));        
+        DummyFactory.add("gif-Any", Transliterator.getInstance("Any-Null"));        
+
+        DummyFactory.add("Any-RemoveCurly", Transliterator.createFromRules("RemoveCurly", "[\\{\\}] > ;", Transliterator.FORWARD));        
+        DummyFactory.add("RemoveCurly-Any", Transliterator.getInstance("Any-Null"));
+        
+        System.out.println("Trying &hex");
+        Transliterator t = Transliterator.createFromRules("hex2", "(.) > &hex($1);", Transliterator.FORWARD);
+        System.out.println("Registering");
+        DummyFactory.add("Any-hex2", t);        
+        
+        System.out.println("Trying &gif");
+        t = Transliterator.createFromRules("gif2", "(.) > &any-gif($1);", Transliterator.FORWARD);
+        System.out.println("Registering");
+        DummyFactory.add("Any-gif2", t);    
+        }
+    }
+    
+    
+    void setTransliterator(String name, String id) {
+        if (DEBUG) System.out.println("Got: " + name);
+        if (id == null) {
+            translit = Transliterator.getInstance(name);
+        } else {
+            String reverseId = "";
+            int pos = id.indexOf('-');
+            if (pos < 0) {
+                reverseId = id + "-Any";
+                id = "Any-" + id;
+            } else {
+                int pos2 = id.indexOf("/", pos);
+                if (pos2 < 0) {
+                    reverseId = id.substring(pos+1) + "-" + id.substring(0,pos);
+                } else {
+                    reverseId = id.substring(pos+1, pos2) + "-" + id.substring(0,pos) + id.substring(pos2);
+                }
+            }
+            
+            
+            translit = Transliterator.createFromRules(id, name, Transliterator.FORWARD);
+            if (DEBUG) {
+                System.out.println("***Forward Rules");
+                System.out.println(translit.toRules(true));
+                System.out.println("***Source Set");
+                System.out.println(translit.getSourceSet().toPattern(true));
+            }
+                System.out.println("***Target Set");
+                UnicodeSet target = translit.getTargetSet();
+                System.out.println(target.toPattern(true));
+                UnicodeSet rest = new UnicodeSet("[a-z]").removeAll(target);
+                System.out.println("***ASCII - Target Set");
+                System.out.println(rest.toPattern(true));
+                
+            DummyFactory.add(id, translit);
+            
+            Transliterator translit2 = Transliterator.createFromRules(reverseId, name, Transliterator.REVERSE);
+            if (DEBUG) {
+                System.out.println("***Backward Rules");
+                System.out.println(translit2.toRules(true));
+            }
+            DummyFactory.add(reverseId, translit2);
+            
+            Transliterator rev = translit.getInverse();
+            if (DEBUG) System.out.println("***Inverse Rules");
+            if (DEBUG) System.out.println(rev.toRules(true));
+            
+        }
+        text.flush();
+        text.setTransliterator(translit);
+        convertSelectionItem.setLabel(Transliterator.getDisplayName(translit.getID()));
+        
+        addHistory(translit);
+        
+        Transliterator inv;
+        try {
+            inv = translit.getInverse();
+        } catch (Exception ex) {
+            inv = null;
+        }
+        if (inv != null) {
+            addHistory(inv);
+            swapSelectionItem.setEnabled(true);
+        } else {
+            swapSelectionItem.setEnabled(false);
+        }
+        System.out.println("Set transliterator: " + translit.getID()
+            + (inv != null ? " and " + inv.getID() : ""));
+    }
+    
+    void addHistory(Transliterator trans) {
+        String name = trans.getID();
+        MenuItem cmi = (MenuItem) historyMap.get(name);
+        if (cmi == null) {
+            cmi = new MenuItem(Transliterator.getDisplayName(name));
+            cmi.addActionListener(new TransliterationListener(name));
+            historyMap.put(name, cmi);
+            historySet.add(cmi);
+            historyMenu.removeAll();
+            Iterator it = historySet.iterator();
+            while (it.hasNext()) {
+                historyMenu.add((MenuItem)it.next());
+            }
+        }
+    }
+    
+    class TransliterationListener implements ActionListener, ItemListener {
+        String name;
+        public TransliterationListener(String name) {
+            this.name = name;
+        }
+        public void actionPerformed(ActionEvent e) {
+            setTransliterator(name, null);
+        }
+        public void itemStateChanged(ItemEvent e) {
+            if (e.getStateChange() == ItemEvent.SELECTED) {
+                setTransliterator(name, null);
+            } else {
+                setTransliterator("Any-Null", null);
+            }
+        }
+    }
+    
+    class FontActionListener implements ActionListener {
+        String name;
+        public FontActionListener(String name) {
+            this.name = name;
+        }
+        public void actionPerformed(ActionEvent e) {
+            if (DEBUG) System.out.println("Font: " + name);
+            fontName = name;
+            text.setFont(new Font(fontName, Font.PLAIN, fontSize));
+        }
+    }
+    
+    class SizeActionListener implements ActionListener {
+        int size;
+        public SizeActionListener(int size) {
+            this.size = size;
+        }
+        public void actionPerformed(ActionEvent e) {
+            if (DEBUG) System.out.println("Size: " + size);
+            fontSize = size;
+            text.setFont(new Font(fontName, Font.PLAIN, fontSize));
+        }
+    }
+    
+    Set add(Set s, Enumeration enumeration) {
+        while(enumeration.hasMoreElements()) {
+            s.add(enumeration.nextElement());
+        }
+        return s;
+    }
+
+    /**
+     * 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(Transliterator trans) {
+        if (trans == 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 + ") -> \"");
+        }
+
+        trans.transliterate(s);
+        String str = s.toString();
+
+        if (DEBUG) {
+            log.append(str + "\"");
+            System.out.println("Batch " + trans.getID() + ": " + log.toString());
+        }
+
+        text.replaceRange(str, start, end);
+        text.select(start, start + str.length());
+    }
+
+    private void handleClose() {
+        helpDialog.dispose();
+        dispose();
+    }
+    
+    /*
+    class InfoDialog extends Dialog {
+        protected Button button;
+        protected TextArea area;
+        protected Dialog me;
+        protected Panel bottom;
+        
+        public TextArea getArea() {
+            return area;
+        }
+        
+        public Panel getBottom() {
+            return bottom;
+        }
+        
+        InfoDialog(Frame parent, String title, String label, String message) {
+            super(parent, title, false);
+            me = this;
+            this.setLayout(new BorderLayout());
+            if (label.length() != 0) {
+                this.add("North", new Label(label));
+            }
+            
+            area = new TextArea(message, 8, 80, TextArea.SCROLLBARS_VERTICAL_ONLY);
+            this.add("Center", area);
+            
+            button = new Button("Hide");
+            button.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e) {
+                    me.hide();
+                }
+            });
+            bottom = new Panel();
+            bottom.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
+            bottom.add(button);
+            this.add("South", bottom);
+            this.pack();
+            addWindowListener(new WindowAdapter() {
+                public void windowClosing(WindowEvent e) {
+                    me.hide();
+                }
+            });
+        }
+    }
+    */
+}
diff --git a/demos/src/com/ibm/icu/dev/demo/translit/DemoApplet.java b/demos/src/com/ibm/icu/dev/demo/translit/DemoApplet.java
new file mode 100644
index 0000000..8ee03ae
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/translit/DemoApplet.java
@@ -0,0 +1,68 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.translit;
+import java.awt.*;
+import java.awt.event.*;
+import java.applet.*;
+import com.ibm.icu.dev.demo.impl.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
+ */
+public class DemoApplet extends Applet {
+
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = 8214879807740061678L;
+    Demo frame = null;
+    
+    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/demos/src/com/ibm/icu/dev/demo/translit/InfoDialog.java b/demos/src/com/ibm/icu/dev/demo/translit/InfoDialog.java
new file mode 100644
index 0000000..08e5dc7
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/translit/InfoDialog.java
@@ -0,0 +1,56 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2007, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.translit;
+import java.awt.event.*;
+import java.awt.*;
+public class InfoDialog extends Dialog {
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = -3086665546137919018L;
+    protected Button button;
+    protected TextArea area;
+    protected Dialog me;
+    protected Panel bottom;
+        
+    public TextArea getArea() {
+        return area;
+    }
+        
+    public Panel getBottom() {
+        return bottom;
+    }
+        
+    InfoDialog(Frame parent, String title, String label, String message) {
+        super(parent, title, false);
+        me = this;
+        this.setLayout(new BorderLayout());
+        if (label.length() != 0) {
+            this.add("North", new Label(label));
+        }
+            
+        area = new TextArea(message, 8, 80, TextArea.SCROLLBARS_VERTICAL_ONLY);
+        this.add("Center", area);
+            
+        button = new Button("Hide");
+        button.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                me.hide();
+            }
+        });
+        bottom = new Panel();
+        bottom.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
+        bottom.add(button);
+        this.add("South", bottom);
+        this.pack();
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent e) {
+                me.hide();
+            }
+        });
+    }
+}
diff --git a/demos/src/com/ibm/icu/dev/demo/translit/Test_Arabic-Latin.txt b/demos/src/com/ibm/icu/dev/demo/translit/Test_Arabic-Latin.txt
new file mode 100644
index 0000000..146c659
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/translit/Test_Arabic-Latin.txt
@@ -0,0 +1,24 @@
+#--------------------------------------------------------------------
+# Copyright (c) 1999-2004, International Business Machines
+# Corporation and others. All Rights Reserved.
+#--------------------------------------------------------------------
+@UPPERFILTER@
+ما هي الشفرة الموحدة "يونِكود" ؟
+
+أساسًا، تتعامل الحواسيب فقط مع الأرقام، وتقوم بتخزين الأحرف والمحارف الأخرى بعد أن تُعطي رقما معينا لكل واحد منها. وقبل اختراع "يونِكود"، كان هناك مئات الأنظمة للتشفير وتخصيص هذه الأرقام للمحارف، ولم يوجد نظام تشفير واحد يحتوي على جميع المحارف الضرورية. وعلى سبيل المثال، فإن الاتحاد الأوروبي لوحده، احتوى العديد من الشفرات المختلفة ليغطي جميع اللغات المستخدمة في الاتحاد. وحتى لو اعتبرنا لغة واحدة، كاللغة الإنجليزية، فإن جدول شفرة واحد لم يكف لاستيعاب جميع الأحرف وعلامات الترقيم والرموز الفنية والعلمية الشائعة الاستعمال.
+
+ 
+
+وتجدر الملاحظة أن أنظمة التشفير المختلفة تتعارض مع بعضها البعض. وبعبارة أخرى، يمكن أن يستخدِم جدولي شفرة نفس الرقم لتمثيل محرفين مختلفين، أو رقمين مختلفين لتمثيل نفس المحرف. ولو أخذنا أي جهاز حاسوب، وبخاصة جهاز النادل (server)، فيجب أن تكون لديه القدرة على التعامل مع عدد كبير من الشفرات المختلفة، ويتم تصميمه على هذا الأساس. ومع ذلك، فعندما تمر البيانات عبر أنظمة مختلفة، توجد هناك خطورة لضياع أو تحريف بعض هذه البيانات.
+
+ 
+
+"يونِكود" تغير هذا كليا !
+
+تخصص الشفرة الموحدة "يونِكود" رقما وحيدا لكل محرف في جميع اللغات العالمية، وذلك بغض النظر عن نوع الحاسوب أو البرامج المستخدمة. وقد تم تبني مواصفة "يونِكود" من قبل قادة الصانعين لأنظمة الحواسيب في العالم، مثل شركات آي.بي.إم. (IBM)، أبل (APPLE)، هِيْولِت باكرد (Hewlett-Packard) ، مايكروسوفت (Microsoft)، أوراكِل (Oracle) ، صن (Sun) وغيرها. كما أن المواصفات والمقاييس الحديثة (مثل لغة البرمجة "جافا" "JAVA" ولغة "إكس إم إل" "XML" التي تستخدم لبرمجة الانترنيت) تتطلب استخدام "يونِكود". علاوة على ذلك ، فإن "يونِكود" هي الطريقة الرسمية لتطبيق المقياس العالمي إيزو ١٠٦٤٦  (ISO 10646) .
+
+ 
+
+إن بزوغ مواصفة "يونِكود" وتوفُّر الأنظمة التي تستخدمه وتدعمه، يعتبر من أهم الاختراعات الحديثة في عولمة البرمجيات لجميع اللغات في العالم. وإن استخدام "يونِكود" في عالم الانترنيت سيؤدي إلى توفير كبير مقارنة مع استخدام المجموعات التقليدية للمحارف المشفرة. كما أن استخدام "يونِكود" سيُمكِّن المبرمج من كتابة البرنامج مرة واحدة، واستخدامه على أي نوع من الأجهزة أو الأنظمة، ولأي لغة أو دولة في العالم أينما كانت، دون الحاجة لإعادة البرمجة أو إجراء أي تعديل. وأخيرا، فإن استخدام "يونِكود" سيمكن البيانات من الانتقال عبر الأنظمة والأجهزة المختلفة دون أي خطورة لتحريفها، مهما تعددت الشركات الصانعة للأنظمة واللغات، والدول التي تمر من خلالها هذه البيانات. 
+
+@SET [[[:Arabic:] & [\u0600-\u06FF]] [‎\u060C\u061B\u061F\u0640\u064B-\u0655\u0660-\u066C\u06F0-\u06F9]]
\ No newline at end of file
diff --git a/demos/src/com/ibm/icu/dev/demo/translit/Test_Greek-Latin.txt b/demos/src/com/ibm/icu/dev/demo/translit/Test_Greek-Latin.txt
new file mode 100644
index 0000000..6380074
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/translit/Test_Greek-Latin.txt
@@ -0,0 +1,73 @@
+#--------------------------------------------------------------------
+# Copyright (c) 1999-2004, International Business Machines
+# Corporation and others. All Rights Reserved.
+#--------------------------------------------------------------------
+
+Τι είναι το Unicode? 
+
+Η κωδικοσελίδα Unicode προτείνει έναν και μοναδικό αριθμό για κάθε χαρακτήρα, ανεξάρτητα από το λειτουργικό σύστημα, ανεξάρτητα από το λογισμικό, ανεξάρτητα από την γλώσσα.
+
+Οι ηλεκτρονικοί υπολογιστές, σε τελική ανάλυση, χειρίζονται απλώς αριθμούς. Αποθηκεύουν γράμματα και άλλους χαρακτήρες αντιστοιχώντας στο καθένα τους από έναν αριθμό (ονομάζουμε μία τέτοια αντιστοιχία κωδικοσελίδα). Πριν την εφεύρεση του Unicode, υπήρχαν εκατοντάδες διαφορετικές κωδικοσελίδες. Λόγω περιορισμών μεγέθους όμως, σε καμία κωδικοσελίδα δεν χωρούσαν αρκετοί χαρακτήρες: λόγου χάριν, η Ευρωπαϊκή Ένωση χρειαζόταν πλήθος διαφορετικών κωδικοσελίδων για να καλύψει όλες τις γλώσσες των χωρών-μελών της. Ακόμα και για μία και μόνη γλώσσα, όπως π.χ. τα Αγγλικά, μία κωδικοσελίδα δεν επαρκούσε για να καλύψει όλα τα γράμματα, σημεία στίξης και τεχνικά σύμβολα ευρείας χρήσης.
+
+Εκτός αυτού, οι κωδικοσελίδες αυτές διαφωνούσαν μεταξύ τους. Έτσι, δύο κωδικοσελίδες μπορούσαν κάλλιστα να χρησιμοποιούν τον ίδιο αριθμό για δύο διαφορετικούς χαρακτήρες, ή να χρησιμοποιούν διαφορετικούς αριθμούς για τον ίδιο χαρακτήρα. Κάθε υπολογιστής (και ιδίως εάν ήταν διακομιστής) έπρεπε να υποστηρίζει πλήθος διαφορετικών κωδικοσελίδων· ταυτόχρονα κάθε φορά που δεδομένα μεταφέρονταν μεταξύ διαφορετικών κωδικοσελίδων ή λειτουργικών συστημάτων, τα δεδομένα αυτά κινδύνευαν να αλλοιωθούν.
+
+Το Unicode αλλάζει αυτή την κατάσταση!
+Το Unicode προτείνει έναν μοναδικό αριθμό για κάθε χαρακτήρα, ανεξάρτητα από το λειτουργικό σύστημα, ανεξάρτητα από το λογισμικό, ανεξάρτητα από την γλώσσα. Την κωδικοσελίδα Unicode έχουν ασπασθεί κορυφαίοι παράγοντες του χώρου των λογισμικών όπως οι: Apple, HP, IBM, JustSystem, Microsoft, Oracle, SAP, Sun, Sybase, Unisys και πολλοί άλλοι. Το Unicode απαιτούν πολλές σύγχρονες τυποποιήσεις όπως οι: XML, Java, ECMAScript (JavaScript), LDAP, CORBA 3.0, WML, κ.λπ., και είναι η επίσημη μέθοδος εφαρμογής της τυποποίησης ISO/IEC 10646. Υποστηρίζεται από πολλά λειτουργικά συστήματα, όλους τους σύχρονους περιηγητές Διαδικτύου, και πολλά άλλα προϊόντα. Η εμφάνιση της κωδικοσελίδας Unicode, και η διαθεσιμότητα εργαλείων που να την υποστηρίζουν είναι από τις σημαντικότερες εξελίξεις της πρόσφατης τεχνολογίας λογισμικών.
+
+Η ενσωμάτωση του Unicode σε εφαρμογές πελάτη-διακομιστή ή "multi-tiered" προσφέρει σημαντικές οικονομίες σε σχέση με τις ως τώρα υπάρχουσες κωδικοσελίδες. Χάρις στο Unicode ένα και μόνο προϊόν ή μία και μόνη τοποθεσία Διαδικτύου μπορεί να επικοινωνεί με διάφορα λειτουργικά συστήματα, σε διάφορες γλώσσες και χώρες, χωρίς την ανάγκη επαναπρογραμματισμού. Γίνεται έτσι δυνατή η μεταφορά δεδομένων ανάμεσα σε πλήθος διαφορετικών συστημάτων δίχως κίνδυνο αλλοίωσης.
+
+Σχετικά με το Κονσόρτιουμ Unicode
+Tο Κονσόρτιουμ Unicode είναι ένας κοινωφελής οργανισμός· ιδρύθηκε για να αναπτύξει, να επεκτείνει και να μεταδώσει την χρήση της κωδικοσελίδας Unicode που καθορίζει την αναπαράσταση κειμένου σε σύγχρονα λογισμικά προϊόντα και τυποποιήσεις. Μεγάλος αριθμός εταιρειών και οργανισμών της διεθνούς βιομηχανίας υπολογιστών και λογισμικών είναι μέλη του Κονσόρτιουμ Unicode. Το Κονσόρτιουμ χρηματοδοτείται μόνο από τις συνδρομές των μελών του. Μέλος του κονσόρτιουμ Unicode μπορεί να γίνει οιοσδήποτε (οργανισμός, εταιρεία ή ιδιώτης, οπουδήποτε στον κόσμο) που να υποστηρίζει την κωδικοσελίδα Unicode και να επιθυμεί να συνδράμει στην επέκταση και στην εφαρμογή της.
+
+Για περαιτέρω πληροφορίες, βλέπε τις εξής ιστοσελίδες: Γλωσσάρι, Δείγματα προϊόντων συμβατών με το Unicode, Τεχνική Εισαγωγή και Χρήσιμες πηγές πληροφοριών.
+
+(ANCIENT)
+
+ἄνδρα μοι ἔννεπε, μοῦσα, πολύτροπον, ὃς μάλα πολλὰ
+πλάγχθη, ἐπεὶ Τροίης ἱερὸν πτολίεθρον ἔπερσεν:
+πολλῶν δ’ ἀνθρώπων ἴδεν ἄστεα καὶ νόον ἔγνω,
+πολλὰ δ’ ὅ γ’ ἐν πόντῳ πάθεν ἄλγεα ὃν κατὰ θυμόν,
+ἀρνύμενος ἥν τε ψυχὴν καὶ νόστον ἑταίρων.
+ἀλλ’ οὐδ’ ὣς ἑτάρους ἐρρύσατο, ἱέμενός περ:
+αὐτῶν γὰρ σφετέρῃσιν ἀτασθαλίῃσιν ὄλοντο,
+νήπιοι, οἳ κατὰ βοῦς Ὑπερίονος Ἠελίοιο
+ἤσθιον: αὐτὰρ ὁ τοῖσιν ἀφείλετο νόστιμον ἦμαρ.
+τῶν ἁμόθεν γε, θεά, θύγατερ Διός, εἰπὲ καὶ ἡμῖν.
+*
+ἔνθ’ ἄλλοι μὲν πάντες, ὅσοι φύγον αἰπὺν ὄλεθρο&