ICU-10103 Merging all maint-50 changes up to 50.1.1 (r32977) and the latest tzdata (2013b) + necessary test code patch (r33396) to eclpse-icu50 stream.

X-SVN-Rev: 33525
diff --git a/build.properties b/build.properties
index 8381bb9..dd8a3b0 100644
--- a/build.properties
+++ b/build.properties
@@ -4,6 +4,6 @@
 #*******************************************************************************

 api.report.version = 50

 api.report.prev.version = 49

-release.file.ver = 50_1

+release.file.ver = 50_1_1

 api.doc.version = 50

 

diff --git a/eclipse-build/build.properties b/eclipse-build/build.properties
index 39a970b..34aade8 100644
--- a/eclipse-build/build.properties
+++ b/eclipse-build/build.properties
@@ -1,8 +1,8 @@
 #*******************************************************************************
-#* Copyright (C) 2010-2012, International Business Machines Corporation and    *
+#* Copyright (C) 2010-2013, International Business Machines Corporation and    *
 #* others. All Rights Reserved.                                                *
 #*******************************************************************************
-icu4j.plugin.impl.version.string=50.1.0
+icu4j.plugin.impl.version.string=50.1.1
 copyright.eclipse=Licensed Materials - Property of IBM \n (C) Copyright IBM Corp. 2000, 2012. All Rights Reserved. \n IBM is a registered trademark of IBM Corp.
 icu4j.data.version.number=50
-icu4j.eclipse.build.version.string=50.1.0.v20121116
+icu4j.eclipse.build.version.string=50.1.1.v20130412
diff --git a/eclipse-build/misc/about_icu.html b/eclipse-build/misc/about_icu.html
index 288c8ff..6d17ca7 100644
--- a/eclipse-build/misc/about_icu.html
+++ b/eclipse-build/misc/about_icu.html
@@ -8,7 +8,7 @@
 <body lang="EN-US">
 <h2>About This Content</h2>
  
-<p>November 16, 2012</p>	
+<p>April 12, 2013</p>
 <h3>License</h3>
 
 <p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;).  Unless otherwise 
@@ -31,13 +31,13 @@
 		for informational purposes only, and you should look to the Redistributor's license for 
 		terms and conditions of use.</p>
 
-		<p><strong>ICU4J 50.1.0.v20121116 plug-in</strong> <br/><br/>
+		<p><strong>ICU4J 50.1.1.v20130412 plug-in</strong> <br/><br/>
 		The plug-in includes software (&quot;ICU4J&quot;) developed by International Business Machines
 		Corporation and others.
 		<br/><br/>
 		ICU4J is:
 		<blockquote>
-		Copyright (c) 1995-2012 International Business Machines Corporation and others<br/>
+		Copyright (c) 1995-2013 International Business Machines Corporation and others<br/>
 		All rights reserved.
 		</blockquote>
 		<p>
diff --git a/eclipse-build/misc/about_icu_base.html b/eclipse-build/misc/about_icu_base.html
index 8ba6f6d..56f4cbd 100644
--- a/eclipse-build/misc/about_icu_base.html
+++ b/eclipse-build/misc/about_icu_base.html
@@ -8,7 +8,7 @@
 <body lang="EN-US">
 <h2>About This Content</h2>
  
-<p>November 16, 2012</p>
+<p>April 12, 2013</p>
 <h3>License</h3>
 
 <p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;).  Unless otherwise 
@@ -31,13 +31,13 @@
 		for informational purposes only, and you should look to the Redistributor's license for 
 		terms and conditions of use.</p>
 
-		<p><strong>ICU4J 50.1.0.v20121116 base plug-in</strong> <br/><br/>
+		<p><strong>ICU4J 50.1.1.v20130412 base plug-in</strong> <br/><br/>
 		The plug-in includes software (&quot;ICU4J&quot;) developed by International Business Machines
 		Corporation and others.
 		<br/><br/>
 		ICU4J is:
 		<blockquote>
-		Copyright (c) 1995-2012 International Business Machines Corporation and others<br/>
+		Copyright (c) 1995-2013 International Business Machines Corporation and others<br/>
 		All rights reserved. 
 		</blockquote>
 		<p>
diff --git a/main/classes/core/src/com/ibm/icu/text/FilteredNormalizer2.java b/main/classes/core/src/com/ibm/icu/text/FilteredNormalizer2.java
index b5ee32d..dea4e60 100644
--- a/main/classes/core/src/com/ibm/icu/text/FilteredNormalizer2.java
+++ b/main/classes/core/src/com/ibm/icu/text/FilteredNormalizer2.java
@@ -277,7 +277,8 @@
                     norm2.append(first, prefix);
                 }
             } else {
-                StringBuilder middle=new StringBuilder(first.subSequence(suffixStart, 0x7fffffff));
+                StringBuilder middle=new StringBuilder(
+                        first.subSequence(suffixStart, first.length()));
                 if(doNormalize) {
                     norm2.normalizeSecondAndAppend(middle, prefix);
                 } else {
@@ -287,7 +288,7 @@
             }
         }
         if(prefixLimit<second.length()) {
-            CharSequence rest=second.subSequence(prefixLimit, 0x7fffffff);
+            CharSequence rest=second.subSequence(prefixLimit, second.length());
             if(doNormalize) {
                 normalize(rest, first, UnicodeSet.SpanCondition.NOT_CONTAINED);
             } else {
diff --git a/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java b/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
index 0a8de3a..9306473 100644
--- a/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
+++ b/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
@@ -1640,33 +1640,9 @@
             } else {
                 // Handle literal pattern text literal
                 numericFieldStart = -1;
-
-                String patl = (String)items[i];
-                int plen = patl.length();
-                int tlen = text.length();
-                int idx = 0;
-                while (idx < plen && pos < tlen) {
-                    char pch = patl.charAt(idx);
-                    char ich = text.charAt(pos);
-                    if (PatternProps.isWhiteSpace(pch)
-                        && PatternProps.isWhiteSpace(ich)) {
-                        // White space characters found in both patten and input.
-                        // Skip contiguous white spaces.
-                        while ((idx + 1) < plen &&
-                                PatternProps.isWhiteSpace(patl.charAt(idx + 1))) {
-                             ++idx;
-                        }
-                        while ((pos + 1) < tlen &&
-                                PatternProps.isWhiteSpace(text.charAt(pos + 1))) {
-                             ++pos;
-                        }
-                    } else if (pch != ich) {
-                        break;
-                    }
-                    ++idx;
-                    ++pos;
-                }
-                if (idx != plen) {
+                boolean[] complete = new boolean[1];
+                pos = matchLiteral(text, pos, items, i, complete);
+                if (!complete[0]) {
                     // Set the position of mismatch
                     parsePos.setIndex(start);
                     parsePos.setErrorIndex(pos);
@@ -1678,6 +1654,18 @@
             }
             ++i;
         }
+        
+        // Special hack for trailing "." after non-numeric field.
+        if (pos < text.length()) {
+            char extra = text.charAt(pos);
+            if (extra == '.' && isLenient() && items.length != 0) {
+                // only do if the last field is not numeric
+                Object lastItem = items[items.length - 1];
+                if (lastItem instanceof PatternItem && !((PatternItem)lastItem).isNumeric) {
+                    pos++; // skip the extra "."
+                }
+            }
+        }
 
         // At this point the fields of Calendar have been set.  Calendar
         // will fill in default values for missing fields when the time
@@ -1855,6 +1843,88 @@
     }
 
     /**
+     * Matches text (starting at pos) with patl. Returns the new pos, and sets complete[0]
+     * if it matched the entire text. Whitespace sequences are treated as singletons.
+     * <p>If isLenient and if we fail to match the first time, some special hacks are put into place.
+     * <ul><li>we are between date and time fields, then one or more whitespace characters
+     * in the text are accepted instead.</li>
+     * <ul><li>we are after a non-numeric field, and the text starts with a ".", we skip it.</li>
+     * </ul>
+     * @param text
+     * @param pos
+     * @param patternLiteral
+     * @param complete
+     * @return
+     */
+    private int matchLiteral(String text, int pos, Object[] items, int itemIndex, boolean[] complete) {
+        int originalPos = pos;
+        String patternLiteral = (String)items[itemIndex];
+        int plen = patternLiteral.length();
+        int tlen = text.length();
+        int idx = 0;
+        while (idx < plen && pos < tlen) {
+            char pch = patternLiteral.charAt(idx);
+            char ich = text.charAt(pos);
+            if (PatternProps.isWhiteSpace(pch)
+                && PatternProps.isWhiteSpace(ich)) {
+                // White space characters found in both patten and input.
+                // Skip contiguous white spaces.
+                while ((idx + 1) < plen &&
+                        PatternProps.isWhiteSpace(patternLiteral.charAt(idx + 1))) {
+                     ++idx;
+                }
+                while ((pos + 1) < tlen &&
+                        PatternProps.isWhiteSpace(text.charAt(pos + 1))) {
+                     ++pos;
+                }
+            } else if (pch != ich) {
+                if (ich == '.' && pos == originalPos && 0 < itemIndex && isLenient()) {
+                    Object before = items[itemIndex-1];
+                    if (before instanceof PatternItem) {
+                        boolean isNumeric = ((PatternItem) before).isNumeric;
+                        if (!isNumeric) {
+                            ++pos; // just update pos
+                            continue;
+                        }
+                    }
+                }
+                break;
+            }
+            ++idx;
+            ++pos;
+        }
+        complete[0] = idx == plen;
+        if (complete[0] == false && isLenient() && 0 < itemIndex && itemIndex < items.length - 1) {
+            // If fully lenient, accept " "* for any text between a date and a time field
+            // We don't go more lenient, because we don't want to accept "12/31" for "12:31".
+            // People may be trying to parse for a date, then for a time.
+            if (originalPos < tlen) {
+                Object before = items[itemIndex-1];
+                Object after = items[itemIndex+1];
+                if (before instanceof PatternItem && after instanceof PatternItem) {
+                    char beforeType = ((PatternItem) before).type;
+                    char afterType = ((PatternItem) after).type;
+                    if (DATE_PATTERN_TYPE.contains(beforeType) != DATE_PATTERN_TYPE.contains(afterType)) {
+                        int newPos = originalPos;
+                        while (true) {
+                            char ich = text.charAt(newPos);
+                            if (!PatternProps.isWhiteSpace(ich)) {
+                                break;
+                            }
+                            ++newPos;
+                        }
+                        complete[0] = newPos > originalPos;
+                        pos = newPos;
+                    }
+                }
+            }
+        }
+        return pos;
+    }
+    
+    static final UnicodeSet DATE_PATTERN_TYPE = new UnicodeSet("[GyYuUQqMLlwWd]").freeze();
+
+    /**
      * Attempt to match the text at a given position against an array of
      * strings.  Since multiple strings in the array may match (for
      * example, if the array contains "a", "ab", and "abc", all will match
@@ -1910,6 +1980,7 @@
         // unfortunately requires us to test all array elements.
         int bestMatchLength = 0, bestMatch = -1;
         int isLeapMonth = 0;
+        int matchLength = 0;
 
         for (; i<count; ++i)
             {
@@ -1917,20 +1988,20 @@
                 // Always compare if we have no match yet; otherwise only compare
                 // against potentially better matches (longer strings).
                 if (length > bestMatchLength &&
-                    text.regionMatches(true, start, data[i], 0, length))
+                    (matchLength = regionMatchesWithOptionalDot(text, start, data[i], length)) >= 0)
                     {
                         bestMatch = i;
-                        bestMatchLength = length;
+                        bestMatchLength = matchLength;
                         isLeapMonth = 0;
                     }
                 if (monthPattern != null) {
                     String leapMonthName = MessageFormat.format(monthPattern, data[i]);
                     length = leapMonthName.length();
                     if (length > bestMatchLength &&
-                        text.regionMatches(true, start, leapMonthName, 0, length))
+                        (matchLength = regionMatchesWithOptionalDot(text, start, leapMonthName, length)) >= 0)
                         {
                             bestMatch = i;
-                            bestMatchLength = length;
+                            bestMatchLength = matchLength;
                             isLeapMonth = 1;
                         }
                  }
@@ -1949,6 +2020,19 @@
         return -start;
     }
 
+    private int regionMatchesWithOptionalDot(String text, int start, String data, int length) {
+        boolean matches = text.regionMatches(true, start, data, 0, length);
+        if (matches) {
+            return length;
+        }
+        if (data.length() > 0 && data.charAt(data.length()-1) == '.') {
+            if (text.regionMatches(true, start, data, 0, length-1)) {
+                return length - 1;
+            }
+        }
+        return -1;
+    }
+
     /**
      * Attempt to match the text at a given position against an array of quarter
      * strings.  Since multiple strings in the array may match (for
@@ -1976,14 +2060,16 @@
         // We keep track of the longest match, and return that.  Note that this
         // unfortunately requires us to test all array elements.
         int bestMatchLength = 0, bestMatch = -1;
+        int matchLength = 0;
         for (; i<count; ++i) {
             int length = data[i].length();
             // Always compare if we have no match yet; otherwise only compare
             // against potentially better matches (longer strings).
             if (length > bestMatchLength &&
-                text.regionMatches(true, start, data[i], 0, length)) {
+                (matchLength = regionMatchesWithOptionalDot(text, start, data[i], length)) >= 0) {
+
                 bestMatch = i;
-                bestMatchLength = length;
+                bestMatchLength = matchLength;
             }
         }
 
diff --git a/main/classes/core/src/com/ibm/icu/util/Currency.java b/main/classes/core/src/com/ibm/icu/util/Currency.java
index 293bf02..ca648e5 100644
--- a/main/classes/core/src/com/ibm/icu/util/Currency.java
+++ b/main/classes/core/src/com/ibm/icu/util/Currency.java
@@ -29,6 +29,7 @@
 import com.ibm.icu.text.CurrencyMetaInfo;
 import com.ibm.icu.text.CurrencyMetaInfo.CurrencyDigits;
 import com.ibm.icu.text.CurrencyMetaInfo.CurrencyFilter;
+import com.ibm.icu.text.CurrencyMetaInfo.CurrencyInfo;
 import com.ibm.icu.util.ULocale.Category;
 
 /**
@@ -159,9 +160,8 @@
      * @stable ICU 4.0
      */
     public static String[] getAvailableCurrencyCodes(ULocale loc, Date d) {
-        CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
         CurrencyFilter filter = CurrencyFilter.onDate(d).withRegion(loc.getCountry());
-        List<String> list = info.currencies(filter);
+        List<String> list = getTenderCurrencies(filter);
         // Note: Prior to 4.4 the spec didn't say that we return null if there are no results, but 
         // the test assumed it did.  Kept the behavior and amended the spec.
         if (list.isEmpty()) {
@@ -356,7 +356,6 @@
             return EMPTY_STRING_ARRAY;
         }
         
-        CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
         if (!commonlyUsed) {
             // Behavior change from 4.3.3, no longer sort the currencies
             return getAvailableCurrencyCodes().toArray(new String[0]);
@@ -377,7 +376,7 @@
         
         // currencies are in region's preferred order when we're filtering on region, which
         // matches our spec
-        List<String> result = info.currencies(filter);
+        List<String> result = getTenderCurrencies(filter);
         
         // No fallback anymore (change from 4.3.3)
         if (result.size() == 0) {
@@ -836,16 +835,16 @@
 
     private static SoftReference<List<String>> ALL_CODES;
     /*
-     * Returns an unmodifiable String list including all known currency codes
+     * Returns an unmodifiable String list including all known tender currency codes.
      */
     private static synchronized List<String> getAvailableCurrencyCodes() {
         List<String> all = (ALL_CODES == null) ? null : ALL_CODES.get();
         if (all == null) {
-            CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
             // Filter out non-tender currencies which have "from" date set to 9999-12-31
             // CurrencyFilter has "to" value set to 9998-12-31 in order to exclude them
-            CurrencyFilter filter = CurrencyFilter.onDateRange(null, new Date(253373299200000L));
-            all = Collections.unmodifiableList(info.currencies(filter));
+            //CurrencyFilter filter = CurrencyFilter.onDateRange(null, new Date(253373299200000L));
+            CurrencyFilter filter = CurrencyFilter.all();
+            all = Collections.unmodifiableList(getTenderCurrencies(filter));
             ALL_CODES = new SoftReference<List<String>>(all);
         }
         return all;
@@ -894,5 +893,24 @@
         List<String> allActive = info.currencies(CurrencyFilter.onDateRange(from, to));
         return allActive.contains(code);
     }
+
+    /**
+     * Returns the list of remaining tender currencies after a filter is applied.
+     * @param filter the filter to apply to the tender currencies
+     * @return a list of tender currencies
+     */
+    private static List<String> getTenderCurrencies(CurrencyFilter filter) {
+        CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
+        List<CurrencyInfo> infoList = info.currencyInfo(filter);
+        List<String> list = new ArrayList<String>();
+        for (CurrencyInfo currencyInfo : infoList) {
+            // Non-tender currencies always have a from of MIN_VALUE and a to of MAX_VALUE, so
+            // exclude them.
+            if (currencyInfo.from != Long.MIN_VALUE || currencyInfo.to != Long.MAX_VALUE) {
+                list.add(currencyInfo.code);
+            }
+        }
+        return list;
+    }
 }
 //eof
diff --git a/main/classes/core/src/com/ibm/icu/util/LocaleData.java b/main/classes/core/src/com/ibm/icu/util/LocaleData.java
index 786cb50..b083b71 100644
--- a/main/classes/core/src/com/ibm/icu/util/LocaleData.java
+++ b/main/classes/core/src/com/ibm/icu/util/LocaleData.java
@@ -45,13 +45,14 @@
 
     /**
      * EXType for {@link #getExemplarSet(int, int)}.
-     * @stable ICU 3.4
+     * @stable ICU 4.4
      */
    public static final int ES_INDEX = 2;
 
    /**
     * EXType for {@link #getExemplarSet(int, int)}.
-    * @stable ICU 3.4
+    * Note: This type is no longer supported.
+    * @stable ICU 4.4
     */
     public static final int ES_CURRENCY = 3;
 
@@ -156,7 +157,7 @@
      *                  IGNORE_SPACE bit is always set, regardless of the
      *                  value of 'options'.
      * @param extype    The type of exemplar set to be retrieved,
-     *                  ES_STANDARD, ES_INDEX, ES_CURRENCY,  or ES_AUXILIARY
+     *                  ES_STANDARD, ES_INDEX, ES_AUXILIARY, or ES_PUNCTUATION
      * @return          The set of exemplar characters for the given locale.
      * @stable ICU 3.4
      */
@@ -167,6 +168,11 @@
             "ExemplarCharactersPunctuation"
         };
 
+        if (extype == ES_CURRENCY) {
+            // currency symbol exemplar is no longer available
+            return new UnicodeSet();
+        }
+
         try{
             ICUResourceBundle stringBundle = (ICUResourceBundle) bundle.get(exemplarSetTypes[extype]);
     
@@ -195,7 +201,7 @@
         }
     }
     
-    static final Pattern US_SYNTAX = Pattern.compile(" ([\\-\\&\\{\\}\\[\\]])");
+    static final Pattern US_SYNTAX = Pattern.compile(" ([\\-\\&\\{\\}\\[\\]\\\\])");
 
     /**
      * Gets the LocaleData object associated with the ULocale specified in locale
diff --git a/main/classes/core/src/com/ibm/icu/util/VersionInfo.java b/main/classes/core/src/com/ibm/icu/util/VersionInfo.java
index 8bf9c9f..7b4aed8 100644
--- a/main/classes/core/src/com/ibm/icu/util/VersionInfo.java
+++ b/main/classes/core/src/com/ibm/icu/util/VersionInfo.java
@@ -502,8 +502,8 @@
         UNICODE_6_1   = getInstance(6, 1, 0, 0);
         UNICODE_6_2   = getInstance(6, 2, 0, 0);
 
-        ICU_VERSION   = getInstance(50, 1, 0, 0);
-        ICU_DATA_VERSION = getInstance(50, 1, 0, 0);
+        ICU_VERSION   = getInstance(50, 1, 1, 0);
+        ICU_DATA_VERSION = getInstance(50, 1, 1, 0);
         UNICODE_VERSION = UNICODE_6_2;
 
         UCOL_RUNTIME_VERSION = getInstance(7);
diff --git a/main/classes/currdata/src/com/ibm/icu/impl/ICUCurrencyMetaInfo.java b/main/classes/currdata/src/com/ibm/icu/impl/ICUCurrencyMetaInfo.java
index 338141c..8821704 100644
--- a/main/classes/currdata/src/com/ibm/icu/impl/ICUCurrencyMetaInfo.java
+++ b/main/classes/currdata/src/com/ibm/icu/impl/ICUCurrencyMetaInfo.java
@@ -147,30 +147,7 @@
             return defaultValue;
         }
         int[] values = b.getIntVector();
-        long time = ((long) values[0] << 32) | (((long) values[1]) & MASK);
-        
-        // TODO: remove once errors in CLDR data are fixed.  Or push this into ICU data generation.
-        // The CLDR data parses month as minutes.  We should be getting minutes = 0, so if we detect
-        // that the minute value is nonzero, this means we have bad data and the minute value is really
-        // the month value.
-        GregorianCalendar cal = new GregorianCalendar();
-        cal.setTimeZone(TimeZone.getTimeZone("GMT"));
-        cal.setTimeInMillis(time);
-        int minute = cal.get(Calendar.MINUTE);
-        if (minute != 0) {
-            cal.set(Calendar.MINUTE, 0);
-            cal.set(Calendar.MONTH, minute - 1); // months are 1-based
-            time = cal.getTimeInMillis();
-        }
-        // TODO: generate in CLDR data rather than here, remove endOfDay flag.
-        if (endOfDay) {
-            cal.set(Calendar.HOUR_OF_DAY, 23);
-            cal.set(Calendar.MINUTE, 59);
-            cal.set(Calendar.SECOND, 59);
-            cal.set(Calendar.MILLISECOND, 999);
-            time = cal.getTimeInMillis();
-        }
-        return time;
+        return ((long) values[0] << 32) | (((long) values[1]) & MASK);
     }
 
     // Utility, just because I don't like the n^2 behavior of using list.contains to build a
diff --git a/main/shared/build/common.properties b/main/shared/build/common.properties
index 3095b8e..c88e3c4 100644
--- a/main/shared/build/common.properties
+++ b/main/shared/build/common.properties
@@ -5,7 +5,7 @@
 
 # Version numbers, etc.
 icu4j.spec.version = 50
-icu4j.impl.version = 50.1
+icu4j.impl.version = 50.1.1
 icu4j.data.version = 50
 current.year = 2012
 default.exec.env = J2SE-1.5
diff --git a/main/shared/data/icudata.jar b/main/shared/data/icudata.jar
index 6f90488..02c965d 100755
--- a/main/shared/data/icudata.jar
+++ b/main/shared/data/icudata.jar
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:19fa12350328b27b171707d59e01934aac487c83617ecab4b8105c564dd86229
-size 9758143
+oid sha256:c6dfb005d2ad7f4272663dbdc3b3ffc6210a8941e34cd245dfcd53171ea227dd
+size 9758191
diff --git a/main/shared/data/icutzdata.jar b/main/shared/data/icutzdata.jar
index 53da8c6..53b95b8 100755
--- a/main/shared/data/icutzdata.jar
+++ b/main/shared/data/icutzdata.jar
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:d07f11389437204991c5f91ae4d4fec8a782334020d93a01f8a4a93db0655098
-size 98283
+oid sha256:95032cc8131740775898478637058ddce1c619aeb7c6777d54336d9978c21904
+size 98787
diff --git a/main/shared/data/testdata.jar b/main/shared/data/testdata.jar
index 3f7363e..2305640 100755
--- a/main/shared/data/testdata.jar
+++ b/main/shared/data/testdata.jar
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:b2409c6f35959bfea4fbdb09a5144ca672308434f91965e29cbef46296619b93
-size 723661
+oid sha256:bf6180a3cd404399287e993a5c2a46c63b8b2817dcfa88a2b8813d23a4247d98
+size 723668
diff --git a/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java b/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java
index 7a08bf1..90640b2 100644
--- a/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java
+++ b/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java
@@ -1,6 +1,6 @@
 /*
  *******************************************************************************
- * Copyright (C) 2001-2012, International Business Machines Corporation and    *
+ * Copyright (C) 2001-2013, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -17,10 +17,12 @@
 import java.text.FieldPosition;
 import java.text.ParseException;
 import java.text.ParsePosition;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.EnumSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.ResourceBundle;
@@ -1751,7 +1753,7 @@
         final String[] strings = {"Mar 15", "Mar 15 1997", "asdf", "3/1/97 1:23:", "3/1/00 1:23:45 AM"}; 
         int strings_length = strings.length;
         DateFormat full = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.US); 
-        String expected = "March 1, 2000 1:23:45 AM ";
+        String expected = "March 1, 2000 at 1:23:45 AM ";
         for (int i = 0; i < strings_length; ++i) {
             final String text = strings[i];
             for (int j = 0; j < looks_length; ++j) {
@@ -1770,8 +1772,10 @@
                             String format;
                             format = full.format(when);
                             logln(prefix + "OK: " + format);
-                            if (!format.substring(0, expected.length()).equals(expected))
-                                errln("FAIL: Expected " + expected);
+                            if (!format.substring(0, expected.length()).equals(expected)) {
+                                errln("FAIL: Expected <" + expected + ">, but got <"
+                                        + format.substring(0, expected.length()) + ">");
+                            }
                         }
                     } catch(java.text.ParseException e) {
                         logln(e.getMessage());
@@ -1842,7 +1846,7 @@
                             String result = ((DateFormat) dateParse).format(date);
                             logln("Parsed \"" + s + "\" using \"" + dateParse.toPattern() + "\" to: " + result);
                             if (expected == null)
-                                errln("FAIL: Expected parse failure");
+                                errln("FAIL: Expected parse failure for <" + result + ">");
                             else
                                 if (!result.equals(expected))
                                     errln("FAIL: Expected " + expected);
@@ -3667,7 +3671,7 @@
         GregorianCalendar gcal = new GregorianCalendar(tz);
 
         gcal.clear();
-        gcal.set(1910, Calendar.JANUARY, 1, 12, 00);    // offset 8:05:52
+        gcal.set(1910, Calendar.JANUARY, 1, 12, 00);    // offset 8:05:57
         d1 = gcal.getTime();
 
         gcal.clear();
@@ -3677,7 +3681,7 @@
         gcal.clear();
         gcal.set(1970, Calendar.JANUARY, 1, 12, 00);
         dexp2 = gcal.getTime();
-        dexp1 = new Date(dexp2.getTime() - (5*60 + 52)*1000);   // subtract 5m52s
+        dexp1 = new Date(dexp2.getTime() - (5*60 + 57)*1000);   // subtract 5m57s
 
         DateFormat fmt = DateFormat.getTimeInstance(DateFormat.FULL, new ULocale("zh"));
         fmt.setTimeZone(tz);
@@ -4182,6 +4186,57 @@
             }
         }
     }
+    
+    static Date TEST_DATE = new Date(2012-1900, 1-1, 15); // January 15, 2012
+
+    public void TestDotAndAtLeniency() {
+        for (ULocale locale : Arrays.asList(ULocale.ENGLISH, ULocale.FRENCH)) {
+            List<Object[]> tests = new ArrayList();
+
+            for (int dateStyle = DateFormat.FULL; dateStyle <= DateFormat.SHORT; ++dateStyle) {
+                DateFormat dateFormat = DateFormat.getDateInstance(dateStyle, locale);
+
+                for (int timeStyle = DateFormat.FULL; timeStyle <= DateFormat.SHORT; ++timeStyle) {
+                    DateFormat format = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
+                    DateFormat timeFormat = DateFormat.getTimeInstance(timeStyle, locale);
+                    String formattedString = format.format(TEST_DATE);
+
+                    tests.add(new Object[]{format, formattedString});
+
+                    formattedString = dateFormat.format(TEST_DATE) + "  " + timeFormat.format(TEST_DATE);
+                    tests.add(new Object[]{format, formattedString});
+                    if (formattedString.contains("n ")) { // will add "." after the end of text ending in 'n', like Jan.
+                        tests.add(new Object[]{format, formattedString.replace("n ", "n. ") + "."});
+                    }
+                    if (formattedString.contains(". ")) { // will subtract "." at the end of strings.
+                        tests.add(new Object[]{format, formattedString.replace(". ", " ")});
+                    }
+                }
+            }
+            for (Object[] test : tests) {
+                DateFormat format = (DateFormat) test[0];
+                String formattedString = (String) test[1];
+                if (!showParse(format, formattedString)) {
+                    // showParse(format, formattedString); // for debugging
+                }
+            }
+        }
+
+    }
+    
+    private boolean showParse(DateFormat format, String formattedString) {
+        ParsePosition parsePosition = new ParsePosition(0);
+        parsePosition.setIndex(0);
+        Date parsed = format.parse(formattedString, parsePosition);
+        boolean ok = TEST_DATE.equals(parsed) && parsePosition.getIndex() == formattedString.length();
+        if (ok) {
+            logln(format + "\t" + formattedString);
+        } else {
+            errln(format + "\t" + formattedString);
+        }
+        return ok;
+    }
+
 }
 
 
diff --git a/main/tests/core/src/com/ibm/icu/dev/test/normalizer/BasicTest.java b/main/tests/core/src/com/ibm/icu/dev/test/normalizer/BasicTest.java
index 7718c0b..fa30004 100644
--- a/main/tests/core/src/com/ibm/icu/dev/test/normalizer/BasicTest.java
+++ b/main/tests/core/src/com/ibm/icu/dev/test/normalizer/BasicTest.java
@@ -1,6 +1,6 @@
 /*
  *******************************************************************************
- * Copyright (C) 1996-2011, International Business Machines Corporation and
+ * Copyright (C) 1996-2012, International Business Machines Corporation and
  * others. All Rights Reserved.
  *******************************************************************************
  */
@@ -2651,6 +2651,26 @@
         }
     }
 
+    public void TestFilteredAppend() {
+        Normalizer2 nfcNorm2=Normalizer2.getNFCInstance();
+        UnicodeSet filter=new UnicodeSet("[^\u00a0-\u00ff\u0310-\u031f]");
+        FilteredNormalizer2 fn2=new FilteredNormalizer2(nfcNorm2, filter);
+
+        // Append two strings that each contain a character outside the filter set.
+        StringBuilder sb = new StringBuilder("a\u0313a");
+        String second = "\u0301\u0313";
+        assertEquals("append()", "a\u0313á\u0313", fn2.append(sb, second).toString());
+
+        // Same, and also normalize the second string.
+        sb.replace(0, 0x7fffffff, "a\u0313a");
+        assertEquals(
+            "normalizeSecondAndAppend()",
+            "a\u0313á\u0313", fn2.normalizeSecondAndAppend(sb, second).toString());
+        
+        // Normalizer2.normalize(String) uses spanQuickCheckYes() and normalizeSecondAndAppend().
+        assertEquals("normalize()", "a\u0313á\u0313", fn2.normalize("a\u0313a\u0301\u0313"));
+    }
+
     public void TestGetEasyToUseInstance() {
         // Test input string:
         // U+00A0 -> <noBreak> 0020
diff --git a/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java b/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java
index e99d833..177349c 100644
--- a/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java
+++ b/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java
@@ -1,6 +1,6 @@
 /**
  *******************************************************************************
- * Copyright (C) 2000-2012, International Business Machines Corporation and    *
+ * Copyright (C) 2000-2013, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -1483,6 +1483,7 @@
                 {"Antarctica/South_Pole", "Antarctica/McMurdo"},
                 {"Atlantic/Jan_Mayen", "Europe/Oslo"},
                 {"Arctic/Longyearbyen", "Europe/Oslo"},
+                {"Europe/Busingen", "Europe/Zurich"},
                 {"Europe/Guernsey", "Europe/London"},
                 {"Europe/Isle_of_Man", "Europe/London"},
                 {"Europe/Jersey", "Europe/London"},
diff --git a/main/tests/core/src/com/ibm/icu/dev/test/util/DebugUtilitiesData.java b/main/tests/core/src/com/ibm/icu/dev/test/util/DebugUtilitiesData.java
index d490f18..d06550d 100644
--- a/main/tests/core/src/com/ibm/icu/dev/test/util/DebugUtilitiesData.java
+++ b/main/tests/core/src/com/ibm/icu/dev/test/util/DebugUtilitiesData.java
@@ -7,7 +7,7 @@
 package com.ibm.icu.dev.test.util;
 
 public class DebugUtilitiesData extends Object {
-    public static final String ICU4C_VERSION="50.1";
+    public static final String ICU4C_VERSION="50.1.1";
     public static final int UDebugEnumType = 0;
     public static final int UCalendarDateFields = 1;
     public static final int UCalendarMonths = 2;
diff --git a/main/tests/core/src/com/ibm/icu/dev/test/util/LocaleDataTest.java b/main/tests/core/src/com/ibm/icu/dev/test/util/LocaleDataTest.java
index 84c84d0..9a6db85 100644
--- a/main/tests/core/src/com/ibm/icu/dev/test/util/LocaleDataTest.java
+++ b/main/tests/core/src/com/ibm/icu/dev/test/util/LocaleDataTest.java
@@ -1,6 +1,6 @@
 /*
  *******************************************************************************
- * Copyright (C) 2003-2010, International Business Machines Corporation and    *
+ * Copyright (C) 2003-2012, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
 */
@@ -275,6 +275,52 @@
         assertTrue("case-folded is sometimes a strict superset, and sometimes equal",
                 equalCount > 0 && equalCount < availableLocales.length * 2);
     }
+
+    // Test case created for checking type coverage of static getExemplarSet method.
+    // See #9785, #9794 and #9795
+    public void TestExemplarSetTypes() {
+        final String[] testLocales = {
+            "am",   // No auxiliary / index exemplars as of ICU 50
+            "en",
+            "th",   // #9785
+            "foo",  // Bogus locale
+        };
+
+        final int[] testTypes = {
+            LocaleData.ES_STANDARD,
+            LocaleData.ES_AUXILIARY,
+            LocaleData.ES_INDEX,
+            LocaleData.ES_CURRENCY,
+            LocaleData.ES_PUNCTUATION,
+        };
+
+        final String[] testTypeNames = {
+                "ES_STANDARD",
+                "ES_AUXILIARY",
+                "ES_INDEX",
+                "ES_CURRENCY",
+                "ES_PUNCTUATION",
+            };
+
+        for (String locstr : testLocales) {
+            ULocale loc = new ULocale(locstr);
+            for (int i = 0; i < testTypes.length; i++) {
+                try {
+                    UnicodeSet set = LocaleData.getExemplarSet(loc, 0, testTypes[i]);
+                    if (set == null) {
+                        // Not sure null is really OK (#9795)
+                        logln(loc + "(" + testTypeNames[i] + ") returned null");
+                    } else if (set.isEmpty()) {
+                        // This is probably reasonable when data is absent
+                        logln(loc + "(" + testTypeNames[i] + ") returned an empty set");
+                    }
+                } catch (Exception e) {
+                    errln(loc + "(" + testTypeNames[i] + ") Exception:" + e.getMessage());
+                }
+            }
+        }
+    }
+
     public void TestCoverage(){
         LocaleData ld = LocaleData.getInstance();
         boolean t = ld.getNoSubstitute();
diff --git a/pom.xml b/pom.xml
index e62b29e..5e27ef4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
 
   <groupId>com.ibm.icu</groupId>
   <artifactId>icu4j</artifactId>
-  <version>50.1</version>
+  <version>50.1.1</version>
 
   <name>ICU4J</name>
   <description>
diff --git a/readme.html b/readme.html
index feeabc9..74d6b1df 100644
--- a/readme.html
+++ b/readme.html
@@ -14,8 +14,8 @@
 <body style="background-color: rgb(255, 255, 255);" lang="EN-US"
  link="#0000ff" vlink="#800080">
 <h2>International Components for Unicode for Java (ICU4J)</h2>
-<h3>Read Me for ICU4J 50 (50.1)</h3>
-(Last Update: 2012-Nov-02)
+<h3>Read Me for ICU4J 50 (50.1.1)</h3>
+(Last Update: 2012-Dec-14)
 <hr size="2" width="100%">
 
 <p><b>Note:</b> This is major release of ICU4J. It contains bug fixes and adds implementations
@@ -1006,9 +1006,9 @@
 <h5> Generating Data from CLDR </h5>
 <I> Note: This procedure assumes that all 3 sources are present</I>
 <ol>
-    <li>Checkout or download CLDR version 'release-22-1'</li>
-    <li>Checkout ICU4C with tag 'release-50-1'</li>
-    <li>Checkout ICU4J with tag 'release-50-1'</li>
+    <li>Checkout or download CLDR version 'release-22-1-1'</li>
+    <li>Checkout ICU4C with tag 'release-50-1-1'</li>
+    <li>Checkout ICU4J with tag 'release-50-1-1'</li>
     <li>cd to <I>$icu4c_root</I>/source/data directory</li>
     <li>Follow the instructions in <I>$icu4c_root</I>/source/data/cldr-icu-readme.txt</li>
     <li>Rebuild ICU4C with the newly generated data.</li>
@@ -1020,7 +1020,7 @@
 </ol>
 
 <h3 class="doc"><a name="timezone"></a>About ICU4J Time Zone</h3>
-<p>ICU4J 50.1 includes time zone data version 2012h, which is the latest one as of
+<p>ICU4J 50.1.1 includes time zone data version 2012j, which is the latest one as of
 the release date.  However, time zone data is frequently updated in response
 to changes made by local governments around the world.  If you need to update
 the time zone data, please refer the ICU user guide topic