ICU-12170 tag the version used for integrating CLDR release-29-beta1

X-SVN-Rev: 38334
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..06ab7d3
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,408 @@
+* 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
+
+main/shared/data/icudata.jar -text
+main/shared/data/icutzdata.jar -text
+main/shared/data/testdata.jar -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_53.1/com.ibm.icu.impl.DateNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.impl.IllegalIcuArgumentException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.impl.InvalidFormatException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.impl.JavaTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.impl.OlsonTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.impl.RelativeDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.impl.TimeZoneAdapter.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.impl.TimeZoneGenericNames.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.impl.TimeZoneNamesImpl.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.impl.duration.BasicDurationFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.impl.locale.LocaleSyntaxException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.math.BigDecimal.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.math.MathContext.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.ArabicShapingException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.ChineseDateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.ChineseDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.ChineseDateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.CompactDecimalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.CurrencyPluralInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.DateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.DateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.DateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.DateIntervalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.DateIntervalInfo$PatternInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.DateIntervalInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.DecimalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.DecimalFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.MeasureFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.MessageFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.MessageFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.NumberFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.NumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.PluralFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.PluralRules.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.RuleBasedNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.SelectFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.SimpleDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.StringPrepParseException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.TimeUnitFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.text.TimeZoneFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.AnnualTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.BuddhistCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.Calendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.ChineseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.CopticCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.Currency.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.DangiCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.DateInterval.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.DateTimeRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.EthiopicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.GregorianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.HebrewCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.ICUCloneNotSupportedException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.ICUException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.ICUUncheckedIOException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.IllformedLocaleException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.IndianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.InitialTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.IslamicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.JapaneseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.MeasureUnit.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.PersianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.RuleBasedTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.SimpleTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.TaiwanCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.TimeArrayTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.TimeUnit.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.TimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.ULocale.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.UResourceTypeMismatchException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_53.1/com.ibm.icu.util.VTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.impl.DateNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.impl.IllegalIcuArgumentException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.impl.InvalidFormatException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.impl.JavaTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.impl.OlsonTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.impl.RelativeDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.impl.TZDBTimeZoneNames.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.impl.TimeZoneAdapter.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.impl.TimeZoneGenericNames.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.impl.TimeZoneNamesImpl.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.impl.duration.BasicDurationFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.impl.locale.LocaleSyntaxException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.math.BigDecimal.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.math.MathContext.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.ArabicShapingException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.ChineseDateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.ChineseDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.ChineseDateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.CompactDecimalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.CurrencyPluralInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.DateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.DateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.DateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.DateIntervalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.DateIntervalInfo$PatternInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.DateIntervalInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.DecimalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.DecimalFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.MeasureFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.MessageFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.MessageFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.NumberFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.NumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.PluralFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.PluralRules.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.RuleBasedNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.SelectFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.SimpleDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.StringPrepParseException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.TimeUnitFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.text.TimeZoneFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.AnnualTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.BuddhistCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.Calendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.ChineseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.CopticCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.Currency.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.DangiCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.DateInterval.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.DateTimeRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.EthiopicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.GregorianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.HebrewCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.ICUCloneNotSupportedException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.ICUException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.ICUUncheckedIOException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.IllformedLocaleException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.IndianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.InitialTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.IslamicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.JapaneseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.MeasureUnit.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.PersianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.RuleBasedTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.SimpleTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.TaiwanCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.TimeArrayTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.TimeUnit.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.TimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.ULocale.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.UResourceTypeMismatchException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_54.1/com.ibm.icu.util.VTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.impl.DateNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.impl.IllegalIcuArgumentException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.impl.InvalidFormatException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.impl.JavaTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.impl.OlsonTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.impl.RelativeDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.impl.TZDBTimeZoneNames.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.impl.TimeZoneAdapter.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.impl.TimeZoneGenericNames.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.impl.TimeZoneNamesImpl.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.impl.duration.BasicDurationFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.impl.locale.LocaleSyntaxException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.math.BigDecimal.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.math.MathContext.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.ArabicShapingException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.ChineseDateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.ChineseDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.ChineseDateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.CompactDecimalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.CurrencyPluralInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.DateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.DateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.DateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.DateIntervalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.DateIntervalInfo$PatternInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.DateIntervalInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.DecimalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.DecimalFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.MeasureFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.MessageFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.MessageFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.NumberFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.NumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.PluralFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.PluralRules.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.RuleBasedNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.SelectFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.SimpleDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.StringPrepParseException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.TimeUnitFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.text.TimeZoneFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.AnnualTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.BuddhistCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.Calendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.ChineseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.CopticCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.Currency.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.DangiCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.DateInterval.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.DateTimeRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.EthiopicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.GregorianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.HebrewCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.ICUCloneNotSupportedException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.ICUException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.ICUUncheckedIOException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.IllformedLocaleException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.IndianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.InitialTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.IslamicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.JapaneseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.MeasureUnit.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.PersianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.RuleBasedTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.SimpleTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.TaiwanCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.TimeArrayTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.TimeUnit.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.TimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.ULocale.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.UResourceTypeMismatchException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_55.1/com.ibm.icu.util.VTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.impl.DateNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.impl.IllegalIcuArgumentException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.impl.InvalidFormatException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.impl.JavaTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.impl.OlsonTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.impl.RelativeDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.impl.TZDBTimeZoneNames.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.impl.TimeZoneAdapter.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.impl.TimeZoneGenericNames.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.impl.TimeZoneNamesImpl.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.impl.duration.BasicDurationFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.impl.locale.LocaleSyntaxException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.math.BigDecimal.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.math.MathContext.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.ArabicShapingException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.ChineseDateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.ChineseDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.ChineseDateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.CompactDecimalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.CurrencyPluralInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.DateFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.DateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.DateFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.DateIntervalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.DateIntervalInfo$PatternInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.DateIntervalInfo.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.DecimalFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.DecimalFormatSymbols.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.MeasureFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.MessageFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.MessageFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.NumberFormat$Field.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.NumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.PluralFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.PluralRules.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.RuleBasedNumberFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.SelectFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.SimpleDateFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.StringPrepParseException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.TimeUnitFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.text.TimeZoneFormat.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.AnnualTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.BuddhistCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.Calendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.ChineseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.CopticCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.Currency.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.DangiCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.DateInterval.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.DateTimeRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.EthiopicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.GregorianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.HebrewCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.ICUCloneNotSupportedException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.ICUException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.ICUUncheckedIOException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.IllformedLocaleException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.IndianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.InitialTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.IslamicCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.JapaneseCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.MeasureUnit.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.PersianCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.RuleBasedTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.SimpleTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.TaiwanCalendar.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.TimeArrayTimeZoneRule.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.TimeUnit.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.TimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.ULocale.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.UResourceTypeMismatchException.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_56.1/com.ibm.icu.util.VTimeZone.dat -text
+main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.setRanges1.16.tri2 -text
+main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.setRanges1.32.tri2 -text
+main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.setRanges2.16.tri2 -text
+main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.setRanges2.32.tri2 -text
+main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.setRanges3.16.tri2 -text
+main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.setRanges3.32.tri2 -text
+main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.setRangesEmpty.16.tri2 -text
+main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.setRangesEmpty.32.tri2 -text
+main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.setRangesSingleValue.16.tri2 -text
+main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.setRangesSingleValue.32.tri2 -text
+samples/src/com/ibm/icu/samples/iuc/data/popmsg/en.res -text
+samples/src/com/ibm/icu/samples/iuc/data/popmsg/es.res -text
+samples/src/com/ibm/icu/samples/iuc/data/popmsg/res_index.res -text
+samples/src/com/ibm/icu/samples/iuc/data/popmsg/root.res -text
+samples/src/com/ibm/icu/samples/iuc/data/reshello/es.res -text
+samples/src/com/ibm/icu/samples/iuc/data/reshello/mt.res -text
+samples/src/com/ibm/icu/samples/iuc/data/reshello/res_index.res -text
+samples/src/com/ibm/icu/samples/iuc/data/reshello/root.res -text
+tools/build/icu4j48.api3.gz -text
+tools/build/icu4j49.api3.gz -text
+tools/build/icu4j50.api3.gz -text
+tools/build/icu4j51.api3.gz -text
+tools/build/icu4j52.api3.gz -text
+tools/build/icu4j53.api3.gz -text
+tools/build/icu4j54.api3.gz -text
+tools/build/icu4j55.api3.gz -text
+tools/build/icu4j56.api3.gz -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..c800d44
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,27 @@
+/*.jar
+/.project
+demos/out
+/doc
+eclipse-build/out
+main/classes/charset/out
+main/classes/collate/out
+main/classes/core/out
+main/classes/currdata/out
+main/classes/langdata/out
+main/classes/localespi/out
+main/classes/regiondata/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/packaging/out
+main/tests/testall/out
+main/tests/translit/out
+/out
+perf-tests/out
+samples/build-local.properties
+samples/out
+tools/build/out
+tools/misc/out
diff --git a/APIChangeReport.html b/APIChangeReport.html
new file mode 100644
index 0000000..96cca83
--- /dev/null
+++ b/APIChangeReport.html
@@ -0,0 +1,49 @@
+<!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 56.1 with ICU4J 57.0.1</title>
+<!-- Copyright 2016, IBM, All Rights Reserved. -->
+</head>
+<body>
+<h1>ICU4J API Comparison: ICU4J 56.1 with ICU4J 57.0.1</h1>
+
+<hr/>
+<h2>Removed from ICU4J 56.1</h2>
+<p>(no API removed)</p>
+
+<hr/>
+<h2>Deprecated or Obsoleted in ICU4J 57.0.1</h2>
+<p>(no API obsoleted)</p>
+
+<hr/>
+<h2>Changed in ICU4J 57.0.1 (old, new)</h2>
+<p>(no API changed)</p>
+
+<hr/>
+<h2>Promoted to stable in ICU4J 57.0.1</h2>
+<p>(no API promoted to stable)</p>
+
+<hr/>
+<h2>Added in ICU4J 57.0.1</h2>
+
+<h3>Package com.ibm.icu.lang</h3>
+<ul>
+UProperty
+<ul>
+<li><span style='color:orange'>(draft)</span> public static final int EMOJI</li>
+<li><span style='color:orange'>(draft)</span> public static final int EMOJI_MODIFIER</li>
+<li><span style='color:orange'>(draft)</span> public static final int EMOJI_MODIFIER_BASE</li>
+<li><span style='color:orange'>(draft)</span> public static final int EMOJI_PRESENTATION</li>
+</ul>
+</ul>
+
+<h3>Package com.ibm.icu.text</h3>
+<ul>
+<li><span style='color:orange'>(draft)</span> public final class <i>SimpleFormatter</i></li>
+</ul>
+
+<hr/>
+<p><i><font size="-1">Contents generated by ReportAPI tool on Sat Jan 30 01:35:42 EST 2016<br/>Copyright (C) 2016, 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..d0c065f
--- /dev/null
+++ b/build.properties
@@ -0,0 +1,9 @@
+#*******************************************************************************
+#* Copyright (C) 2009-2016, International Business Machines Corporation and    *
+#* others. All Rights Reserved.                                                *
+#*******************************************************************************
+api.report.version = 57
+api.report.prev.version = 56
+release.file.ver = 57m1
+api.doc.version = 57 Milestone 1
+
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..eb2685f
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,2055 @@
+<!--
+*******************************************************************************
+* Copyright (C) 1997-2016, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+-->
+<project name="icu4j" default="jar" basedir="."
+    xmlns:jacoco="antlib:org.jacoco.ant">
+
+    <property file="build-local.properties"/>
+    <property file="build.properties"/>
+
+    <property name="shared.dir" value="main/shared"/>
+    <import file="${shared.dir}/build/common-targets.xml"/>
+
+    <property environment="env"/>
+
+    <!-- icu4j binaries -->
+    <property name="icu4j.jar.file" value="icu4j.jar"/>
+    <property name="icu4jtests.jar.file" value="icu4jtests.jar"/>
+    <property name="icu4j-charset.jar.file" value="icu4j-charset.jar"/>
+    <property name="icu4j-localespi.jar.file" value="icu4j-localespi.jar"/>
+
+    <property name="icu4jdemos.jar.file" value="icu4jdemos.jar"/>
+
+    <!-- icu4j API doc jar file -->
+    <property name="icu4jdocs.jar.file" value="icu4j-docs.jar"/>
+
+    <!-- icu4j src jar files -->
+    <property name="icu4j-src.jar.file" value="icu4j-src.jar"/>
+    <property name="icu4j-charset-src.jar.file" value="icu4j-charset-src.jar"/>
+    <property name="icu4j-localespi-src.jar.file" value="icu4j-localespi-src.jar"/>
+
+    <!-- icu4j source package archive files -->
+    <property name="icu4jsrc.zip.file" value="icu4j.zip"/>
+    <property name="icu4jsrc.tgz.file" value="icu4j.tgz"/>
+
+    <!-- icu4j versioned release files -->
+    <property name="icu4j.jar.versioned.file" value="icu4j-${release.file.ver}.jar"/>
+    <property name="icu4j-charset.jar.versioned.file" value="icu4j-charset-${release.file.ver}.jar"/>
+    <property name="icu4j-localespi.jar.versioned.file" value="icu4j-localespi-${release.file.ver}.jar"/>
+
+    <property name="icu4j-src.jar.versioned.file" value="icu4j-${release.file.ver}-src.jar"/>
+    <property name="icu4j-charset-src.jar.versioned.file" value="icu4j-charset-${release.file.ver}-src.jar"/>
+    <property name="icu4j-localespi-src.jar.versioned.file" value="icu4j-localespi-${release.file.ver}-src.jar"/>
+
+    <property name="icu4jdocs.jar.versioned.file" value="icu4j-${release.file.ver}-docs.jar"/>
+
+    <!-- <property name="icu4jsrc.zip.versioned.file" value="icu4j-${release.file.ver}.zip"/> -->
+    <property name="icu4jsrc.tgz.versioned.file" value="icu4j-${release.file.ver}.tgz"/>
+
+    <!-- API doc -->
+    <property name="icu4j.api.doc.title" value="ICU4J ${api.doc.version} API Specification"/>
+    <property name="icu4j.api.doc.window.title" value="ICU4J ${api.doc.version}"/>
+    <property name="icu4j.api.doc.header" value="ICU4J ${api.doc.version}"/>
+    <property name="icu4j.api.doc.jdk.link" value="http://docs.oracle.com/javase/8/docs/api/"/>
+
+    <!-- directories -->
+    <property name="release.dir" value="release"/>
+    <property name="doc.dir" value="doc"/>
+    <property name="cldr.util.out.dir" value="${out.dir}/cldr_util"/>
+    <property name="cldr.release.dir" value="release_cldr"/>
+
+    <!-- Java version check -->
+    <condition property="is.java6.plus">
+        <or>
+            <contains string="${java.version}" substring="1.6."/>
+            <contains string="${java.version}" substring="1.7."/>
+            <contains string="${java.version}" substring="1.8."/>
+            <contains string="${java.version}" substring="1.9."/>
+        </or>
+    </condition>
+    <fail message="The JDK version is too old or unknown.">
+        <condition>
+            <not>
+                <isset property="is.java6.plus"/>
+            </not>
+        </condition>
+    </fail>
+
+    <condition property="is.java7">
+            <contains string="${java.version}" substring="1.7."/>
+    </condition>
+
+    <condition property="is.java7.plus">
+        <or>
+            <contains string="${java.version}" substring="1.7."/>
+            <contains string="${java.version}" substring="1.8."/>
+        </or>
+    </condition>
+    <condition property="is.pre.java8">
+        <or>
+            <contains string="${java.version}" substring="1.5."/>
+            <contains string="${java.version}" substring="1.6."/>
+            <contains string="${java.version}" substring="1.7."/>
+        </or>
+    </condition>
+    
+
+    <!-- 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.currdata.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.langdata.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.localespi.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.regiondata.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.packaging-tests.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.translit-tests.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.testall.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"/>
+        <ant dir="${icu4j.samples.dir}" target="clean" inheritAll="false"/>
+        <ant dir="${icu4j.perf-tests.dir}" target="clean" inheritAll="false"/>
+
+        <!-- delete all .jar files root directory -->
+        <delete>
+            <fileset dir="." includes="icu4j*.jar"/>
+        </delete>
+
+        <delete dir="${release.dir}"/>
+        <delete dir="${doc.dir}"/>
+        <delete dir="${out.dir}"/>
+        <delete dir="${module.dir}"/>
+        <delete dir="${cldr.release.dir}"/>
+
+        <available file="eclipse-build" type="dir" property="eclipse-build.dir.present"/>
+        <antcall target="_clean.eclipse-build"/>
+    </target>
+
+    <target name="_clean.eclipse-build" if="eclipse-build.dir.present">
+        <ant dir="eclipse-build" target="clean" inheritAll="false"/>
+    </target>
+
+    <!-- meta build targets -->
+    <target name="all" depends="info, main, tests, build-tools, tools, demos, samples, perf-tests, jar, docs" description="Build all primary targets"/>
+    <target name="main" depends="info, core, collate, charset, currdata, langdata, regiondata, translit, localespi" description="Build ICU4J runtime library classes"/>
+    <target name="tests" depends="info, core-tests, charset-tests, collate-tests, packaging-tests, translit-tests, testall, localespi-tests" description="Build ICU4J test classes"/>
+
+    <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=""/>
+            <param name="runcheck.jvmarg" value="${jvm_options} -ea"/>
+        </antcall>
+    </target>
+
+    <target name="exhaustiveCheck" description="Run the standard ICU4J test suite in exhaustive mode">
+        <antcall target="_runCheck">
+            <param name="runcheck.arg" value="-e10"/>
+            <param name="runcheck.jvmarg" value="${jvm_options} -ea"/>
+        </antcall>
+    </target>
+
+    <target name="timeZoneCheck" description="Run the complete test for TimeZoneRoundTripAll">
+        <antcall target="_runCheck">
+            <param name="runcheck.arg" value="-prop:TimeZoneRoundTripAll=true Core/Format/DateFormat/TimeZoneFormatTest -v"/>
+            <param name="runcheck.jvmarg" value="${jvm_options}"/>
+        </antcall>
+    </target>
+
+    <target name="jdktzCheck" description="Run the standard ICU4J test suite with JDK TimeZone">
+        <antcall target="_runCheck">
+            <param name="runcheck.arg" value=""/>
+            <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 location="${icu4j.core.jar}"/>
+                <pathelement location="${icu4j.collate.jar}"/>
+                <pathelement location="${icu4j.charset.jar}"/>
+                <pathelement location="${icu4j.currdata.jar}"/>
+                <pathelement location="${icu4j.langdata.jar}"/>
+                <pathelement location="${icu4j.regiondata.jar}"/>
+                <pathelement location="${icu4j.translit.jar}"/>
+                <pathelement location="${icu4j.test-framework.jar}"/>
+                <pathelement location="${icu4j.core-tests.jar}"/>
+                <pathelement location="${icu4j.collate-tests.jar}"/> 
+                <pathelement location="${icu4j.charset-tests.jar}"/>
+                <pathelement location="${icu4j.translit-tests.jar}"/>
+                <pathelement location="${icu4j.testall.jar}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <target name="_runTestArgCheck" unless="testarg">
+        <echo message="No test arguments are supplied."/>
+        <echo message="For specifying test arguments, use '-Dtestarg=[test args]' as"/>
+        <echo message="ant command line argument. For example:"/>
+        <echo message="  &#x3E;ant runTest -Dtestarg=&#x22;Core/Format -e10&#x22;"/>
+        <echo message="for running ICU4J core format test suite in exhaustive mode."/>
+    </target>
+
+    <target name="runTest" depends="_runTestArgCheck" description="Run a ICU4J test case, without calling any other build targets">
+        <echo message="JVM argument:   ${jvm_options} -Djava.awt.headless=true"/>
+        <echo message="Test argument:   ${testarg}"/>
+
+        <java classname="com.ibm.icu.dev.test.TestAll" fork="yes" failonerror="true">
+            <arg line="${testarg}"/>
+            <jvmarg line="${jvm_options} -Djava.awt.headless=true"/>
+            <classpath>
+                <pathelement location="${icu4j.core.jar}"/>
+                <pathelement location="${icu4j.collate.jar}"/>
+                <pathelement location="${icu4j.charset.jar}"/>
+                <pathelement location="${icu4j.currdata.jar}"/>
+                <pathelement location="${icu4j.langdata.jar}"/>
+                <pathelement location="${icu4j.regiondata.jar}"/>
+                <pathelement location="${icu4j.translit.jar}"/>
+                <pathelement location="${icu4j.test-framework.jar}"/>
+                <pathelement location="${icu4j.core-tests.jar}"/>
+                <pathelement location="${icu4j.collate-tests.jar}"/> 
+                <pathelement location="${icu4j.charset-tests.jar}"/>
+                <pathelement location="${icu4j.translit-tests.jar}"/>
+                <pathelement location="${icu4j.testall.jar}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <target name="packagingCheck" depends="info, core, packaging-tests" description="Run packaging tests">
+        <!-- region data but no language data -->
+        <java classname="com.ibm.icu.dev.test.TestPackaging" fork="yes" failonerror="true">
+            <arg line="-w"/>
+            <classpath>
+                <pathelement location="${icu4j.core.jar}"/>
+                <pathelement location="${icu4j.charset.jar}"/>
+                <pathelement location="${icu4j.test-framework.jar}"/>
+                <pathelement location="${icu4j.packaging-tests.jar}"/>
+                <pathelement location="${icu4j.regiondata.jar}"/>
+            </classpath>
+        </java>
+        <!-- language data but no region data -->
+        <java classname="com.ibm.icu.dev.test.TestPackaging" fork="yes" failonerror="true">
+            <arg line="-w"/>
+            <classpath>
+                <pathelement location="${icu4j.core.jar}"/>
+                <pathelement location="${icu4j.charset.jar}"/>
+                <pathelement location="${icu4j.test-framework.jar}"/>
+                <pathelement location="${icu4j.packaging-tests.jar}"/>
+                <pathelement location="${icu4j.langdata.jar}"/>
+            </classpath>
+        </java>
+        <!-- neither region nor language data -->
+        <java classname="com.ibm.icu.dev.test.TestPackaging" fork="yes" failonerror="true">
+            <arg line="-w"/>
+            <classpath>
+                <pathelement location="${icu4j.core.jar}"/>
+                <pathelement location="${icu4j.charset.jar}"/>
+                <pathelement location="${icu4j.test-framework.jar}"/>
+                <pathelement location="${icu4j.packaging-tests.jar}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <target name="coreCheck" depends="info, core, currdata, langdata, regiondata, core-tests" description="Run only the core tests">
+        <java classname="com.ibm.icu.dev.test.TestAllCore" fork="yes" failonerror="true">
+            <classpath>
+                <pathelement location="${icu4j.core.jar}"/>
+                <pathelement location="${icu4j.currdata.jar}"/>
+                <pathelement location="${icu4j.langdata.jar}"/>
+                <pathelement location="${icu4j.regiondata.jar}"/>
+                <pathelement location="${icu4j.test-framework.jar}"/>
+                <pathelement location="${icu4j.core-tests.jar}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <target name="collateCheck" depends="info, core, collate, currdata, langdata, regiondata, core-tests, collate-tests" description="Run only the collation tests">
+        <java classname="com.ibm.icu.dev.test.TestAllCollate" fork="yes" failonerror="true">
+            <classpath>
+                <pathelement location="${icu4j.core.jar}"/>
+                <pathelement location="${icu4j.collate.jar}"/>
+                <pathelement location="${icu4j.test-framework.jar}"/>
+                <pathelement location="${icu4j.collate-tests.jar}"/>
+
+                <!-- for now, collateCheck needs currdata, langdata and regiondata, because of GlobalizationPreferencesTest" -->
+                <pathelement location="${icu4j.currdata.jar}"/>
+                <pathelement location="${icu4j.langdata.jar}"/>
+                <pathelement location="${icu4j.regiondata.jar}"/>
+                <pathelement location="${icu4j.core-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">
+            <classpath>
+                <pathelement location="${icu4j.core.jar}"/>
+                <pathelement location="${icu4j.translit.jar}"/>
+                <pathelement location="${icu4j.test-framework.jar}"/>
+                <pathelement location="${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}${icu4j.currdata.dir}/${jar.dir}${path.separator}${icu4j.langdata.dir}/${jar.dir}${path.separator}${icu4j.regiondata.dir}/${jar.dir}${path.separator}${java.ext.dirs}"/>
+            <classpath>
+                <pathelement location="${icu4j.localespi-tests.jar}"/>
+                <pathelement location="${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="-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 location="${icu4j.jar.file}"/>
+                <pathelement location="${icu4j-charset.jar.file}"/>
+                <pathelement location="${icu4jtests.jar.file}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <!-- jar targets -->
+    <target name="jar" depends="icu4jJar, charset, localespi" description="Build ICU4J runtime library jar files">
+        <copy file="${icu4j.charset.jar}" tofile="${icu4j-charset.jar.file}"/>
+        <copy file="${icu4j.localespi.jar}" tofile="${icu4j-localespi.jar.file}" failonerror="false"/>
+    </target>
+
+    <target name="icu4jJar" depends="info, core, collate, currdata, langdata, regiondata, translit" description="Build ICU4J all-in-one core jar">
+        <mkdir dir="${out.dir}"/>
+
+        <!-- manifest -->
+        <copy file="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}"/>
+                <filter token="EXECENV" value="${jar.exec.env}"/>
+            </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.currdata.dir}/${bin.dir}" includes="**/*"/>
+            <fileset dir="${icu4j.langdata.dir}/${bin.dir}" includes="**/*"/>
+            <fileset dir="${icu4j.regiondata.dir}/${bin.dir}" includes="**/*"/>
+            <fileset dir="${icu4j.translit.dir}/${bin.dir}" includes="**/*"/>
+            <fileset dir="${shared.dir}/licenses">
+                <include name="license.html"/>
+            </fileset>
+        </jar>
+    </target>
+
+    <target name="icu4jSrcJar" description="Build icu4j-src.jar">
+        <jar jarfile="${icu4j-src.jar.file}"
+                compress="true">
+            <fileset dir="${icu4j.core.dir}/${src.dir}" includes="**/*.java"/>
+            <fileset dir="${icu4j.collate.dir}/${src.dir}" includes="**/*.java"/>
+            <fileset dir="${icu4j.currdata.dir}/${src.dir}" includes="**/*.java"/>
+            <fileset dir="${icu4j.langdata.dir}/${src.dir}" includes="**/*.java"/>
+            <fileset dir="${icu4j.regiondata.dir}/${src.dir}" includes="**/*.java"/>
+            <fileset dir="${icu4j.translit.dir}/${src.dir}" includes="**/*.java"/>
+            <fileset dir="${shared.dir}/licenses">
+                <include name="license.html"/>
+            </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="**/*"/>
+            <fileset dir="${icu4j.testall.dir}/${bin.dir}" includes="**/*"/>
+        </jar>
+    </target>
+
+    <target name="jarDemos" depends="icu4jJar, demos" description="Build ICU4J demo jar file">
+        <copy file="${icu4j.demos.jar}" tofile="${icu4jdemos.jar.file}"/>
+    </target>
+
+
+    <!-- release targets -->
+    <target name="_check_config_for_release">
+        <condition property="release.build.config.ok">
+            <and>
+                <isset property="is.java7"/>
+                <isset property="java6.bootclasspath"/>
+                <isset property="jcite.libs"/>
+            </and>
+        </condition>
+    </target>
+
+    <target name="_verify_config_for_release" depends="_check_config_for_release" unless="release.build.config.ok">
+        <condition property="disp.is.java7" value="${java.version}" else="${java.version} - Must be 1.7!">
+            <isset property="is.java7"/>
+        </condition>
+        <condition property="disp.java6.bootclasspath" value="${java6.bootclasspath}" else="Not Defined!">
+            <isset property="java6.bootclasspath"/>
+        </condition>
+        <condition property="disp.jcite.libs" value="${jcite.libs}" else="Not Defined!">
+            <isset property="jcite.libs"/>
+        </condition>
+
+        <echo message="################################################################"/>
+        <echo message="[WARNING] Insufficient Build Configuration for ICU4J Release"/>
+        <echo message="JDK Tools Version:              ${disp.is.java7}"/>
+        <echo message="JRE 6 System Library Path:      ${disp.java6.bootclasspath}"/>
+        <echo message="JCite Library Path:             ${disp.jcite.libs}"/>
+        <echo message="################################################################"/>
+    </target>
+
+    <target name="releaseVer" depends="info, releaseBinaries, releaseSrcJars, releaseDocs, releaseSourceArchiveTgz"
+            description="Build all ICU4J release files for distribution with versioned file names">
+        <!-- binaries -->
+        <move file="${release.dir}/${icu4j.jar.file}" tofile="${release.dir}/${icu4j.jar.versioned.file}"/>
+        <move file="${release.dir}/${icu4j-charset.jar.file}" tofile="${release.dir}/${icu4j-charset.jar.versioned.file}"/>
+        <move file="${release.dir}/${icu4j-localespi.jar.file}" tofile="${release.dir}/${icu4j-localespi.jar.versioned.file}"/>
+
+        <!-- source jars -->
+        <move file="${release.dir}/${icu4j-src.jar.file}" tofile="${release.dir}/${icu4j-src.jar.versioned.file}"/>
+        <move file="${release.dir}/${icu4j-charset-src.jar.file}" tofile="${release.dir}/${icu4j-charset-src.jar.versioned.file}"/>
+        <move file="${release.dir}/${icu4j-localespi-src.jar.file}" tofile="${release.dir}/${icu4j-localespi-src.jar.versioned.file}"/>
+
+        <!-- docs -->
+        <move file="${release.dir}/${icu4jdocs.jar.file}" tofile="${release.dir}/${icu4jdocs.jar.versioned.file}"/>
+
+        <!-- package archive -->
+        <move file="${release.dir}/${icu4jsrc.tgz.file}" tofile="${release.dir}/${icu4jsrc.tgz.versioned.file}"/>
+
+        <!-- md5 checksum file -->
+        <mkdir dir="${out.dir}/checksum"/>
+        <delete dir="${out.dir}/checksum" includes="**/*"/>
+
+        <checksum todir="${out.dir}/checksum" format="MD5SUM">
+            <fileset dir="${release.dir}">
+                <include name="*.jar"/>
+                <include name="*.tgz"/>
+            </fileset>
+        </checksum>
+
+        <concat destfile="${release.dir}/icu4j-${release.file.ver}.md5">
+            <fileset dir="${out.dir}/checksum" includes="*"/>
+            <filterchain>
+                <fixcrlf eol="lf"/>
+            </filterchain>
+        </concat>
+
+        <antcall target="_verify_config_for_release"/>
+    </target>
+
+    <target name="release" depends="info, releaseBinaries, releaseSrcJars, releaseDocs, releaseSourceArchiveTgz" description="Build all ICU4J release files for distribution">
+        <mkdir dir="${out.dir}/checksum"/>
+        <delete dir="${out.dir}/checksum" includes="**/*"/>
+
+        <checksum todir="${out.dir}/checksum" format="MD5SUM">
+            <fileset dir="${release.dir}">
+                <include name="*.jar"/>
+                <include name="*.tgz"/>
+            </fileset>
+        </checksum>
+
+        <concat destfile="${release.dir}/icu4j.md5">
+            <fileset dir="${out.dir}/checksum" includes="*"/>
+            <filterchain>
+                <fixcrlf eol="lf"/>
+            </filterchain>
+        </concat>
+
+        <antcall target="_verify_config_for_release"/>
+    </target>
+
+    <target name="releaseBinaries" depends="icu4jJar, charset, localespi" description="Build ICU4J binary files for distribution">
+        <mkdir dir="${release.dir}"/>
+        <copy file="${icu4j.jar.file}" tofile="${release.dir}/${icu4j.jar.file}"/>
+        <copy file="${icu4j.charset.jar}" tofile="${release.dir}/${icu4j-charset.jar.file}"/>
+        <copy file="${icu4j.localespi.jar}" tofile="${release.dir}/${icu4j-localespi.jar.file}"/>
+    </target>
+
+    <target name="releaseSrcJars" depends="icu4jSrcJar" description="Build ICU4J src jar files for distribution">
+        <mkdir dir="${release.dir}"/>
+
+        <!-- icu4j src-jar -->
+        <copy file="${icu4j-src.jar.file}" tofile="${release.dir}/${icu4j-src.jar.file}"/>
+
+        <!-- charset/localespi src-jar -->
+        <ant dir="${icu4j.charset.dir}" target="src-jar" inheritAll="false"/>
+        <ant dir="${icu4j.localespi.dir}" target="src-jar" inheritAll="false"/>
+
+        <copy file="${icu4j.charset.dir}/${out.dir}/lib/${icu4j-charset-src.jar.file}" tofile="${release.dir}/${icu4j-charset-src.jar.file}"/>
+        <copy file="${icu4j.localespi.dir}/${out.dir}/lib/${icu4j-localespi-src.jar.file}" tofile="${release.dir}/${icu4j-localespi-src.jar.file}"/>
+    </target>
+
+
+    <target name="releaseDocs" depends="docs" description="Build ICU4J API reference doc jar file for distribution">
+        <mkdir dir="${release.dir}"/>
+        <jar jarfile="${release.dir}/${icu4jdocs.jar.file}" compress="true" basedir="${doc.dir}"/>
+    </target>
+
+    <property name="src.release.wrk.dir" value="${out.dir}/tmpsrc"/>
+
+    <target name="releaseSourceArchiveZip" description="Build ICU4J source release archive (.zip)">
+        <delete dir="${src.release.wrk.dir}"/>
+        <delete file="${icu4jsrc.zip.file}"/>
+
+        <mkdir dir="${src.release.wrk.dir}"/>
+
+        <fixcrlf srcdir="."
+                destdir="${src.release.wrk.dir}"
+                encoding="UTF-8"
+                eol="crlf">
+            <include name="demos/**/*"/>
+            <include name="main/**/*"/>
+            <include name="perf-tests/**/*"/>
+            <include name="samples/**/*"/>
+            <include name="tools/**/*"/>
+            <include name="*.html"/>
+            <include name="*.xml"/>
+            <include name="*.properties"/>
+            <include name="*.css"/>
+            <include name="*.stub"/>
+            <exclude name="**/out/**/*"/>
+            <exclude name="**/*.jar"/>
+            <exclude name="**/build-local.properties"/>
+            <exclude name="main/tests/core/src/com/ibm/icu/dev/data/rbbi/english.dict"/>
+            <exclude name="main/tests/core/src/com/ibm/icu/dev/test/serializable/data/**/*.dat"/>
+            <exclude name="main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.*.tri2"/>
+            <exclude name="tools/build/icu4j*.api*.gz"/>
+        </fixcrlf>
+
+        <mkdir dir="${release.dir}"/>
+        <zip destfile="${release.dir}/${icu4jsrc.zip.file}">
+            <fileset dir="${src.release.wrk.dir}" includes="**/*"/>
+            <fileset dir="${basedir}">
+                <include name="main/shared/data/*.jar"/>
+                <include name="main/tests/core/src/com/ibm/icu/dev/data/rbbi/english.dict"/>
+                <include name="main/tests/core/src/com/ibm/icu/dev/test/serializable/data/**/*.dat"/>
+                <include name="main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.*.tri2"/>
+                <include name="tools/build/icu4j*.api*.gz"/>
+            </fileset>
+        </zip>
+
+        <delete dir="${src.release.wrk.dir}"/>
+    </target>
+
+    <target name="releaseSourceArchiveTgz" description="Build ICU4J source release archive (.tgz)">
+        <delete dir="${src.release.wrk.dir}"/>
+        <delete file="${icu4jsrc.tgz.file}"/>
+
+        <mkdir dir="${src.release.wrk.dir}"/>
+
+        <fixcrlf srcdir="."
+                destdir="${src.release.wrk.dir}"
+                encoding="UTF-8"
+                eol="lf">
+            <include name="demos/**/*"/>
+            <include name="main/**/*"/>
+            <include name="perf-tests/**/*"/>
+            <include name="samples/**/*"/>
+            <include name="tools/**/*"/>
+            <include name="*.html"/>
+            <include name="*.xml"/>
+            <include name="*.properties"/>
+            <include name="*.css"/>
+            <include name="*.stub"/>
+            <exclude name="**/out/**/*"/>
+            <exclude name="**/*.jar"/>
+            <exclude name="**/build-local.properties"/>
+            <exclude name="main/tests/core/src/com/ibm/icu/dev/data/rbbi/english.dict"/>
+            <exclude name="main/tests/core/src/com/ibm/icu/dev/test/serializable/data/**/*.dat"/>
+            <exclude name="main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.*.tri2"/>
+            <exclude name="tools/build/icu4j*.api*.gz"/>
+        </fixcrlf>
+
+        <property name="icu4jsrc.tar" value="${out.dir}/icu4jsrc.tar"/>
+
+        <tar destfile="${icu4jsrc.tar}" longfile="gnu">
+            <fileset dir="${src.release.wrk.dir}" includes="**/*"/>
+            <fileset dir="${basedir}">
+                <include name="main/shared/data/*.jar"/>
+                <include name="main/tests/core/src/com/ibm/icu/dev/data/rbbi/english.dict"/>
+                <include name="main/tests/core/src/com/ibm/icu/dev/test/serializable/data/**/*.dat"/>
+                <include name="main/tests/core/src/com/ibm/icu/dev/test/util/Trie2Test.*.tri2"/>
+                <include name="tools/build/icu4j*.api*.gz"/>
+            </fileset>
+        </tar>
+
+        <mkdir dir="${release.dir}"/>
+        <gzip destfile="${release.dir}/${icu4jsrc.tgz.file}" src="${icu4jsrc.tar}"/>
+
+        <delete dir="${src.release.wrk.dir}"/>
+        <delete file="${icu4jsrc.tar}"/>
+    </target>
+
+    <!-- findbugs targets -->
+
+    <target name="findbugs" description="Run FindBugs on all library sub projects.">
+        <property name="findbugs.out.dir" value="${out.dir}/findbugs"/>
+        <mkdir dir="${findbugs.out.dir}"/>
+
+        <ant dir="${icu4j.core.dir}" inheritAll="false" target="findbugs"/>
+        <copy file="${icu4j.core.dir}/${out.dir}/fb-core.html" todir="${findbugs.out.dir}"/>
+
+        <ant dir="${icu4j.collate.dir}" inheritAll="false" target="findbugs"/>
+        <copy file="${icu4j.collate.dir}/${out.dir}/fb-collate.html" todir="${findbugs.out.dir}"/>
+
+        <ant dir="${icu4j.currdata.dir}" inheritAll="false" target="findbugs"/>
+        <copy file="${icu4j.currdata.dir}/${out.dir}/fb-currdata.html" todir="${findbugs.out.dir}"/>
+
+        <ant dir="${icu4j.langdata.dir}" inheritAll="false" target="findbugs"/>
+        <copy file="${icu4j.langdata.dir}/${out.dir}/fb-langdata.html" todir="${findbugs.out.dir}"/>
+
+        <ant dir="${icu4j.regiondata.dir}" inheritAll="false" target="findbugs"/>
+        <copy file="${icu4j.regiondata.dir}/${out.dir}/fb-regiondata.html" todir="${findbugs.out.dir}"/>
+
+        <ant dir="${icu4j.translit.dir}" inheritAll="false" target="findbugs"/>
+        <copy file="${icu4j.translit.dir}/${out.dir}/fb-translit.html" todir="${findbugs.out.dir}"/>
+
+
+        <ant dir="${icu4j.charset.dir}" inheritAll="false" target="findbugs"/>
+        <copy file="${icu4j.charset.dir}/${out.dir}/fb-charset.html" todir="${findbugs.out.dir}"/>
+
+        <ant dir="${icu4j.localespi.dir}" inheritAll="false" target="findbugs"/>
+        <copy file="${icu4j.localespi.dir}/${out.dir}/fb-localespi.html" todir="${findbugs.out.dir}"/>
+    </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="currdata" depends="core" description="Build currency data classes">
+        <ant dir="${icu4j.currdata.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="langdata" depends="core" description="Build language data classes">
+        <ant dir="${icu4j.langdata.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, currdata, langdata, regiondata">
+        <ant dir="${icu4j.localespi.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="regiondata" depends="core" description="Build region data classes">
+        <ant dir="${icu4j.regiondata.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="packaging-tests" depends="test-framework" description="Build packaging tests">
+        <ant dir="${icu4j.packaging-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="testall" depends="test-framework" description="Build top level TestAll">
+        <ant dir="${icu4j.testall.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="samples" depends="core, charset, collate, translit" description="Build sample classes">
+        <ant dir="${icu4j.samples.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, collate, translit, translit-tests" description="Build tool classes">
+        <ant dir="${icu4j.tools.dir}" inheritAll="false"/>
+    </target>
+
+    <target name="perf-tests" if="is.java6.plus" depends="core, charset, collate, tools" description="Build performance test classes">
+        <ant dir="${icu4j.perf-tests.dir}" inheritAll="false"/>
+    </target>
+
+    <!-- doc targets -->
+    <target name="docs" depends="info, build-tools, _checkJCite, _docsWithJCite, _docsWithoutJCite" description="Build API documents"/>
+
+    <target name="_checkJCite" if="env.JCITE_DIR">
+        <fileset dir="${env.JCITE_DIR}" id="jcite.files">
+            <include name="build/*.jar"/>
+            <include name="lib/*.jar"/>
+        </fileset>
+        <pathconvert property="jcite.libs" refid="jcite.files"/>
+
+        <dirset dir="${basedir}" id="jcite.src.dirs">
+            <include name="samples/src"/>
+            <include name="demos/src"/>
+            <include name="main/tests/*/src"/>
+        </dirset>
+        <pathconvert property="jcite.addl.src" refid="jcite.src.dirs"/>
+    </target>
+
+    <target name="_docsStyleSheet">
+        <condition property="docs.style.sheet" value="stylesheet7.css" else="stylesheet.css">
+            <isset property="is.java7.plus"/>
+        </condition>
+    </target>
+
+    <!-- doclint in V8 is too strict to handle existing html in javadoc -->
+    <target name="_setLintV8" unless="is.pre.java8">
+        <property name="lintParam" value="-Xdoclint:-html"/>
+    </target>
+    <target name="_setLintPreV8" if="is.pre.java8">
+        <property name="lintParam" value=""/>
+    </target>
+    
+    <target name="_docsWithJCite" depends="_docsStyleSheet, _setLintV8, _setLintPreV8" if="jcite.libs">
+        <echo message="JCite library path:             ${jcite.libs}"/>
+        <echo message="JCite additional source path:   ${jcite.addl.src}"/>
+        <echo message="Custom stylesheet:              ${docs.style.sheet}"/>
+        <javadoc
+                destdir="${doc.dir}"
+                nodeprecatedlist="true"
+                windowtitle="${icu4j.api.doc.window.title}"
+                doctitle="${icu4j.api.doc.title}"
+                header="${icu4j.api.doc.header}"
+                encoding="${java.src.encoding}"
+                docencoding="UTF-8"
+                charset="UTF-8"
+                bottom="&lt;font size=-1&gt;Copyright (c) ${current.year} IBM Corporation and others.&lt;/font&gt;"
+                additionalparam="${lintParam} -breakiterator -use -tagletpath ${icu4j.build-tools.jar}${path.separator}${jcite.libs} -taglet com.ibm.icu.dev.tool.docs.ICUTaglet -taglet ch.arrenbrecht.jcite.JCiteTaglet -J-Djcitesourcepath=${jcite.addl.src} -J-Dfile.encoding=UTF-8"
+                link="${icu4j.api.doc.jdk.link}"
+                source="1.6"
+                bootclasspath="${java6.bootclasspath}"
+                stylesheetfile="${docs.style.sheet}">
+            <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>
+
+    <target name="_docsWithoutJCite" unless="jcite.libs">
+        <javadoc
+                destdir="${doc.dir}"
+                nodeprecatedlist="true"
+                windowtitle="${icu4j.api.doc.window.title}"
+                doctitle="${icu4j.api.doc.title}"
+                header="${icu4j.api.doc.header}"
+                encoding="${java.src.encoding}"
+                docencoding="UTF-8"
+                charset="UTF-8"
+                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="${icu4j.api.doc.jdk.link}"
+                source="1.6"
+                bootclasspath="${java6.bootclasspath}">
+            <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>
+
+    <!-- JaCoCo code coverage target -->
+    <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml" onerror="ignore">
+        <classpath path="${env.JACOCO_DIR}/lib/jacocoant.jar"/>
+    </taskdef>
+
+    <target name="coverageJaCoCo" depends="jar, tests" description="Run the ICU4J unit tests and generate code coverage report">
+        <property name="jacoco.out.dir" value="${out.dir}/jacoco"/>
+        <property name="jacoco.exec.data.file" value="${jacoco.out.dir}/jacoco.exec"/>
+        <property name="jacoco.report.html.zip" value="${jacoco.out.dir}/report_html.zip"/>
+        <property name="jacoco.report.xml" value="${jacoco.out.dir}/report.xml"/>
+        <property name="jacoco.report.csv" value="${jacoco.out.dir}/report.csv"/>
+
+        <delete dir="${jacoco.out.dir}"/>
+        <mkdir dir="${jacoco.out.dir}"/>
+
+        <jacoco:coverage destfile="${jacoco.exec.data.file}">
+            <java classname="com.ibm.icu.dev.test.TestAll" fork="yes" failonerror="true">
+                <jvmarg line="${jvm_options} -ea -Djava.awt.headless=true"/>
+                <classpath>
+                    <pathelement location="${icu4j.jar.file}"/>
+                    <pathelement location="${icu4j-charset.jar.file}"/>
+                    <pathelement location="${icu4j.test-framework.jar}"/>
+                    <pathelement location="${icu4j.core-tests.jar}"/>
+                    <pathelement location="${icu4j.collate-tests.jar}"/>
+                    <pathelement location="${icu4j.charset-tests.jar}"/>
+                    <pathelement location="${icu4j.translit-tests.jar}"/>
+                    <pathelement location="${icu4j.testall.jar}"/>
+            </classpath>
+        </java>
+        </jacoco:coverage>
+
+        <jacoco:report>
+            <executiondata>
+                <file file="${jacoco.exec.data.file}"/>
+            </executiondata>
+
+            <structure name="ICU4J Project">
+                <classfiles>
+                    <fileset dir=".">
+                        <include name="${icu4j.jar.file}"/>
+                        <include name="${icu4j-charset.jar.file}"/>
+                    </fileset>
+                </classfiles>
+                <sourcefiles encoding="UTF-8">
+                    <fileset dir="${icu4j.core.dir}/src"/>
+                    <fileset dir="${icu4j.collate.dir}/src"/>
+                    <fileset dir="${icu4j.currdata.dir}/src"/>
+                    <fileset dir="${icu4j.langdata.dir}/src"/>
+                    <fileset dir="${icu4j.regiondata.dir}/src"/>
+                    <fileset dir="${icu4j.translit.dir}/src"/>
+
+                    <fileset dir="${icu4j.charset.dir}/src"/>
+                </sourcefiles>
+            </structure>
+
+            <html destfile="${jacoco.report.html.zip}"/>
+            <xml destfile="${jacoco.report.xml}"/>
+            <csv destfile="${jacoco.report.csv}"/>
+        </jacoco:report>
+    </target>
+
+    <!-- Clover 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.currdata.dir}" inheritAll="false" inheritRefs="true">
+            <property name="build.compiler" value="${build.compiler}"/>
+        </ant>
+        <ant dir="${icu4j.langdata.dir}" inheritAll="false" inheritRefs="true">
+            <property name="build.compiler" value="${build.compiler}"/>
+        </ant>
+        <ant dir="${icu4j.regiondata.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>
+        <ant dir="${icu4j.testall.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">
+            <classpath>
+                <pathelement location="${icu4j.core.jar}"/>
+                <pathelement location="${icu4j.collate.jar}"/>
+                <pathelement location="${icu4j.charset.jar}"/>
+                <pathelement location="${icu4j.currdata.jar}"/>
+                <pathelement location="${icu4j.langdata.jar}"/>
+                <pathelement location="${icu4j.regiondata.jar}"/>
+                <pathelement location="${icu4j.translit.jar}"/>
+                <pathelement location="${icu4j.test-framework.jar}"/>
+                <pathelement location="${icu4j.core-tests.jar}"/>
+                <pathelement location="${icu4j.collate-tests.jar}"/>
+                <pathelement location="${icu4j.charset-tests.jar}"/>
+                <pathelement location="${icu4j.translit-tests.jar}"/>
+                <pathelement location="${icu4j.testall.jar}"/>
+                <pathelement location="${clover.jar}"/>
+            </classpath>
+        </java>
+
+        <!-- Generate HTML coverage report -->
+        <!-- <clover-html-report outdir="${clover.out.dir}/html" title="ICU4J Code Coverage"/> -->
+        <clover-report>
+            <current outfile="${clover.out.dir}/html" title="ICU4J Code Coverage">
+                <format type="html" filter="assert" />
+            </current>
+        </clover-report>
+    </target>
+
+    <!-- Release management targets -->
+    <target name="checktags" depends="info, build-tools" description="Check API tags before release">
+        <javadoc source="1.6"
+                 bootclasspath="${java6.bootclasspath}"
+                 encoding="${java.src.encoding}">
+            <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.6"
+                 bootclasspath="${java6.bootclasspath}"
+                 encoding="${java.src.encoding}">
+            <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/**"/>
+                <include name="com/ibm/icu/util/**"/>
+            </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/text/**"/>
+            </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}.api3"/>
+                <param name="-internal"/>
+                <param name="-version"/>
+                <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}.api3.gz" />
+            <arg value="-new:" />
+            <arg value="${out.dir}/icu4j${api.report.version}.api3.gz" />
+            <arg value="-html" />
+            <arg value="-out:" />
+            <arg value="${out.dir}/icu4j_compare_${api.report.prev.version}_${api.report.version}.html" />
+        </java>
+    </target>
+
+    <target name="gatherapiOld" depends="info, build-tools" description="Run API database generator tool (Pre Java 5 style)">
+        <mkdir dir="${out.dir}"/>
+        <javadoc source="1.6"
+                 bootclasspath="${java6.bootclasspath}"
+                 encoding="${java.src.encoding}">
+            <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/**"/>
+                <include name="com/ibm/icu/util/**"/>
+            </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/text/**"/>
+            </packageset>
+            <doclet name="com.ibm.icu.dev.tool.docs.GatherAPIDataOld" 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="apireportOld" depends="info, gatherapiOld" description="Run API report generator tool (Pre Java 5 Style)">
+        <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="checkDeprecated" depends="info, build-tools, gatherapi, main"
+        description="Check consistency between javadoc @deprecated and @Deprecated annotation">
+        <java classname="com.ibm.icu.dev.tool.docs.DeprecatedAPIChecker"
+                failonerror="true">
+            <arg value="${out.dir}/icu4j${api.report.version}.api3.gz" />
+            <classpath>
+                <pathelement location="${icu4j.build-tools.jar}"/>
+                <pathelement location="${icu4j.core.jar}"/>
+                <pathelement location="${icu4j.collate.jar}"/>
+                <pathelement location="${icu4j.charset.jar}"/>
+                <pathelement location="${icu4j.currdata.jar}"/>
+                <pathelement location="${icu4j.langdata.jar}"/>
+                <pathelement location="${icu4j.regiondata.jar}"/>
+                <pathelement location="${icu4j.translit.jar}"/>
+            </classpath>
+        </java>
+    </target>
+
+    <target name="draftAPIs" depends="info, gatherapi" description="Run API collector tool and generate draft API report">
+        <java classname="com.ibm.icu.dev.tool.docs.CollectAPI"
+                classpath="${icu4j.build-tools.jar}"
+                failonerror="true">
+            <arg value="-f"/>
+            <arg value="Draft"/>
+            <arg value="-o"/>
+            <arg value="${out.dir}/draftAPIs.html"/>
+            <arg value="${out.dir}/icu4j${api.report.version}.api3.gz" />
+        </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>
+
+    <target name="serialTestData" depends="main, tests">
+        <property name="serial.test.data.dir" value="${out.dir}/serialTestData"/>
+        <delete dir="${serial.test.data.dir}"/>
+        <mkdir dir="${serial.test.data.dir}"/>
+        <java classname="com.ibm.icu.dev.test.serializable.SerializableWriter" fork="yes" failonerror="true">
+            <arg line="${serial.test.data.dir}"/>
+            <classpath>
+                <pathelement location="${icu4j.core.jar}"/>
+                <pathelement location="${icu4j.collate.jar}"/>
+                <pathelement location="${icu4j.charset.jar}"/>
+                <pathelement location="${icu4j.currdata.jar}"/>
+                <pathelement location="${icu4j.langdata.jar}"/>
+                <pathelement location="${icu4j.regiondata.jar}"/>
+                <pathelement location="${icu4j.translit.jar}"/>
+                <pathelement location="${icu4j.test-framework.jar}"/>
+                <pathelement location="${icu4j.core-tests.jar}"/>
+            </classpath>
+        </java>
+        <echo message="Note: The serialization compatibility test data files were"/>
+        <echo message="created in ${serial.test.data.dir}. Once you confirm"/>
+        <echo message="the test runs clean, you should copy the data file directory to"/>
+        <echo message="main/tests/core/src/com/ibm/icu/dev/test/serializable/data."/>
+    </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}"
+                encoding="${java.src.encoding}"
+                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}"
+                encoding="${java.src.encoding}"
+                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="icu4jJar" description="Build Utilities for CLDR tooling">
+        <mkdir dir="${cldr.util.out.dir}/bin"/>
+        <javac destdir="${cldr.util.out.dir}/bin"
+                source="${javac.source}"
+                target="${javac.target}"
+                encoding="${java.src.encoding}"
+                debug="on" deprecation="off"
+                classpath="${icu4j.jar.file}">
+
+            <src path="${icu4j.tools.dir}/src"/>
+            <src path="${icu4j.translit-tests.dir}/src"/>
+            <src path="${icu4j.test-framework.dir}/src"/>
+
+            <include name="com/ibm/icu/dev/test/TestFmwk.java" />
+            <include name="com/ibm/icu/dev/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/*.class"/>
+            <include name="com/ibm/icu/dev/util/*.class"/>
+            <include name="com/ibm/icu/dev/tool/UOption*.class"/>
+        </jar>
+    </target>
+
+    <target name="releaseCLDR" depends="icu4jJar,icu4jSrcJar,cldrUtil" description="Build release files for CLDR tooling">
+        <mkdir dir="${cldr.release.dir}"/>
+        <!-- icu4j.jar -->
+        <copy file="${icu4j.jar.file}" todir="${cldr.release.dir}"/>
+        <!-- icu4j-src.jar -->
+        <copy file="${icu4j-src.jar.file}" todir="${cldr.release.dir}"/>
+        <!-- utilities.jar -->
+        <copy file="${cldr.util.out.dir}/lib/utilities.jar" todir="${cldr.release.dir}"/>
+        <!-- utilities-src.jar -->
+        <jar jarfile="${cldr.release.dir}/utilities-src.jar" compress="true">
+            <fileset dir="${icu4j.test-framework.dir}/${src.dir}">
+                <include name="com/ibm/icu/dev/test/TestFmwk.java"/>
+                <include name="com/ibm/icu/dev/test/*Log*.java"/>
+                <include name="com/ibm/icu/dev/test/TestUtil.java"/>
+                <include name="com/ibm/icu/dev/test/UTF16Util.java"/>
+            </fileset>
+            <fileset dir="${icu4j.test-framework.dir}/${src.dir}" includes="com/ibm/icu/dev/util/*.java"/>
+            <fileset dir="${icu4j.translit-tests.dir}/${src.dir}" includes="com/ibm/icu/dev/util/*.java"/>
+            <fileset dir="${icu4j.tools.dir}/${src.dir}" includes="com/ibm/icu/dev/tool/UOption.java"/>
+       </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"
+                encoding="${java.src.encoding}"
+                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="-nodata"/>
+            <classpath>
+                <pathelement location="${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}"
+                encoding="${java.src.encoding}"
+                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}"
+                encoding="${java.src.encoding}"
+                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"/>
+            <src path="${icu4j.testall.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}"
+                encoding="${java.src.encoding}"
+                debug="on" deprecation="off">
+            <include name="com/ibm/icu/impl/data/*Holiday*.java"/>
+            <include name="com/ibm/icu/impl/TimeZoneNames*.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>
+        <unjar src="${icu4j.tzdata.jar}" dest="${module.bin.dir}">
+            <patternset>
+                <include name="**/*.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}"
+                encoding="${java.src.encoding}"
+                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"/>
+            <src path="${icu4j.testall.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}"
+                encoding="${java.src.encoding}"
+                debug="on" deprecation="off">
+            <src path="${icu4j.core.dir}/src"/>
+            <src path="${icu4j.collate.dir}/src"/>
+
+            <include name="com/ibm/icu/impl/coll/*.java"/>
+            <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="**/*.nrm"/>
+                <include name="**/icudt${icu4j.data.version}b/res_index.res"/>
+                <include name="**/keyTypeData.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}"
+                encoding="${java.src.encoding}"
+                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"/>
+            <src path="${icu4j.testall.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/AlphabeticIndexTest.java"/>
+            <exclude name="com/ibm/icu/dev/test/collator/RandomCollator.java"/>
+            <exclude name="com/ibm/icu/dev/test/collator/IndexCharactersTest.java"/>
+        </javac>
+
+        <copy todir="${module.tests.dir}">
+            <fileset dir="${icu4j.collate-tests.dir}/src">
+                <include name="com/ibm/icu/dev/data/*.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}"
+                encoding="${java.src.encoding}"
+                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}"
+                encoding="${java.src.encoding}"
+                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"/>
+            <src path="${icu4j.testall.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}"
+                encoding="${java.src.encoding}"
+                debug="on" deprecation="off">
+            <include name="com/ibm/icu/impl/LocaleDisplayNamesImpl.java"/>
+            <include name="com/ibm/icu/impl/TimeZoneNames*.java"/>
+            <include name="com/ibm/icu/lang/UCharacter.java"/>
+            <include name="com/ibm/icu/text/BreakIteratorFactory.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>
+
+        <javac srcdir="${icu4j.regiondata.dir}/src"
+                destdir="${module.bin.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                encoding="${java.src.encoding}"
+                debug="on" deprecation="off"/>
+
+        <javac srcdir="${icu4j.currdata.dir}/src"
+                destdir="${module.bin.dir}"
+                source="${javac.source}"
+                target="${javac.target}"
+                encoding="${java.src.encoding}"
+                debug="on" deprecation="off"/>
+
+        <unjar src="${icu4j.data.jar}" dest="${module.bin.dir}">
+            <patternset>
+                <include name="**/*.icu"/>
+                <include name="**/*.brk"/>
+                <include name="**/*.res"/>
+                <exclude name="**/translit/*.res"/>
+            </patternset>
+        </unjar>
+        <unjar src="${icu4j.tzdata.jar}" dest="${module.bin.dir}">
+            <patternset>
+                <include name="**/*.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}"
+                encoding="${java.src.encoding}"
+                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"/>
+            <src path="${icu4j.testall.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"/>
+
+        <copy file="${icu4j.core-tests.dir}/src/com/ibm/icu/dev/data/numberformattestspecification.txt"
+                todir="${module.tests.dir}/com/ibm/icu/dev/data"/>
+
+    </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}"
+                encoding="${java.src.encoding}"
+                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="**/ubidi.icu"/>
+                <include name="**/ucase.icu"/>
+                <include name="**/unorm.icu"/>
+                <include name="**/uprops.icu"/>
+                <include name="**/pnames.icu"/>
+                <include name="**/unames.icu"/>
+                <include name="**/*.nrm"/>
+            </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}"
+                encoding="${java.src.encoding}"
+                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"/>
+            <src path="${icu4j.testall.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"/>
+            </fileset>
+        </copy>
+
+        <unjar src="${icu4j.testdata.jar}" dest="${module.tests.dir}">
+            <patternset>
+                <include name="**/testnorm.nrm"/>
+            </patternset>
+        </unjar>
+
+    </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"/>
+                <include name="**/*.nrm"/>
+            </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="**/*.dict"/>
+                <include name="**/*.nrm"/>
+                <exclude name="**/coll/*.res"/>
+                <exclude name="**/translit/*.res"/>
+                <exclude name="**/rbnf/*.res"/>
+            </patternset>
+        </unjar>
+        <unjar src="${icu4j.tzdata.jar}" dest="${module.bin.dir}">
+            <patternset>
+                <include name="**/*.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}"
+                encoding="${java.src.encoding}"
+                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}"
+                encoding="${java.src.encoding}"
+                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"/>
+            <src path="${icu4j.testall.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}"
+                encoding="${java.src.encoding}"
+                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="**/*.dict"/>
+                <include name="**/*.nrm"/>
+                <include name="**/brkitr/*.res"/>
+                <include name="**/translit/*.res"/>
+                <include name="**/likelySubtags.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}"
+                encoding="${java.src.encoding}"
+                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"/>
+            <src path="${icu4j.testall.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}"
+                encoding="${java.src.encoding}"
+                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}"
+                encoding="${java.src.encoding}"
+                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"/>
+            <src path="${icu4j.testall.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>
+
+    <target name="publishToMavenRepo" depends="releaseVer">
+        <!--
+            Publish libraries to Maven repositories, snapshot or release depending on current
+            version in pom.xml.
+
+            Prerequisites
+            
+            1) Apache Maven Ant tasks - http://maven.apache.org/ant-tasks
+            2) GnuPG
+            3) Put build-local.properties to specify followings
+            
+                maven-ant-tasks.jar = [location of maven ant tasks jar file]
+                gpg.user = ICU Project
+                gpg.passphrase = [passprase for ICU Project's PGP key]
+
+            4) Maven configuration file ~/.m2/settings.xml
+                <settings>
+                    <servers>
+                        <server>
+                            <id>icu4j-releases</id>
+                            <username>[your JIRA/Nexus ID]</username>
+                            <password>[your JIRA/Nexus password]</password>
+                        </server>
+                        <server>
+                            <id>icu4j-snapshots</id>
+                            <username>[your JIRA/Nexus ID]</username>
+                            <password>[your JIRA/Nexus password]</password>
+                        </server>
+                    </servers>
+                </settings>
+
+            Note: For now, charset.jar and localespi.jar are excluded.
+        -->
+        <fail message="Maven Ant Tasks are required to publish libraries. Set maven-ant-tasks.jar property. Maven Ant Tasks URL: http://maven.apache.org/ant-tasks/" unless="maven-ant-tasks.jar"/>
+        <condition property="no_maven-ant-tasks">
+            <available file="${maven-ant-tasks.jar}"/>
+        </condition>
+        <fail message="Maven Ant Tasks not found at ${maven-ant-tasks.jar}" unless="no_maven-ant-tasks"/>
+
+        <path id="maven-ant-tasks.classpath" path="${maven-ant-tasks.jar}"/>
+        <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant"
+            classpathref="maven-ant-tasks.classpath"/>
+
+        <xmlproperty file="pom.xml" prefix="pom.xml"/>
+
+        <!-- copy release files -->
+        <property name="maven.release.dir" value="${release.dir}/maven"/>
+
+        <property name="maven.icu4j.jar.versioned.file" value="icu4j-${pom.xml.project.version}.jar"/>
+        <property name="maven.icu4j-src.jar.versioned.file" value="icu4j-${pom.xml.project.version}-src.jar"/>
+        <property name="maven.icu4jdocs.jar.file" value="icu4j-${pom.xml.project.version}-javadoc.jar"/>
+
+        <mkdir dir="${maven.release.dir}"/>
+
+        <copy file="${release.dir}/${icu4j.jar.versioned.file}" tofile="${maven.release.dir}/${maven.icu4j.jar.versioned.file}"/>
+        <copy file="${release.dir}/${icu4j-src.jar.versioned.file}" tofile="${maven.release.dir}/${maven.icu4j-src.jar.versioned.file}"/>
+        <copy file="${release.dir}/${icu4jdocs.jar.versioned.file}" tofile="${maven.release.dir}/${maven.icu4jdocs.jar.file}"/>
+
+        <copy file="pom.xml" todir="${maven.release.dir}"/>
+
+        <!-- sign release files-->
+        <macrodef name="gpg">
+            <attribute name="file"/>
+            <sequential>
+                <delete file="@{file}.asc" failonerror="false"/>
+                <exec executable="gpg">
+                    <arg value="-u"/>
+                    <arg value="${gpg.user}"/>
+                    <arg value="-ab"/>
+                    <arg value="--passphrase"/>
+                    <arg value="${gpg.passphrase}"/>
+                    <arg value="-o"/>
+                    <arg value="@{file}.asc"/>
+                    <arg value="@{file}"/>
+                </exec>
+            </sequential>
+        </macrodef>
+
+        <gpg file="${maven.release.dir}/${maven.icu4j.jar.versioned.file}"/>
+        <gpg file="${maven.release.dir}/${maven.icu4j-src.jar.versioned.file}"/>
+        <gpg file="${maven.release.dir}/${maven.icu4jdocs.jar.file}"/>
+
+        <gpg file="${maven.release.dir}/pom.xml"/>
+
+        <!-- deploy files to the repository -->
+        <deploy xmlns="urn:maven-artifact-ant" file="${maven.release.dir}/${maven.icu4j.jar.versioned.file}">
+            <pom file="${maven.release.dir}/pom.xml"/>
+            <attach file="${maven.release.dir}/pom.xml.asc" type="pom.asc"/>
+
+            <attach file="${maven.release.dir}/${maven.icu4j.jar.versioned.file}.asc" type="jar.asc"/>
+            <attach file="${maven.release.dir}/${maven.icu4j-src.jar.versioned.file}" classifier="sources"/>
+            <attach file="${maven.release.dir}/${maven.icu4j-src.jar.versioned.file}.asc" classifier="sources" type="jar.asc"/>
+            <attach file="${maven.release.dir}/${maven.icu4jdocs.jar.file}" classifier="javadoc"/>
+            <attach file="${maven.release.dir}/${maven.icu4jdocs.jar.file}.asc" classifier="javadoc" type="jar.asc"/>
+        </deploy>
+
+        <antcall target="_verify_config_for_release"/>
+    </target>
+
+</project>
diff --git a/demos/.classpath b/demos/.classpath
new file mode 100644
index 0000000..c15c97e
--- /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/JavaSE-1.6"/>
+	<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.core.resources.prefs b/demos/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..2d2d78c
--- /dev/null
+++ b/demos/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+#Fri Nov 05 14:18:21 EDT 2010
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/demos/.settings/org.eclipse.jdt.core.prefs b/demos/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..8e21554
--- /dev/null
+++ b/demos/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,358 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+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.explicitlyClosedAutoCloseable=ignore
+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.includeNullInfoFromAsserts=disabled
+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.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+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.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=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.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+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.unusedObjectAllocation=ignore
+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.unusedTypeParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.6
+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_field=insert
+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_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=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_annotation_on_type=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..73e8bc9
--- /dev/null
+++ b/demos/build.xml
@@ -0,0 +1,31 @@
+<!--
+*******************************************************************************
+* Copyright (C) 2009-2011, 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.name" value="icu4j-${ant.project.name}.jar"/>
+    <property name="src.jar.name" value="icu4j-${ant.project.name}-src.jar"/>
+
+    <target name="build" depends="compile, copy, jar, src-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"/>
+
+    <target name="src-jar" depends="@src-jar" description="Create the project's source 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..51b22ca
--- /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..bd5512a
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/Launcher.java
@@ -0,0 +1,187 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2007-2011, 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",
+        "rbnf.RbnfDemo",
+        "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..2940d59
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/calendar/CalendarApp.java
@@ -0,0 +1,37 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2010, 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.DemoApplet;
+
+/**
+ * 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..284d16d
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/charsetdet/DetectingViewer.java
@@ -0,0 +1,421 @@
+/*
+ **************************************************************************
+ * Copyright (C) 2005-2010, International Business Machines Corporation   *
+ * and others. All Rights Reserved.                                       *
+ **************************************************************************
+ *
+ */
+
+package com.ibm.icu.dev.demo.charsetdet;
+
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.security.AccessControlException;
+
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JScrollPane;
+import javax.swing.JTextPane;
+import javax.swing.KeyStroke;
+
+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..cd81ef1
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/holiday/HolidayBorderPanel.java
@@ -0,0 +1,552 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2010, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.holiday;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.Panel;
+
+/**
+ * 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..67fe6d8
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/holiday/HolidayCalendarDemo.java
@@ -0,0 +1,738 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2014, 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.DateTimePatternGenerator;
+import com.ibm.icu.text.SimpleDateFormat;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.Holiday;
+
+/**
+ * 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()
+        {
+            final Locale displayLocale = calendarPanel.getDisplayLocale();
+            final String pattern = DateTimePatternGenerator.
+                    getInstance(displayLocale).getBestPattern("MMMMy");
+            SimpleDateFormat f = new SimpleDateFormat(pattern,
+                                                        displayLocale);
+            f.setCalendar(calendarPanel.getCalendar());
+            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()
+        {
+            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)
+                {
+                    if(d.after(endOfMonth)) {
+                        throw new InternalError("Error: for " + fAllHolidays[h].getDisplayName()+
+                                "  #" + h + "/"+fAllHolidays.length+": " + d +" is after end of month " + endOfMonth);
+                    }
+                    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;
+
+                // 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);
+                    }
+                    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..d408936
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/AppletFrame.java
@@ -0,0 +1,149 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2010, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.impl;
+import java.applet.Applet;
+import java.applet.AppletContext;
+import java.applet.AppletStub;
+import java.applet.AudioClip;
+import java.awt.Frame;
+import java.awt.Image;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Iterator;
+
+/**
+ * <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..339e6a7
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/DemoApplet.java
@@ -0,0 +1,80 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2010, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+
+package com.ibm.icu.dev.demo.impl;
+
+import java.awt.Button;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+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..a3d8349
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/DemoTextBox.java
@@ -0,0 +1,96 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2010, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.impl;
+
+
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.text.BreakIterator;
+
+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..2014b35
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/DemoUtility.java
@@ -0,0 +1,141 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2014, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.impl;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Label;
+import java.awt.Panel;
+import java.awt.TextComponent;
+import java.util.Locale;
+
+import com.ibm.icu.util.Calendar;
+
+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;
+
+    private static final int getCurrentYear() {
+        return Calendar.getInstance().get(Calendar.YEAR);
+    }
+    public static final String copyright1 =
+        "Copyright (C) IBM Corp and others. 1997 - "+getCurrentYear()+" 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..e6147be
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/DumbTextComponent.java
@@ -0,0 +1,827 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2010, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.impl;
+import java.awt.AWTEventMulticaster;
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.TextEvent;
+import java.awt.event.TextListener;
+import java.text.BreakIterator;
+
+// 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..c07b770
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/impl/Selection.java
@@ -0,0 +1,161 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2010, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.impl;
+import java.text.BreakIterator;
+
+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..6e36765
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/number/CurrencyDemo.java
@@ -0,0 +1,114 @@
+/*
+**********************************************************************
+* Copyright (c) 2003-2010, 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 java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import com.ibm.icu.impl.Utility;
+import com.ibm.icu.text.DecimalFormat;
+import com.ibm.icu.text.DecimalFormatSymbols;
+import com.ibm.icu.text.NumberFormat;
+import com.ibm.icu.util.Currency;
+
+/**
+ * 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..76f8f01
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/rbnf/RbnfDemo.java
@@ -0,0 +1,580 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2010, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.rbnf;
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.CardLayout;
+import java.awt.Checkbox;
+import java.awt.Choice;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.GridLayout;
+import java.awt.Panel;
+import java.awt.ScrollPane;
+import java.awt.TextArea;
+import java.awt.TextComponent;
+import java.awt.TextField;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.TextEvent;
+import java.awt.event.TextListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.text.BreakIterator;
+import java.text.DecimalFormat;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+import com.ibm.icu.dev.demo.impl.DemoApplet;
+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/translit/AnyTransliterator.java b/demos/src/com/ibm/icu/dev/demo/translit/AnyTransliterator.java
new file mode 100644
index 0000000..3f458d8
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/translit/AnyTransliterator.java
@@ -0,0 +1,308 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2010, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.translit;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import com.ibm.icu.lang.UScript;
+import com.ibm.icu.text.Replaceable;
+import com.ibm.icu.text.Transliterator;
+import com.ibm.icu.text.UTF16;
+import com.ibm.icu.text.UnicodeFilter;
+
+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..b2b477a
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/translit/CaseIterator.java
@@ -0,0 +1,560 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2010, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*/
+
+package com.ibm.icu.dev.demo.translit;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import com.ibm.icu.lang.UCharacter;
+import com.ibm.icu.text.Transliterator;
+import com.ibm.icu.text.UTF16;
+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..70d5e9c
--- /dev/null
+++ b/demos/src/com/ibm/icu/dev/demo/translit/Demo.java
@@ -0,0 +1,1426 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2012, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.demo.translit;
+
+import java.awt.Button;
+import java.awt.CheckboxMenuItem;
+import java.awt.FileDialog;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.GraphicsEnvironment;
+import java.awt.Label;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.MenuShortcut;
+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.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.text.CharacterIterator;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import com.ibm.icu.impl.Differ;
+import com.ibm.icu.lang.UCharacter;
+import com.ibm.icu.text.BreakIterator;
+import com.ibm.icu.text.CanonicalIterator;
+import com.ibm.icu.text.Normalizer;
+import com.ibm.icu.text.ReplaceableString;
+import com.ibm.icu.text.Transliterator;
+import com.ibm.icu.text.UTF16;
+import com.ibm.icu.text.UnicodeSet;
+import com.ibm.icu.text.UnicodeSetIterator;
+
+/**
+ * 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) {
+        BufferedReader in = null;
+        try {
+            
+            System.out.println("Reading: " + sourceFile.getCanonicalPath());
+            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();
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (Exception e) {
+                    // ignore
+                }
+            }
+        }
+    }
+    
+    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));