From 297e43379762d1670336201fe5eb6c3e1c501028 Mon Sep 17 00:00:00 2001 From: Mark Davis Date: Mon, 15 Apr 2013 06:19:53 +0000 Subject: [PATCH] ICU-8474 fixes for serialization, which included change to equals X-SVN-Rev: 33528 --- .../src/com/ibm/icu/text/PluralRules.java | 326 ++- .../ibm/icu/text/PluralRulesSerialProxy.java | 26 + .../dev/test/format/PluralRulesFactory.java | 116 +- .../icu/dev/test/format/PluralRulesTest.java | 137 +- .../dev/test/format/WritePluralRulesData.java | 719 +++--- .../com/ibm/icu/dev/test/format/plurals.txt | 1957 +++++++++++++++++ .../test/serializable/CompatibilityTest.java | 28 +- .../dev/test/serializable/FormatTests.java | 15 +- .../test/serializable/SerializableTest.java | 3 +- 9 files changed, 2878 insertions(+), 449 deletions(-) create mode 100644 icu4j/main/classes/core/src/com/ibm/icu/text/PluralRulesSerialProxy.java create mode 100644 icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/plurals.txt diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/PluralRules.java b/icu4j/main/classes/core/src/com/ibm/icu/text/PluralRules.java index 66b0a0e2bc2..6420a7846f0 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/text/PluralRules.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/text/PluralRules.java @@ -7,6 +7,11 @@ package com.ibm.icu.text; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; import java.io.Serializable; import java.text.ParseException; import java.util.ArrayList; @@ -303,7 +308,7 @@ public class PluralRules implements Serializable { } public String toString() { - return ""; + return null; } public int updateRepeatLimit(int limit) { @@ -374,7 +379,7 @@ public class PluralRules implements Serializable { public static class NumberInfo implements Comparable { public final double source; public final int visibleFractionDigitCount; - public final int fractionalDigits; + public final long fractionalDigits; public final long intValue; public final boolean hasIntegerValue; @@ -384,6 +389,19 @@ public class PluralRules implements Serializable { fractionalDigits = f; intValue = (long)n; hasIntegerValue = source == intValue; + // check values. TODO make into unit test. + // + // long visiblePower = (int) Math.pow(10, v); + // if (fractionalDigits > visiblePower) { + // throw new IllegalArgumentException(); + // } + // double fraction = intValue + (fractionalDigits / (double) visiblePower); + // if (fraction != source) { + // double diff = Math.abs(fraction - source)/(Math.abs(fraction) + Math.abs(source)); + // if (diff > 0.00000001d) { + // throw new IllegalArgumentException(); + // } + // } } // Ugly, but for samples we don't care. @@ -391,17 +409,6 @@ public class PluralRules implements Serializable { this(n,v,getFractionalDigits(n, v)); } - // Ugly, but for samples we don't care. - public static int decimals(double n) { - String temp = String.valueOf(n); - return temp.endsWith(".0") ? 0 : temp.length() - temp.indexOf('.') - 1; - } - - // Ugly, but for samples we don't care. - public NumberInfo (String n) { - this(Double.parseDouble(n), getVisibleFractionCount(n)); - } - private static int getFractionalDigits(double n, int v) { if (v == 0) { return 0; @@ -412,23 +419,35 @@ public class PluralRules implements Serializable { } } - private static int getVisibleFractionCount(String value) { - int decimalPos = value.trim().indexOf('.') + 1; - if (decimalPos == 0) { - return 0; - } else { - return value.length() - decimalPos - 1; - } - } - public NumberInfo(double n) { this(n, decimals(n)); } + // Ugly, but for samples we don't care. + public static int decimals(double n) { + String temp = String.valueOf(n); + return temp.endsWith(".0") ? 0 : temp.length() - temp.indexOf('.') - 1; + } + public NumberInfo(long n) { this(n,0); } + // Ugly, but for samples we don't care. + public NumberInfo (String n) { + this(Double.parseDouble(n), getVisibleFractionCount(n)); + } + + private static int getVisibleFractionCount(String value) { + value = value.trim(); + int decimalPos = value.indexOf('.') + 1; + if (decimalPos == 0) { + return 0; + } else { + return value.length() - decimalPos; + } + } + public double get(Operand operand) { switch(operand) { default: return source; @@ -446,13 +465,20 @@ public class PluralRules implements Serializable { * We're not going to care about NaN. */ public int compareTo(NumberInfo other) { + if (intValue != other.intValue) { + return intValue < other.intValue ? -1 : 1; + } if (source != other.source) { return source < other.source ? -1 : 1; } if (visibleFractionDigitCount != other.visibleFractionDigitCount) { return visibleFractionDigitCount < other.visibleFractionDigitCount ? -1 : 1; } - return fractionalDigits - other.fractionalDigits; + long diff = fractionalDigits - other.fractionalDigits; + if (diff != 0) { + return diff < 0 ? -1 : 1; + } + return 0; } @Override public boolean equals(Object arg0) { @@ -471,7 +497,7 @@ public class PluralRules implements Serializable { @Override public int hashCode() { // TODO Auto-generated method stub - return fractionalDigits + 37 * (visibleFractionDigitCount + (int)(37 * source)); + return (int)(fractionalDigits + 37 * (visibleFractionDigitCount + (int)(37 * source))); } @Override public String toString() { @@ -660,13 +686,13 @@ public class PluralRules implements Serializable { String[] pair = Utility.splitString(range, ".."); double low, high; if (pair.length == 2) { - low = Long.parseLong(pair[0]); - high = Long.parseLong(pair[1]); + low = Double.parseDouble(pair[0]); + high = Double.parseDouble(pair[1]); if (low > high) { throw unexpected(range, condition); } } else if (pair.length == 1) { - low = high = Long.parseLong(pair[0]); + low = high = Double.parseDouble(pair[0]); } else { throw unexpected(range, condition); } @@ -679,7 +705,7 @@ public class PluralRules implements Serializable { vals = null; } } else { - lowBound = highBound = Long.parseLong(t); + lowBound = highBound = Double.parseDouble(t); } if (x != tokens.length) { @@ -761,6 +787,10 @@ public class PluralRules implements Serializable { private static RuleList parseRuleChain(String description) throws ParseException { RuleList result = new RuleList(); + // remove trailing ; + if (description.endsWith(";")) { + description = description.substring(0,description.length()-1); + } String[] rules = Utility.split(description, ';'); for (int i = 0; i < rules.length; ++i) { result.addRule(parseRule(rules[i].trim())); @@ -808,30 +838,30 @@ public class PluralRules implements Serializable { if (upperBound != lowerBound) { toAddTo.add(new NumberInfo(upperBound + offset)); } -// if (range_list != null) { -// // add from each range -// for (int i = 0; i < range_list.length; i += 2) { -// double lower = range_list[i]; -// double upper = range_list[i+1]; -// if (lower != lowerBound) { -// toAddTo.add(new NumberInfo(lower + offset)); -// } -// if (upper != upperBound) { -// toAddTo.add(new NumberInfo(upper + offset)); -// } -// } -// } + // if (range_list != null) { + // // add from each range + // for (int i = 0; i < range_list.length; i += 2) { + // double lower = range_list[i]; + // double upper = range_list[i+1]; + // if (lower != lowerBound) { + // toAddTo.add(new NumberInfo(lower + offset)); + // } + // if (upper != upperBound) { + // toAddTo.add(new NumberInfo(upper + offset)); + // } + // } + // } if (!integersOnly) { double average = (lowerBound + upperBound) / 2.0d; toAddTo.add(new NumberInfo(average + offset)); -// if (range_list != null) { -// // we will just add one value from the middle -// for (int i = 0; i < range_list.length; i += 2) { -// double lower = range_list[i]; -// double upper = range_list[i+1]; -// toAddTo.add(new NumberInfo((lower + upper) / 2.0d + offset)); -// } -// } + // if (range_list != null) { + // // we will just add one value from the middle + // for (int i = 0; i < range_list.length; i += 2) { + // double lower = range_list[i]; + // double upper = range_list[i+1]; + // toAddTo.add(new NumberInfo((lower + upper) / 2.0d + offset)); + // } + // } } } @@ -1095,6 +1125,9 @@ public class PluralRules implements Serializable { Map ordered = new TreeMap(KEYWORD_COMPARATOR); for (Rule rule : rules) { String keyword = rule.getKeyword(); + if (keyword.equals("other")) { + continue; + } String constraint = rule.getConstraint(); ordered.put(keyword, constraint); } @@ -1145,8 +1178,10 @@ public class PluralRules implements Serializable { return a; } } - - static final int[] TENS = {1, 10, 100, 1000}; + + private static final int[] TENS = {1, 10, 100, 1000, 10000, 100000, 1000000}; + + private static final int LIMIT_FRACTION_SAMPLES = 3; private Set fractions(Set original) { Set toAddTo = new HashSet(); @@ -1156,25 +1191,52 @@ public class PluralRules implements Serializable { result.add((int)base1.intValue); } List ints = new ArrayList(result); + Set keywords = new HashSet(); for (int j = 0; j < ints.size(); ++j) { Integer base = ints.get(j); - Integer fract = ints.get((j == 0 ? ints.size() : j) -1); - for (int visibleFractions = 1; visibleFractions < 3; ++visibleFractions) { - for (int i = 1; i <= visibleFractions; ++i) { - // with visible fractions = 3, and fract = 1, then we should get x.10, 0.01 - // with visible fractions = 3, and fract = 15, then we should get x.15, x.15 - if (fract >= TENS[i]) { - continue; + String keyword = select(base); + if (keywords.contains(keyword)) { + continue; + } + keywords.add(keyword); + toAddTo.add(new NumberInfo(base,1)); // add .0 + toAddTo.add(new NumberInfo(base,2)); // add .00 + Integer fract = getDifferentCategory(ints, keyword); + if (fract >= TENS[LIMIT_FRACTION_SAMPLES-1]) { // make sure that we always get the value + toAddTo.add(new NumberInfo(base + "." + fract)); + } else { + for (int visibleFractions = 1; visibleFractions < LIMIT_FRACTION_SAMPLES; ++visibleFractions) { + for (int i = 1; i <= visibleFractions; ++i) { + // with visible fractions = 3, and fract = 1, then we should get x.10, 0.01 + // with visible fractions = 3, and fract = 15, then we should get x.15, x.15 + if (fract >= TENS[i]) { + continue; + } + toAddTo.add(new NumberInfo(base + fract/(double)TENS[i], visibleFractions)); } - NumberInfo combo = new NumberInfo(base + fract/(double)TENS[i], visibleFractions); - toAddTo.add(combo); } } } return toAddTo; } + /** + * @param ints + * @param base + * @return + */ + private Integer getDifferentCategory(List ints, String keyword) { + for (int i = ints.size() - 1; i >= 0; --i) { + Integer other = ints.get(i); + String keywordOther = select(other); + if (!keywordOther.equals(keyword)) { + return other; + } + } + return 37; + } + private boolean addConditional(Set toAddTo, Set others, double trial) { boolean added; NumberInfo toAdd = new NumberInfo(trial); @@ -1307,7 +1369,7 @@ public class PluralRules implements Serializable { * @deprecated This API is ICU internal only. */ public String select(NumberInfo sample) { - return rules.select(new NumberInfo(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits)); + return rules.select(sample); } /** @@ -1472,65 +1534,67 @@ public class PluralRules implements Serializable { addRelation(foundKeywords, keyword, s); } main: - if (foundKeywords.size() != keywords.size()) { - for (int i = 1; i < 1000; ++i) { - boolean done = addIfNotPresent(i, mentioned, foundKeywords); - if (done) break main; + if (foundKeywords.size() != keywords.size()) { + for (int i = 1; i < 1000; ++i) { + boolean done = addIfNotPresent(i, mentioned, foundKeywords); + if (done) break main; + } + // if we are not done, try tenths + for (int i = 10; i < 1000; ++i) { + boolean done = addIfNotPresent(i/10d, mentioned, foundKeywords); + if (done) break main; + } + System.out.println("Failed to find sample for each keyword: " + foundKeywords + "\n\t" + rules + "\n\t" + mentioned); } - // if we are not done, try tenths - for (int i = 10; i < 1000; ++i) { - boolean done = addIfNotPresent(i/10d, mentioned, foundKeywords); - if (done) break main; - } - System.out.println("Failed to find sample for each keyword: " + foundKeywords + "\n\t" + rules + "\n\t" + mentioned); - } mentioned.add(new NumberInfo(0)); // always there mentioned.add(new NumberInfo(1)); // always there mentioned.add(new NumberInfo(2)); // always there + mentioned.add(new NumberInfo(0.1,1)); // always there + mentioned.add(new NumberInfo(1.99,2)); // always there mentioned.addAll(fractions(mentioned)); -// Set toAddTo = mentioned; -// { -// // once done, manufacture values for the OTHER case -// int otherCount = 2; -// for (int i = 0; i < 1000; ++i) { -// } -// NumberInfo last = null; -// Set others = new LinkedHashSet(); -// for (NumberInfo s : toAddTo) { -// double trial; -// if (last == null) { -// trial = s.source-0.5; -// } else { -// double diff = s.source - last.source; -// if (diff > 1.0d) { -// trial = Math.floor(s.source); -// if (trial == s.source) { -// --trial; -// } -// } else { -// trial = (s.source + last.source) / 2; -// } -// } -// if (trial >= 0) { -// addConditional(toAddTo, others, trial); -// } -// last = s; -// } -// double trial = last == null ? 0 : last.source; -// double fraction = 0; -// while (otherCount > 0) { -// if (addConditional(toAddTo, others, trial = trial * 2 + 1 + fraction)) { -// --otherCount; -// } -// fraction += 0.125; -// } -// toAddTo.addAll(others); -// others.clear(); -// toAddTo.addAll(fractions(toAddTo, others)); -// -// } + // Set toAddTo = mentioned; + // { + // // once done, manufacture values for the OTHER case + // int otherCount = 2; + // for (int i = 0; i < 1000; ++i) { + // } + // NumberInfo last = null; + // Set others = new LinkedHashSet(); + // for (NumberInfo s : toAddTo) { + // double trial; + // if (last == null) { + // trial = s.source-0.5; + // } else { + // double diff = s.source - last.source; + // if (diff > 1.0d) { + // trial = Math.floor(s.source); + // if (trial == s.source) { + // --trial; + // } + // } else { + // trial = (s.source + last.source) / 2; + // } + // } + // if (trial >= 0) { + // addConditional(toAddTo, others, trial); + // } + // last = s; + // } + // double trial = last == null ? 0 : last.source; + // double fraction = 0; + // while (otherCount > 0) { + // if (addConditional(toAddTo, others, trial = trial * 2 + 1 + fraction)) { + // --otherCount; + // } + // fraction += 0.125; + // } + // toAddTo.addAll(others); + // others.clear(); + // toAddTo.addAll(fractions(toAddTo, others)); + // + // } for (NumberInfo s : mentioned) { - String keyword = select(s.source, s.visibleFractionDigitCount, s.fractionalDigits); + String keyword = select(s); Set list = sampleFractionMap.get(keyword); if (list == null) { list = new LinkedHashSet(); // will be sorted because the iteration is @@ -1675,12 +1739,21 @@ public class PluralRules implements Serializable { return false; } - int limit = Math.max(getRepeatLimit(), rhs.getRepeatLimit()); - for (int i = 0; i < limit * 2; ++i) { - if (!select(i).equals(rhs.select(i))) { - return false; + for (String keyword : rhs.getKeywords()) { + String rules2 = getRules(keyword); + String rules3 = rhs.getRules(keyword); + if (rules2 != rules3) { + if (rules2 == null || !rules2.equals(rules3)) { + return false; + } } } + // int limit = Math.max(getRepeatLimit(), rhs.getRepeatLimit()); + // for (int i = 0; i < limit * 2; ++i) { + // if (!select(i).equals(rhs.select(i))) { + // return false; + // } + // } return true; } @@ -1807,4 +1880,21 @@ public class PluralRules implements Serializable { public String getRules(String keyword) { return rules.getRules(keyword); } + + private void writeObject( + ObjectOutputStream out) + throws IOException { + throw new NotSerializableException(); + } + private void readObject(ObjectInputStream in + ) throws IOException, ClassNotFoundException { + throw new NotSerializableException(); + } + private void readObjectNoData( + ) throws ObjectStreamException { + throw new NotSerializableException(); + } + private Object writeReplace() throws ObjectStreamException { + return new PluralRulesSerialProxy(toString()); + } } diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/PluralRulesSerialProxy.java b/icu4j/main/classes/core/src/com/ibm/icu/text/PluralRulesSerialProxy.java new file mode 100644 index 00000000000..c7afc9fc601 --- /dev/null +++ b/icu4j/main/classes/core/src/com/ibm/icu/text/PluralRulesSerialProxy.java @@ -0,0 +1,26 @@ +/* + ******************************************************************************* + * Copyright (C) 2013, Google Inc, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ +package com.ibm.icu.text; + +import java.io.ObjectStreamException; +import java.io.Serializable; + +/** + * @author markdavis + * + */ +public class PluralRulesSerialProxy implements Serializable { + private static final long serialVersionUID = 42L; + private final String data; + PluralRulesSerialProxy(String rules) { + data = rules; + } + private Object readResolve() throws ObjectStreamException { + return PluralRules.createRules(data); + } +} + diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesFactory.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesFactory.java index 3a5e16f4c3a..cc771a4e636 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesFactory.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesFactory.java @@ -65,29 +65,45 @@ public abstract class PluralRulesFactory { static Relation EXTRA_SAMPLES = Relation.of(new HashMap>(), HashSet.class); static { String[][] overrides = { + {"bn", ""}, {"en,ca,de,et,fi,gl,it,nl,pt,sv,sw,ta,te,ur", "one: j is 1"}, {"cs,sk", "one: j is 1; few: j in 2..4; many: v is not 0"}, + {"cy", "one: n is 1; two: n is 2; few: n is 3; many: n is 6"}, //{"el", "one: j is 1 or i is 0 and f is 1"}, {"da,is", "one: j is 1 or f is 1"}, {"fil", "one: j in 0..1"}, {"he", "one: j is 1; two: j is 2", "10,20"}, {"hi", "one: n within 0..1"}, - {"hr", "one: j mod 10 is 1 and j mod 100 is not 11; few: j mod 10 in 2..4 and j mod 100 not in 12..14; many: j mod 10 is 0 or j mod 10 in 5..9 or j mod 100 in 11..14"}, + {"hy", "one: n within 0..2 and n is not 2"}, +// {"hr", "one: j mod 10 is 1 and j mod 100 is not 11; few: j mod 10 in 2..4 and j mod 100 not in 12..14; many: j mod 10 is 0 or j mod 10 in 5..9 or j mod 100 in 11..14"}, {"lv", "zero: n mod 10 is 0" + " or n mod 10 in 11..19" + " or v in 1..6 and f is not 0 and f mod 10 is 0" + " or v in 1..6 and f mod 10 in 11..19;" + "one: n mod 10 is 1 and n mod 100 is not 11" + " or v in 1..6 and f mod 10 is 1 and f mod 100 is not 11" + - " or v not in 0..6 and f mod 10 is 1"}, + " or v not in 0..6 and f mod 10 is 1"}, +// {"lv", "zero: n mod 10 is 0" + +// " or n mod 10 in 11..19" + +// " or v in 1..6 and f is not 0 and f mod 10 is 0" + +// " or v in 1..6 and f mod 10 in 11..19;" + +// "one: n mod 10 is 1 and n mod 100 is not 11" + +// " or v in 1..6 and f mod 10 is 1 and f mod 100 is not 11" + +// " or v not in 0..6 and f mod 10 is 1"}, {"pl", "one: j is 1; few: j mod 10 in 2..4 and j mod 100 not in 12..14; many: j is not 1 and j mod 10 in 0..1 or j mod 10 in 5..9 or j mod 100 in 12..14"}, {"sl", "one: j mod 100 is 1; two: j mod 100 is 2; few: j mod 100 in 3..4 or v is not 0"}, - {"sr", "one: j mod 10 is 1 and j mod 100 is not 11" + - " or v in 1..6 and f mod 10 is 1 and f mod 100 is not 11" + - " or v not in 0..6 and f mod 10 is 1;" + +// {"sr", "one: j mod 10 is 1 and j mod 100 is not 11" + +// " or v in 1..6 and f mod 10 is 1 and f mod 100 is not 11" + +// " or v not in 0..6 and f mod 10 is 1;" + +// "few: j mod 10 in 2..4 and j mod 100 not in 12..14" + +// " or v in 1..6 and f mod 10 in 2..4 and f mod 100 not in 12..14" + +// " or v not in 0..6 and f mod 10 in 2..4" +// }, + {"sr,hr", "one: j mod 10 is 1 and j mod 100 is not 11" + + " or f mod 10 is 1 and f mod 100 is not 11;" + "few: j mod 10 in 2..4 and j mod 100 not in 12..14" + - " or v in 1..6 and f mod 10 in 2..4 and f mod 100 not in 12..14" + - " or v not in 0..6 and f mod 10 in 2..4" + " or f mod 10 in 2..4 and f mod 100 not in 12..14" + }, // + // " ; many: j mod 10 is 0 " + // " or j mod 10 in 5..9 " + @@ -96,11 +112,14 @@ public abstract class PluralRulesFactory { // " or v in 1..6 and f mod 10 in 5..9" + // " or v in 1..6 and f mod 100 in 11..14" + // " or v not in 0..6 and f mod 10 in 5..9" - }, {"ro", "one: j is 1; few: n is 0 or n is not 1 and n mod 100 in 1..19"}, - {"ru,uk", "one: j mod 10 is 1 and j mod 100 is not 11;" + - " few: j mod 10 in 2..4 and j mod 100 not in 12..14;" + - " many: j mod 10 is 0 or j mod 10 in 5..9 or j mod 100 in 11..14"}, + {"ru", "one: j mod 10 is 1 and j mod 100 is not 11;" + + " many: j mod 10 is 0 or j mod 10 in 5..9 or j mod 100 in 11..14" +// + "; many: j mod 10 is 0 or j mod 10 in 5..9 or j mod 100 in 11..14" + }, + {"uk", "one: j mod 10 is 1 and j mod 100 is not 11; " + + "few: j mod 10 in 2..4 and j mod 100 not in 12..14; " + + "many: j mod 10 is 0 or j mod 10 in 5..9 or j mod 100 in 11..14"}, }; for (String[] pair : overrides) { for (String locale : pair[0].split("\\s*,\\s*")) { @@ -160,4 +179,79 @@ public abstract class PluralRulesFactory { return result == null ? ULocale.ROOT : result; } }; + + static String[][] OLDRULES = { + {"af", "one: n is 1"}, + {"am", "one: n in 0..1"}, + {"ar", "zero: n is 0; one: n is 1; two: n is 2; few: n mod 100 in 3..10; many: n mod 100 in 11..99"}, + {"az", "other: null"}, + {"bg", "one: n is 1"}, + {"bn", "one: n is 1"}, + {"ca", "one: n is 1"}, + {"cs", "one: n is 1; few: n in 2..4"}, + {"cy", "zero: n is 0; one: n is 1; two: n is 2; few: n is 3; many: n is 6"}, + {"da", "one: n is 1"}, + {"de", "one: n is 1"}, + {"el", "one: n is 1"}, + {"en", "one: n is 1"}, + {"es", "one: n is 1"}, + {"et", "one: n is 1"}, + {"eu", "one: n is 1"}, + {"fa", "other: null"}, + {"fi", "one: n is 1"}, + {"fil", "one: n in 0..1"}, + {"fr", "one: n within 0..2 and n is not 2"}, + {"gl", "one: n is 1"}, + {"gu", "one: n is 1"}, + {"hi", "one: n in 0..1"}, + {"hr", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"}, + {"hu", "other: null"}, + {"hy", "one: n is 1"}, + {"id", "other: null"}, + {"is", "one: n is 1"}, + {"it", "one: n is 1"}, + {"he", "one: n is 1; two: n is 2; many: n is not 0 and n mod 10 is 0"}, + {"ja", "other: null"}, + {"ka", "other: null"}, + {"kk", "one: n is 1"}, + {"km", "other: null"}, + {"kn", "other: null"}, + {"ko", "other: null"}, + {"ky", "one: n is 1"}, + {"lo", "other: null"}, + {"lt", "one: n mod 10 is 1 and n mod 100 not in 11..19; few: n mod 10 in 2..9 and n mod 100 not in 11..19"}, + {"lv", "zero: n is 0; one: n mod 10 is 1 and n mod 100 is not 11"}, + {"mk", "one: n mod 10 is 1 and n is not 11"}, + {"ml", "one: n is 1"}, + {"mn", "one: n is 1"}, + {"mr", "one: n is 1"}, + {"ms", "other: null"}, + {"my", "other: null"}, + {"ne", "one: n is 1"}, + {"nl", "one: n is 1"}, + {"nb", "one: n is 1"}, + {"pa", "one: n is 1"}, + {"pl", "one: n is 1; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n is not 1 and n mod 10 in 0..1 or n mod 10 in 5..9 or n mod 100 in 12..14"}, + {"ps", "one: n is 1"}, + {"pt", "one: n is 1"}, + {"ro", "one: n is 1; few: n is 0 or n is not 1 and n mod 100 in 1..19"}, + {"ru", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"}, + {"si", "other: null"}, + {"sk", "one: n is 1; few: n in 2..4"}, + {"sl", "one: n mod 100 is 1; two: n mod 100 is 2; few: n mod 100 in 3..4"}, + {"sq", "one: n is 1"}, + {"sr", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"}, + {"sv", "one: n is 1"}, + {"sw", "one: n is 1"}, + {"ta", "one: n is 1"}, + {"te", "one: n is 1"}, + {"th", "other: null"}, + {"tr", "other: null"}, + {"uk", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"}, + {"ur", "one: n is 1"}, + {"uz", "other: null"}, + {"vi", "other: null"}, + {"zh", "other: null"}, + {"zu", "one: n is 1"}, + }; } diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesTest.java index 0fa7e33ce05..b376b0c684b 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesTest.java @@ -6,6 +6,12 @@ */ package com.ibm.icu.dev.test.format; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; @@ -36,11 +42,11 @@ import com.ibm.icu.util.ULocale; * @author markdavis (Mark Davis) [for fractional support] */ public class PluralRulesTest extends TestFmwk { - + static boolean USE_ALT = System.getProperty("alt_plurals") != null; - + PluralRulesFactory factory = USE_ALT ? PluralRulesFactory.ALTERNATE : PluralRulesFactory.NORMAL; - + public static void main(String[] args) throws Exception { new PluralRulesTest().run(args); } @@ -163,43 +169,43 @@ public class PluralRulesTest extends TestFmwk { public void testUniqueRules() { main: - for (ULocale locale : factory.getAvailableULocales()) { - PluralRules rules = factory.forLocale(locale); - Collection samples = rules.getFractionSamples(); - Map keywordToRule = new HashMap(); - for (String keyword : rules.getKeywords()) { - if (keyword.equals("other")) { - continue; - } - String rules2 = keyword + ":" + rules.getRules(keyword); - PluralRules singleRule = PluralRules.createRules(rules2); - if (singleRule == null) { - errln("Can't generate single rule for " + rules2); - PluralRules.createRules(rules2); // for debugging - continue main; - } - keywordToRule.put(keyword, singleRule); - } - Map collisionTest = new TreeMap(); - for (NumberInfo sample : samples) { - collisionTest.clear(); - for (Entry entry: keywordToRule.entrySet()) { - String keyword = entry.getKey(); - PluralRules rule = entry.getValue(); - String foundKeyword = rule.select(sample); - if (foundKeyword.equals("other")) { + for (ULocale locale : factory.getAvailableULocales()) { + PluralRules rules = factory.forLocale(locale); + Collection samples = rules.getFractionSamples(); + Map keywordToRule = new HashMap(); + for (String keyword : rules.getKeywords()) { + if (keyword.equals("other")) { continue; } - String old = collisionTest.get(sample); - if (old != null) { - errln(locale + "\tNon-unique rules: " + sample + " => " + old + " & " + foundKeyword); - rule.select(sample); - } else { - collisionTest.put(sample, foundKeyword); + String rules2 = keyword + ":" + rules.getRules(keyword); + PluralRules singleRule = PluralRules.createRules(rules2); + if (singleRule == null) { + errln("Can't generate single rule for " + rules2); + PluralRules.createRules(rules2); // for debugging + continue main; + } + keywordToRule.put(keyword, singleRule); + } + Map collisionTest = new TreeMap(); + for (NumberInfo sample : samples) { + collisionTest.clear(); + for (Entry entry: keywordToRule.entrySet()) { + String keyword = entry.getKey(); + PluralRules rule = entry.getValue(); + String foundKeyword = rule.select(sample); + if (foundKeyword.equals("other")) { + continue; + } + String old = collisionTest.get(sample); + if (old != null) { + errln(locale + "\tNon-unique rules: " + sample + " => " + old + " & " + foundKeyword); + rule.select(sample); + } else { + collisionTest.put(sample, foundKeyword); + } } } } - } } private void checkCategoriesAndExpected(String title, String categoriesAndExpected, PluralRules rules) { @@ -224,14 +230,19 @@ public class PluralRulesTest extends TestFmwk { } private static String[][] equalityTestData = { - { "a: n is 5", - "a: n in 2..6 and n not in 2..4 and n is not 6" }, - { "a: n in 2..3", - "a: n is 2 or n is 3", - "a: n is 3 and n in 2..5 or n is 2" }, - { "a: n is 12; b:n mod 10 in 2..3", - "b: n mod 10 in 2..3 and n is not 12; a: n in 12..12", - "b: n is 13; a: n is 12; b: n mod 10 is 2 or n mod 10 is 3" }, + // once we add fractions, we had to retract the "test all possibilities" for equality, + // so we only have a limited set of equality tests now. + { "a:n in 2;b:n in 5", + "b: n in 5;a: n in 2;" }, + +// { "a: n is 5", +// "a: n in 2..6 and n not in 2..4 and n is not 6" }, +// { "a: n in 2..3", +// "a: n is 2 or n is 3", +// "a: n is 3 and n in 2..5 or n is 2" }, +// { "a: n is 12; b:n mod 10 in 2..3", +// "b: n mod 10 in 2..3 and n is not 12; a: n in 12..12", +// "b: n is 13; a: n is 12; b: n mod 10 is 2 or n mod 10 is 3" }, }; private static String[][] inequalityTestData = { @@ -240,7 +251,10 @@ public class PluralRulesTest extends TestFmwk { }, { "a: n mod 3 is 2 and n is not 5", "a: n mod 6 is 2 or n is 8 or n is 11" - } + }, + // the following are currently inequal, but we may make them equal in the future. + { "a: n in 2..5", + "a: n in 2..4,5" }, }; private void compareEquality(String id, Object[] objects, boolean shouldBeEqual) { @@ -655,4 +669,37 @@ public class PluralRulesTest extends TestFmwk { "cy; zero: 0, 0.0; one: 1, 1.0; two: 2; few: 3; many: 6; other: 0.1, 2.5, 3.5, 5", }; -} + private T serializeAndDeserialize(T original, Output size) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream ostream = new ObjectOutputStream(baos); + ostream.writeObject(original); + ostream.flush(); + byte bytes[] = baos.toByteArray(); + size.value = bytes.length; + ObjectInputStream istream = new ObjectInputStream(new ByteArrayInputStream(bytes)); + T reconstituted = (T)istream.readObject(); + return reconstituted; + } catch(IOException e) { + throw new RuntimeException(e); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + public void TestSerialization() { + Output size = new Output(); + int max = 0; + for (ULocale locale : PluralRules.getAvailableULocales()) { + PluralRules item = PluralRules.forLocale(locale); + PluralRules item2 = serializeAndDeserialize(item, size); + logln(locale + "\tsize:\t" + size.value); + max = Math.max(max, size.value); + if (!assertEquals(locale + "\tPlural rules before and after serialization", item, item2)) { + PluralRules item3 = serializeAndDeserialize(item, size); + item.equals(item2); + } + } + logln("max \tsize:\t" + max); + } +} \ No newline at end of file diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/WritePluralRulesData.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/WritePluralRulesData.java index e25c1f93388..cb8c03af24d 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/WritePluralRulesData.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/WritePluralRulesData.java @@ -6,23 +6,39 @@ */ package com.ibm.icu.dev.test.format; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import com.ibm.icu.dev.test.format.PluralRulesTest.StandardPluralCategories; import com.ibm.icu.dev.util.CollectionUtilities; import com.ibm.icu.dev.util.Relation; import com.ibm.icu.impl.Row; +import com.ibm.icu.text.NumberFormat; import com.ibm.icu.text.PluralRules; import com.ibm.icu.text.PluralRules.NumberInfo; import com.ibm.icu.util.ULocale; @@ -31,214 +47,53 @@ import com.ibm.icu.util.ULocale; * @author markdavis */ public class WritePluralRulesData { - + // TODO use options + public static final String TARGETDIR = "/Users/markdavis/Google Drive/Backup-2012-10-09/Documents/indigo/Generated/icu/plurals/"; + public static void main(String[] args) throws Exception { if (args.length == 0) { args = new String[] {"rules"}; } for (String arg : args) { if (arg.equalsIgnoreCase("samples")) { - generateSamples(); + generateSamples(SampleStyle.modified); + } else if (arg.equalsIgnoreCase("original")) { + generateSamples(SampleStyle.original); + } else if (arg.startsWith("verify")) { + generateSamples(SampleStyle.verify); } else if (arg.equalsIgnoreCase("rules")) { showRules(); } else if (arg.equalsIgnoreCase("oldSnap")) { generateLOCALE_SNAPSHOT(PluralRulesFactory.NORMAL); } else if (arg.equalsIgnoreCase("newSnap")) { generateLOCALE_SNAPSHOT(PluralRulesFactory.ALTERNATE); + } else if (arg.equalsIgnoreCase("fromList")) { + getOriginalSamples(); } else { throw new IllegalArgumentException(); } } } - public static void generateLOCALE_SNAPSHOT(PluralRulesFactory pluralRulesFactory) { - StringBuilder builder = new StringBuilder(); - Map, Relation> keywordsToData = new TreeMap(StandardPluralCategories.SHORTEST_FIRST); - for (ULocale locale : pluralRulesFactory.getAvailableULocales()) { - builder.setLength(0); - PluralRules rules = pluralRulesFactory.forLocale(locale); - boolean firstKeyword = true; - EnumSet keywords = StandardPluralCategories.getSet(rules.getKeywords()); - Relation samplesToLocales = keywordsToData.get(keywords); - if (samplesToLocales == null) { - keywordsToData.put(keywords, samplesToLocales = Relation.of( - new LinkedHashMap>(), LinkedHashSet.class)); - } - //System.out.println(locale); - for (StandardPluralCategories keyword : keywords) { - if (firstKeyword) { - firstKeyword = false; - } else { - builder.append(";\t"); - } - Collection samples = rules.getFractionSamples(keyword.toString()); - if (samples.size() == 0) { - throw new IllegalArgumentException(); - } - builder.append(keyword).append(": "); - boolean first = true; - for (NumberInfo n : samples) { - if (first) { - first = false; - } else { - builder.append(", "); - } - builder.append(n); - // for (double j : samples) { - // double sample = i + j/100; - // } - } - } - samplesToLocales.put(builder.toString(), locale); - } - System.out.println(" static final String[] LOCALE_SNAPSHOT = {"); - for (Entry, Relation> keywordsAndData : keywordsToData.entrySet()) { - System.out.println("\n // " + keywordsAndData.getKey()); - for (Entry> samplesAndLocales : keywordsAndData.getValue().keyValuesSet()) { - Set locales = samplesAndLocales.getValue(); - // check functional equivalence - boolean[] isAvailable = new boolean[1]; - for (ULocale locale : locales) { - ULocale base = pluralRulesFactory.getFunctionalEquivalent(locale, isAvailable); - if (!locales.contains(base) && base.toString().length() != 0) { - System.out.println("**" + locales + " doesn't contain " + base); - } - } - - System.out.println( - " \"" + CollectionUtilities.join(locales, ",") - + ";\t" + samplesAndLocales.getKey() + "\","); - } - } - System.out.println(" };"); - } - - private static class OldNewData extends Row.R4 { - public OldNewData(String oldRules, String oldSamples, String newRules, String newSamples) { - super(oldRules, oldSamples, newRules, newSamples); - } - } - static final String[] FOCUS_LOCALES = ("af,am,ar,az,bg,bn,ca,cs,cy,da,de,el,en,es,et,eu,fa,fi,fil,fr,gl,gu," + "hi,hr,hu,hy,id,is,it,he,ja,ka,kk,km,kn,ko,ky,lo,lt,lv,mk,ml,mn,mr,ms,my,ne,nl,nb," + "pa,pl,ps,pt,ro,ru,si,sk,sl,sq,sr,sv,sw,ta,te,th,tr,uk,ur,uz,vi,zh,zu").split("\\s*,\\s*"); - public static void showRules() { - if (true) { - // for debugging - PluralRules rules = PluralRulesFactory.ALTERNATE.forLocale(new ULocale("lv")); - rules.select(2.0d, 2, 0); - } - // System.out.println(new TreeSet(Arrays.asList(locales))); - Relation, String> rulesToLocale = Relation.of( - new TreeMap, Set>( - new CollectionUtilities.MapComparator()), TreeSet.class); - for (String localeString : FOCUS_LOCALES) { - ULocale locale = new ULocale(localeString); - PluralRules oldRules = PluralRulesFactory.NORMAL.forLocale(locale); - PluralRules newRules = PluralRulesFactory.ALTERNATE.hasOverride(locale) ? PluralRulesFactory.ALTERNATE.forLocale(locale) : null; - Set keywords = oldRules.getKeywords(); - if (newRules != null) { - TreeSet temp = new TreeSet(PluralRules.KEYWORD_COMPARATOR); - temp.addAll(keywords); - temp.addAll(newRules.getKeywords()); - keywords = temp; - } - Map temp = new LinkedHashMap(); - for (String keyword : keywords) { - Collection oldFractionSamples = oldRules.getFractionSamples(keyword); - Collection newFractionSamples = newRules == null ? null : newRules.getFractionSamples(keyword); - - // add extra samples if we have some, or if the rules differ - - if (newRules != null) { - oldFractionSamples = oldFractionSamples == null ? new TreeSet() - : new TreeSet(oldFractionSamples); - newFractionSamples = newFractionSamples == null ? new TreeSet() - : new TreeSet(newFractionSamples); - // if (extraSamples != null) { - // for (NumberPlus sample : extraSamples) { - // if (oldRules.select(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits).equals(keyword)) { - // oldFractionSamples.add(sample); - // } - // if (newRules != null && newRules.select(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits).equals(keyword)) { - // newFractionSamples.add(sample); - // } - // } - // } - - // if the rules differ, then add samples from each to the other - if (newRules != null) { - for (NumberInfo sample : oldRules.getFractionSamples()) { - if (newRules.select(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits).equals(keyword)) { - newFractionSamples.add(sample); - } - } - for (NumberInfo sample : newRules.getFractionSamples()) { - if (oldRules.select(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits).equals(keyword)) { - oldFractionSamples.add(sample); - } - } - } - } - String oldRulesString = oldRules.getRules(keyword); - if (oldRulesString == null) { - oldRulesString = ""; - } - String newRulesString = newRules == null ? "" : newRules.getRules(keyword); - if (newRulesString == null) { - newRulesString = ""; - } - temp.put(keyword, new OldNewData( - oldRulesString, - oldFractionSamples == null ? "" : "'" + CollectionUtilities.join(oldFractionSamples, ", "), - newRulesString, - newFractionSamples == null ? "" : "'" + CollectionUtilities.join(newFractionSamples, ", ") - )); - } - rulesToLocale.put(temp, locale.toString()); - } - System.out.println("Locales\tPC\tOld Rules\tOld Samples\tNew Rules\tNew Samples"); - for (Entry, Set> entry : rulesToLocale.keyValuesSet()) { - String localeList = CollectionUtilities.join(entry.getValue(), " "); - for (Entry keywordRulesSamples : entry.getKey().entrySet()) { - System.out.println( - localeList // locale - + "\t" + keywordRulesSamples.getKey() // keyword - + "\t" + keywordRulesSamples.getValue().get0() // rules - + "\t" + keywordRulesSamples.getValue().get1() // samples - + "\t" + keywordRulesSamples.getValue().get2() // rules - + "\t" + keywordRulesSamples.getValue().get3() // samples - ); - localeList = ""; - } - } - - if (false) { - System.out.println("\n\nOld Rules for Locales"); - for (String localeString : FOCUS_LOCALES) { - ULocale locale = new ULocale(localeString); - PluralRules oldRules = PluralRules.forLocale(locale); - System.out.println("{\"" + locale.toString() + "\", \"" + oldRules.toString() + "\"},"); - } - } - } - static String[][] SAMPLE_PATTERNS = { {"af", "one", "{0} dag"}, {"af", "other", "{0} dae"}, {"am", "one", "{0} ቀን"}, {"am", "other", "{0} ቀናት"}, // fixed to 'other' {"ar", "few", "{0} ساعات"}, - {"ar", "many", "{0} ساعة"}, + {"ar", "many", "{0} ساعة"}, {"ar", "one", "ساعة"}, {"ar", "other", "{0} ساعة"}, {"ar", "two", "ساعتان"}, {"ar", "zero", "{0} ساعة"}, {"bg", "one", "{0} ден"}, {"bg", "other", "{0} дена"}, - {"bn", "one", "{0} টি আপেল"}, - {"bn", "other", "আমার অনেকগুলি আপেল আছে"}, + {"bn", "other", "{0} টি আপেল"}, + //{"bn", "other", "আমার অনেকগুলি আপেল আছে"}, {"br", "few", "{0} deiz"}, {"br", "many", "{0} a zeizioù"}, {"br", "one", "{0} deiz"}, @@ -289,14 +144,10 @@ public class WritePluralRulesData { {"hr", "few", "za {0} mjeseca"}, {"hr", "many", "za {0} mjeseci"}, {"hr", "one", "za {0} mjesec"}, - {"hr", "other", "za sljedeći broj mjeseci: {0}"}, + {"hr", "other", "za {0} mjeseci"}, {"hu", "other", "{0} nap"}, - {"hy", "few", "{0} օր"}, - {"hy", "many", "{0} օր"}, - {"hy", "one", "{0} օր"}, - {"hy", "other", "{0} օր"}, - {"hy", "two", "{0} օր"}, - {"hy", "zero", "{0} օր"}, + {"hy", "one", "այդ {0} ժամը"}, + {"hy", "other", "այդ {0} ժամերը"}, {"id", "other", "{0} hari"}, {"is", "one", "{0} dagur"}, {"is", "other", "{0} dagar"}, @@ -380,6 +231,333 @@ public class WritePluralRulesData { {"zu", "one", "{0} usuku"}, // added from spreadsheet {"zu", "other", "{0} izinsuku"}, // added from spreadsheet }; + + static final Map localeToSamplePatterns = new LinkedHashMap(); + static { + for (String[] row : SAMPLE_PATTERNS) { + ULocale locale = new ULocale(row[0]); + String keyword = row[1]; + String sample = row[2]; + SamplePatterns samplePatterns = localeToSamplePatterns.get(locale); + if (samplePatterns == null) { + localeToSamplePatterns.put(locale, samplePatterns = new SamplePatterns()); + } + samplePatterns.put(keyword, sample); + } + } + + static final String[][] ORIGINAL_SAMPLES = { + {"af", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"am", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"ar", "0.0, 0.1, 0.2, 0.4, 1.0, 1.2, 1.4, 2.0, 2.1, 2.4, 4.0, 4.1, 4.2, 12.0, 12.1, 12.2, 12.4, 101.0, 101.1, 101.2, 101.4, 0.00, 0.01, 0.02, 0.04, 0.30, 0.21, 0.22, 0.14, 1.00, 1.02, 1.04, 1.30, 1.21, 1.22, 1.14, 2.00, 2.01, 2.04, 2.30, 2.21, 2.22, 2.14, 4.00, 4.01, 4.02, 4.30, 4.21, 4.22, 4.14, 12.00, 12.01, 12.02, 12.04, 101.00, 101.01, 101.02, 101.04, 101.30, 101.21, 101.22, 101.14, 0.000, 0.001, 0.002, 0.110, 0.004, 0.030, 0.021, 0.022, 0.014, 0.200, 0.201, 0.202, 1.000, 1.002, 1.110, 1.004, 1.030, 1.021, 1.022, 1.014, 1.200, 1.201, 1.202, 2.000, 2.001, 2.110, 2.004, 2.030, 2.021, 2.022, 2.014, 2.200, 2.201, 2.202, 4.000, 4.001, 4.002, 4.030, 4.021, 4.022, 4.014, 4.200, 4.201, 4.202, 12.000, 12.001, 12.002, 12.110, 12.004, 12.200, 12.201, 12.202, 101.000, 101.001, 101.002, 101.110, 101.004, 101.030, 101.021, 101.022, 101.014"}, + {"bg", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"bn", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"br", "0.0, 0.4, 0.6, 21.0, 21.4, 21.6, 22.0, 22.4, 22.6, 4.0, 4.6, 1000000.0, 1000000.4, 1000000.6, 6.0, 6.4, 0.00, 0.21, 0.22, 0.04, 0.20, 0.71, 0.72, 0.14, 0.06, 21.00, 21.22, 21.04, 21.20, 21.71, 21.72, 21.14, 21.06, 22.00, 22.21, 22.04, 22.20, 22.71, 22.72, 22.14, 22.06, 4.00, 4.21, 4.22, 4.20, 4.71, 4.72, 4.14, 4.06, 1000000.00, 1000000.21, 1000000.22, 1000000.04, 1000000.20, 1000000.71, 1000000.72, 1000000.14, 1000000.06, 6.00, 6.21, 6.22, 6.04, 0.000, 0.021, 0.022, 0.004, 0.020, 0.071, 0.072, 0.014, 0.006, 21.000, 21.022, 21.004, 21.020, 21.071, 21.072, 21.014, 21.006, 22.000, 22.021, 22.004, 22.020, 22.071, 22.072, 22.014, 22.006, 4.000, 4.021, 4.022, 4.020, 4.071, 4.072, 4.014, 4.006, 1000000.000, 1000000.021, 1000000.022, 1000000.004, 1000000.020, 1000000.071, 1000000.072, 1000000.014, 1000000.006, 6.000, 6.021, 6.022, 6.004"}, + {"ca", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"cs", "0.0, 0.1, 0.3, 0.6, 1.0, 1.3, 1.6, 3.0, 3.1, 3.6, 6.0, 6.1, 6.3, 0.00, 0.01, 0.03, 0.20, 0.21, 0.13, 0.06, 1.00, 1.03, 1.20, 1.21, 1.13, 1.06, 3.00, 3.01, 3.20, 3.21, 3.13, 3.06, 6.00, 6.01, 6.03, 0.000, 0.001, 0.003, 0.020, 0.021, 0.013, 0.006, 1.000, 1.003, 1.020, 1.021, 1.013, 1.006, 3.000, 3.001, 3.020, 3.021, 3.013, 3.006, 6.000, 6.001, 6.003"}, + {"da", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"de", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"dz", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"el", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"es", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"et", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"eu", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"fa", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"fi", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"fil", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"fr", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"gl", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"gu", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"he", "0.0, 0.1, 0.2, 0.4, 1.0, 1.2, 1.4, 2.0, 2.1, 2.4, 20.0, 20.1, 20.2, 20.4, 4.0, 4.1, 4.2, 0.00, 0.01, 0.02, 0.20, 0.21, 0.22, 0.04, 1.00, 1.02, 1.20, 1.21, 1.22, 1.04, 2.00, 2.01, 2.20, 2.21, 2.22, 2.04, 20.00, 20.01, 20.02, 20.21, 20.22, 20.04, 4.00, 4.01, 4.02, 4.20, 0.000, 0.001, 0.002, 0.020, 0.021, 0.022, 0.004, 1.000, 1.002, 1.020, 1.021, 1.022, 1.004, 2.000, 2.001, 2.020, 2.021, 2.022, 2.004, 20.000, 20.001, 20.002, 20.021, 20.022, 20.004, 4.000, 4.001, 4.002, 4.020"}, + {"hi", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"hr", "0.0, 0.3, 0.6, 21.0, 21.3, 21.6, 3.0, 3.6, 6.0, 6.3, 0.00, 0.21, 0.03, 0.20, 0.13, 0.06, 21.00, 21.03, 21.20, 21.13, 21.06, 3.00, 3.21, 3.20, 3.13, 3.06, 6.00, 6.21, 6.03, 0.000, 0.021, 0.003, 0.020, 0.111, 0.013, 0.006, 21.000, 21.003, 21.020, 21.111, 21.013, 21.006, 3.000, 3.021, 3.020, 3.111, 3.013, 3.006, 6.000, 6.021, 6.003"}, + {"hu", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"id", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"is", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"it", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"ja", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"km", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"kn", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"ko", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"lo", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"lt", "0.0, 0.3, 21.0, 21.3, 3.0, 11.0, 11.3, 0.00, 0.21, 0.03, 0.20, 0.13, 21.00, 21.03, 21.20, 21.13, 3.00, 3.21, 3.20, 3.13, 11.00, 11.21, 11.03, 0.000, 0.021, 0.003, 0.020, 0.111, 0.013, 21.000, 21.003, 21.020, 21.111, 21.013, 3.000, 3.021, 3.020, 3.111, 3.013, 11.000, 11.021, 11.003"}, + {"lv", "0.0, 0.3, 21.0, 21.3, 3.0, 0.00, 0.21, 0.20, 0.03, 21.00, 21.20, 21.03, 3.00, 3.21, 0.000, 0.021, 0.020, 0.111, 0.003, 21.000, 21.020, 21.111, 21.003, 3.000, 3.021"}, + {"ml", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"mr", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"ms", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"nb", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"ne", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"nl", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"pl", "0.0, 0.1, 0.3, 0.6, 1.0, 1.3, 1.6, 3.0, 3.1, 3.6, 6.0, 6.1, 6.3, 0.00, 0.01, 0.03, 0.20, 0.21, 0.13, 0.06, 1.00, 1.03, 1.20, 1.21, 1.13, 1.06, 3.00, 3.01, 3.20, 3.21, 3.13, 3.06, 6.00, 6.01, 6.03, 0.000, 0.001, 0.003, 0.020, 0.021, 0.013, 0.006, 1.000, 1.003, 1.020, 1.021, 1.013, 1.006, 3.000, 3.001, 3.020, 3.021, 3.013, 3.006, 6.000, 6.001, 6.003"}, + {"pt", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"pt_PT", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"ro", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 21.0, 21.1, 21.3, 0.00, 0.01, 0.03, 0.30, 0.31, 0.23, 1.00, 1.03, 1.30, 1.31, 1.23, 3.00, 3.01, 3.30, 3.31, 3.23, 21.00, 21.01, 21.03, 0.000, 0.001, 0.110, 0.101, 0.003, 0.030, 0.031, 0.023, 1.000, 1.110, 1.101, 1.003, 1.030, 1.031, 1.023, 3.000, 3.001, 3.030, 3.031, 3.023, 21.000, 21.001, 21.110, 21.101, 21.003"}, + {"ru", "0.0, 0.3, 0.6, 21.0, 21.3, 21.6, 3.0, 3.6, 6.0, 6.3, 0.00, 0.21, 0.03, 0.20, 0.13, 0.06, 21.00, 21.03, 21.20, 21.13, 21.06, 3.00, 3.21, 3.20, 3.13, 3.06, 6.00, 6.21, 6.03, 0.000, 0.021, 0.003, 0.020, 0.111, 0.013, 0.006, 21.000, 21.003, 21.020, 21.111, 21.013, 21.006, 3.000, 3.021, 3.020, 3.111, 3.013, 3.006, 6.000, 6.021, 6.003"}, + {"si", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"sk", "0.0, 0.1, 0.3, 0.6, 1.0, 1.3, 1.6, 3.0, 3.1, 3.6, 6.0, 6.1, 6.3, 0.00, 0.01, 0.03, 0.20, 0.21, 0.13, 0.06, 1.00, 1.03, 1.20, 1.21, 1.13, 1.06, 3.00, 3.01, 3.20, 3.21, 3.13, 3.06, 6.00, 6.01, 6.03, 0.000, 0.001, 0.003, 0.020, 0.021, 0.013, 0.006, 1.000, 1.003, 1.020, 1.021, 1.013, 1.006, 3.000, 3.001, 3.020, 3.021, 3.013, 3.006, 6.000, 6.001, 6.003"}, + {"sl", "0.0, 0.4, 0.6, 101.0, 101.4, 101.6, 102.0, 102.4, 102.6, 4.0, 4.6, 6.0, 6.4, 0.00, 0.04, 0.20, 0.21, 0.22, 0.14, 0.06, 101.00, 101.04, 101.20, 101.21, 101.22, 101.14, 101.06, 102.00, 102.04, 102.20, 102.21, 102.22, 102.14, 102.06, 4.00, 4.20, 4.21, 4.22, 4.14, 4.06, 6.00, 6.04, 0.000, 0.101, 0.102, 0.004, 0.020, 0.021, 0.022, 0.014, 0.006, 101.000, 101.102, 101.004, 101.020, 101.021, 101.022, 101.014, 101.006, 102.000, 102.101, 102.004, 102.020, 102.021, 102.022, 102.014, 102.006, 4.000, 4.101, 4.102, 4.020, 4.021, 4.022, 4.014, 4.006, 6.000, 6.101, 6.102, 6.004"}, + {"sr", "0.0, 0.3, 0.6, 21.0, 21.3, 21.6, 3.0, 3.6, 6.0, 6.3, 0.00, 0.21, 0.03, 0.20, 0.13, 0.06, 21.00, 21.03, 21.20, 21.13, 21.06, 3.00, 3.21, 3.20, 3.13, 3.06, 6.00, 6.21, 6.03, 0.000, 0.021, 0.003, 0.020, 0.111, 0.013, 0.006, 21.000, 21.003, 21.020, 21.111, 21.013, 21.006, 3.000, 3.021, 3.020, 3.111, 3.013, 3.006, 6.000, 6.021, 6.003"}, + {"sv", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"sw", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"ta", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"te", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"th", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"tr", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"uk", "0.0, 0.3, 0.6, 21.0, 21.3, 21.6, 3.0, 3.6, 6.0, 6.3, 0.00, 0.21, 0.03, 0.20, 0.13, 0.06, 21.00, 21.03, 21.20, 21.13, 21.06, 3.00, 3.21, 3.20, 3.13, 3.06, 6.00, 6.21, 6.03, 0.000, 0.021, 0.003, 0.020, 0.111, 0.013, 0.006, 21.000, 21.003, 21.020, 21.111, 21.013, 21.006, 3.000, 3.021, 3.020, 3.111, 3.013, 3.006, 6.000, 6.021, 6.003"}, + {"ur", "0.0, 0.1, 0.3, 1.0, 1.3, 3.0, 3.1, 0.00, 0.01, 0.20, 0.21, 0.03, 1.00, 1.20, 1.21, 1.03, 3.00, 3.01, 0.000, 0.001, 0.020, 0.021, 0.003, 1.000, 1.020, 1.021, 1.003, 3.000, 3.001"}, + {"vi", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"zh", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + {"zh_Hant", "0.0, 0.2, 2.0, 0.00, 0.20, 0.02, 2.00, 0.000, 0.020, 0.002, 2.000"}, + }; + static final Map> LOCALE_TO_ORIGINALS = new HashMap(); + static { + for (String[] pair : ORIGINAL_SAMPLES) { + ArrayList row = new ArrayList(); + for (String s : pair[1].split("\\s*,\\s*")) { + row.add(new NumberInfo(s)); + } + LOCALE_TO_ORIGINALS.put(new ULocale(pair[0]), row); + } + } + + public static void getOriginalSamples() { + try { + File file = new File("/Users/markdavis/workspace/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/plurals.txt"); + BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file))); + Map localeToSamples = new TreeMap(); + Matcher m = Pattern.compile("\\d+[.]\\d+").matcher(""); + while (true) { + String line = br.readLine(); + if (line == null) break; + String[] parts = line.split("\t"); + String locale = parts[0]; + String pattern = parts[1]; + boolean found = m.reset(pattern).find(); + String sample = found + ? m.group() + : "-1"; + String samples = localeToSamples.get(locale); + localeToSamples.put(locale, samples == null ? sample : samples + ", " + sample); + } + br.close(); + for (Entry entry : localeToSamples.entrySet()) { + System.out.println("{\"" + entry.getKey() + "\", \"" + entry.getValue() + "\"},"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static void generateLOCALE_SNAPSHOT(PluralRulesFactory pluralRulesFactory) { + StringBuilder builder = new StringBuilder(); + Map, Relation> keywordsToData = new TreeMap(StandardPluralCategories.SHORTEST_FIRST); + for (ULocale locale : pluralRulesFactory.getAvailableULocales()) { + builder.setLength(0); + PluralRules rules = pluralRulesFactory.forLocale(locale); + boolean firstKeyword = true; + EnumSet keywords = StandardPluralCategories.getSet(rules.getKeywords()); + Relation samplesToLocales = keywordsToData.get(keywords); + if (samplesToLocales == null) { + keywordsToData.put(keywords, samplesToLocales = Relation.of( + new LinkedHashMap>(), LinkedHashSet.class)); + } + //System.out.println(locale); + for (StandardPluralCategories keyword : keywords) { + if (firstKeyword) { + firstKeyword = false; + } else { + builder.append(";\t"); + } + Collection samples = rules.getFractionSamples(keyword.toString()); + if (samples.size() == 0) { + throw new IllegalArgumentException(); + } + builder.append(keyword).append(": "); + boolean first = true; + for (NumberInfo n : samples) { + if (first) { + first = false; + } else { + builder.append(", "); + } + builder.append(n); + // for (double j : samples) { + // double sample = i + j/100; + // } + } + } + samplesToLocales.put(builder.toString(), locale); + } + System.out.println(" static final String[] LOCALE_SNAPSHOT = {"); + for (Entry, Relation> keywordsAndData : keywordsToData.entrySet()) { + System.out.println("\n // " + keywordsAndData.getKey()); + for (Entry> samplesAndLocales : keywordsAndData.getValue().keyValuesSet()) { + Set locales = samplesAndLocales.getValue(); + // check functional equivalence + boolean[] isAvailable = new boolean[1]; + for (ULocale locale : locales) { + ULocale base = pluralRulesFactory.getFunctionalEquivalent(locale, isAvailable); + if (!locales.contains(base) && base.toString().length() != 0) { + System.out.println("**" + locales + " doesn't contain " + base); + } + } + + System.out.println( + " \"" + CollectionUtilities.join(locales, ",") + + ";\t" + samplesAndLocales.getKey() + "\","); + } + } + System.out.println(" };"); + } + + private static class OldNewData extends Row.R5 { + public OldNewData(String oldRules, String oldSamples, String newRules, String newSamples, String intDiff) { + super(oldRules, oldSamples, newRules, newSamples, intDiff); + } + } + + public static void showRules() { + if (true) { + // for debugging + PluralRules rules = PluralRulesFactory.ALTERNATE.forLocale(new ULocale("lv")); + rules.select(2.0d, 2, 0); + } + // System.out.println(new TreeSet(Arrays.asList(locales))); + Relation, String> rulesToLocale = Relation.of( + new TreeMap, Set>( + new CollectionUtilities.MapComparator()), TreeSet.class); + for (String localeString : FOCUS_LOCALES) { + ULocale locale = new ULocale(localeString); + PluralRules oldRules = PluralRulesFactory.NORMAL.forLocale(locale); + PluralRules newRules = PluralRulesFactory.ALTERNATE.hasOverride(locale) ? PluralRulesFactory.ALTERNATE.forLocale(locale) : null; + Set keywords = oldRules.getKeywords(); + if (newRules != null) { + TreeSet temp = new TreeSet(PluralRules.KEYWORD_COMPARATOR); + temp.addAll(keywords); + temp.addAll(newRules.getKeywords()); + keywords = temp; + } + Map temp = new LinkedHashMap(); + for (String keyword : keywords) { + Collection oldFractionSamples = oldRules.getFractionSamples(keyword); + Collection newFractionSamples = newRules == null ? null : newRules.getFractionSamples(keyword); + + // add extra samples if we have some, or if the rules differ + + if (newRules != null) { + oldFractionSamples = oldFractionSamples == null ? new TreeSet() + : new TreeSet(oldFractionSamples); + newFractionSamples = newFractionSamples == null ? new TreeSet() + : new TreeSet(newFractionSamples); + // if (extraSamples != null) { + // for (NumberPlus sample : extraSamples) { + // if (oldRules.select(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits).equals(keyword)) { + // oldFractionSamples.add(sample); + // } + // if (newRules != null && newRules.select(sample.source, sample.visibleFractionDigitCount, sample.fractionalDigits).equals(keyword)) { + // newFractionSamples.add(sample); + // } + // } + // } + + // if the rules differ, then add samples from each to the other + if (newRules != null) { + for (NumberInfo sample : oldRules.getFractionSamples()) { + if (newRules.select(sample).equals(keyword)) { + newFractionSamples.add(sample); + } + } + for (NumberInfo sample : newRules.getFractionSamples()) { + if (oldRules.select(sample).equals(keyword)) { + oldFractionSamples.add(sample); + } + } + } + } + + String intDiff = newRules == null ? "" : getDiffs(oldFractionSamples, newFractionSamples); + + String oldRulesString = rulesForDisplay(oldRules, keyword); + if (oldRulesString == null) { + oldRulesString = ""; + } + String newRulesString = newRules == null ? "" : rulesForDisplay(newRules, keyword); + if (newRulesString == null) { + newRulesString = ""; + } + if (oldRulesString.length() == 0 && newRulesString.length() != 0) { + oldRulesString = ""; + } else if (oldRulesString.length() != 0 && newRulesString.length() == 0 && newRules != null) { + newRulesString = ""; + } + temp.put(keyword, new OldNewData( + oldRulesString, + oldFractionSamples == null ? "" : "'" + CollectionUtilities.join(oldFractionSamples, ", "), + newRulesString, + newFractionSamples == null ? "" : "'" + CollectionUtilities.join(newFractionSamples, ", "), + intDiff.length() == 0 ? "" : "'" + intDiff + )); + } + rulesToLocale.put(temp, locale.toString()); + } + System.out.println("Locales\tPC\tOld Rules\tOld Sample Numbers\tNew Rules\tNew Sample Numbers\tInt-Diff"); + for (Entry, Set> entry : rulesToLocale.keyValuesSet()) { + String localeList = CollectionUtilities.join(entry.getValue(), " "); + for (Entry keywordRulesSamples : entry.getKey().entrySet()) { + System.out.println( + localeList // locale + + "\t" + keywordRulesSamples.getKey() // keyword + + "\t" + keywordRulesSamples.getValue().get0() // rules + + "\t" + keywordRulesSamples.getValue().get1() // samples + + "\t" + keywordRulesSamples.getValue().get2() // rules + + "\t" + keywordRulesSamples.getValue().get3() // samples + + "\t" + keywordRulesSamples.getValue().get4() // int diff + ); + localeList = ""; + } + } + + if (false) { + System.out.println("\n\nOld Rules for Locales"); + for (String localeString : FOCUS_LOCALES) { + ULocale locale = new ULocale(localeString); + PluralRules oldRules = PluralRules.forLocale(locale); + System.out.println("{\"" + locale.toString() + "\", \"" + oldRules.toString() + "\"},"); + } + } + } + + /** + * @param oldFractionSamples + * @param newFractionSamples + * @return + */ + private static String getDiffs(Collection oldFractionSamples, + Collection newFractionSamples) { + oldFractionSamples = oldFractionSamples == null ? Collections.EMPTY_SET : oldFractionSamples; + newFractionSamples = newFractionSamples == null ? Collections.EMPTY_SET : newFractionSamples; + + TreeSet additions = new TreeSet(newFractionSamples); + additions.removeAll(oldFractionSamples); + TreeSet removals = new TreeSet(oldFractionSamples); + removals.removeAll(newFractionSamples); + StringBuffer result = new StringBuffer(); + addInts(additions, "+", result); + addInts(removals, "-", result); + return result.toString(); + } + + private static void addInts(TreeSet additions, String title, StringBuffer result) { + for (NumberInfo n : additions) { + if (n.visibleFractionDigitCount == 0) { + if (result.length() != 0) { + result.append("; "); + } + result.append(title).append(n); + } + } + } + static final Set NEW_LOCALES = new HashSet(Arrays.asList("az,ka,kk,ky,mk,mn,my,pa,ps,sq,uz".split("\\s*,\\s*"))); static class SamplePatterns { @@ -389,7 +567,7 @@ public class WritePluralRulesData { if (keywordToPattern.containsKey(keyword)) { throw new IllegalArgumentException("Duplicate keyword <" + keyword + ">"); } else { - keywordToPattern.put(keyword, sample); + keywordToPattern.put(keyword, sample.replace(" ", "\u00A0")); } } public void checkErrors(Set set) { @@ -397,7 +575,7 @@ public class WritePluralRulesData { for (String keyword : set) { String error = ""; String sample = keywordToPattern.get(keyword); - String skeleton = sample.replace(" ", "").replace("{0}", ""); + String skeleton = sample.replace(" ", "").replaceAll("\\s*\\{0\\}\\s*", ""); String oldSkeletonKeyword = skeletonToKeyword.get(skeleton); if (oldSkeletonKeyword != null) { if (error.length() != 0) { @@ -416,22 +594,22 @@ public class WritePluralRulesData { } } - static void generateSamples() { - Map localeToSamplePatterns = new LinkedHashMap(); - for (String[] row : SAMPLE_PATTERNS) { - ULocale locale = new ULocale(row[0]); - String keyword = row[1]; - String sample = row[2]; - SamplePatterns samplePatterns = localeToSamplePatterns.get(locale); - if (samplePatterns == null) { - localeToSamplePatterns.put(locale, samplePatterns = new SamplePatterns()); - } - samplePatterns.put(keyword, sample); - } + enum SampleStyle {original, modified, verify} + + static void generateSamples(SampleStyle sampleStyle) throws IOException { LinkedHashSet skippedLocales = new LinkedHashSet(); - System.out.println("Locale\tPC\tPattern\tSample\tErrors"); + System.out.println("Locale\tPC\tPattern\tSamples\tRules\tErrors (" + sampleStyle + ")"); + BufferedWriter writer = null; for (String localeString : FOCUS_LOCALES) { ULocale locale = new ULocale(localeString); + if (sampleStyle == SampleStyle.verify) { + writer = new BufferedWriter( + new OutputStreamWriter( + new FileOutputStream(TARGETDIR + "fraction-" + locale + ".tsv"), Charset.forName("UTF-8"))); + writer.write("Plural Category\tEnglish Number\tFormatted Sample\tAcceptable?\tReplacement\n"); + } + + NumberFormat nf = NumberFormat.getInstance(new ULocale(locale.toString()+"@numbers=latn")); PluralRules newRules = PluralRulesFactory.ALTERNATE.forLocale(locale); SamplePatterns samplePatterns = localeToSamplePatterns.get(locale); if (samplePatterns == null && NEW_LOCALES.contains(localeString)) { @@ -442,108 +620,105 @@ public class WritePluralRulesData { samplePatterns.checkErrors(newRules.getKeywords()); // now print. for (String keyword : newRules.getKeywords()) { + if (sampleStyle != SampleStyle.modified) { + Collection samples = getSamples(newRules, keyword, + sampleStyle == SampleStyle.verify ? null : locale); + for (NumberInfo sample : samples) { + String pattern = samplePatterns.keywordToPattern.get(keyword); + String str = format(pattern, nf, sample); + if (sampleStyle == SampleStyle.verify) { + writer.write(keyword + "\t'" + sample + "\t" + str + "\n"); + } else { + System.out.println(locale + "\t" + keyword + "\t" + sample + "\t" + str); + } + } + continue; + } String pattern = null; String error = null; - Collection samples = newRules.getFractionSamples(keyword); + Collection samples = getSamples(newRules, keyword, null); NumberInfo first = samples.iterator().next(); String sample = "??? " + first.toString(); + String rule = ""; if (samplePatterns == null) { pattern = "???"; error = "\tERROR: Locale data missing"; } else { pattern = samplePatterns.keywordToPattern.get(keyword); + rule = rulesForDisplay(newRules, keyword); error = samplePatterns.keywordToErrors.get(keyword); if (pattern == null) { pattern = "???"; error = "\tERROR: Needed for new rules"; } else { - sample = pattern.replace("{0}", first.toString()); + StringBuilder buffer = new StringBuilder(); + for (NumberInfo x : samples) { + if (buffer.length() != 0) { + buffer.append("; "); + } + String str = format(pattern, nf, x); + buffer.append(str); + } + sample = buffer.toString(); } } System.out.println(locale + "\t" + keyword + "\t" + pattern + "\t" + sample + + "\t" + rule + error ); } + if (sampleStyle == SampleStyle.verify) { + writer.close(); + } } System.out.println("SKIP:\t\t\t" + skippedLocales); } + private static Collection getSamples(PluralRules newRules, String keyword, ULocale locale) { + if (locale == null) { + return newRules.getFractionSamples(keyword); + } + Collection result = new ArrayList(); + List originals = LOCALE_TO_ORIGINALS.get(locale); + if (originals == null) { + return newRules.getFractionSamples(keyword); + } + for (NumberInfo s : originals) { + if (keyword.equals(newRules.select(s))) { + result.add(s); + } + } + if (result.size() == 0) { + return newRules.getFractionSamples(keyword); + } + return result; + } + + private static String rulesForDisplay(PluralRules newRules, String keyword) { + String rule; + rule = newRules.getRules(keyword); + rule = rule != null ? rule.replace(" ", "\u00A0").replace("\u00A0or", " or") + : keyword.equals("other") ? "" + : ""; + return rule; + } + + private static String format(String pattern, NumberFormat nf, NumberInfo x) { + nf.setMaximumFractionDigits(x.visibleFractionDigitCount); + nf.setMinimumFractionDigits(x.visibleFractionDigitCount); + String str = nf.format(x.source); + return pattern.replace("{0}", str); + } + + /** + * + */ + private static void generateVerificationSamples() { + // TODO Auto-generated method stub + + } - static String[][] OLDRULES = { - {"af", "one: n is 1"}, - {"am", "one: n in 0..1"}, - {"ar", "zero: n is 0; one: n is 1; two: n is 2; few: n mod 100 in 3..10; many: n mod 100 in 11..99"}, - {"az", "other: null"}, - {"bg", "one: n is 1"}, - {"bn", "one: n is 1"}, - {"ca", "one: n is 1"}, - {"cs", "one: n is 1; few: n in 2..4"}, - {"cy", "zero: n is 0; one: n is 1; two: n is 2; few: n is 3; many: n is 6"}, - {"da", "one: n is 1"}, - {"de", "one: n is 1"}, - {"el", "one: n is 1"}, - {"en", "one: n is 1"}, - {"es", "one: n is 1"}, - {"et", "one: n is 1"}, - {"eu", "one: n is 1"}, - {"fa", "other: null"}, - {"fi", "one: n is 1"}, - {"fil", "one: n in 0..1"}, - {"fr", "one: n within 0..2 and n is not 2"}, - {"gl", "one: n is 1"}, - {"gu", "one: n is 1"}, - {"hi", "one: n in 0..1"}, - {"hr", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"}, - {"hu", "other: null"}, - {"hy", "one: n is 1"}, - {"id", "other: null"}, - {"is", "one: n is 1"}, - {"it", "one: n is 1"}, - {"he", "one: n is 1; two: n is 2; many: n is not 0 and n mod 10 is 0"}, - {"ja", "other: null"}, - {"ka", "other: null"}, - {"kk", "one: n is 1"}, - {"km", "other: null"}, - {"kn", "other: null"}, - {"ko", "other: null"}, - {"ky", "one: n is 1"}, - {"lo", "other: null"}, - {"lt", "one: n mod 10 is 1 and n mod 100 not in 11..19; few: n mod 10 in 2..9 and n mod 100 not in 11..19"}, - {"lv", "zero: n is 0; one: n mod 10 is 1 and n mod 100 is not 11"}, - {"mk", "one: n mod 10 is 1 and n is not 11"}, - {"ml", "one: n is 1"}, - {"mn", "one: n is 1"}, - {"mr", "one: n is 1"}, - {"ms", "other: null"}, - {"my", "other: null"}, - {"ne", "one: n is 1"}, - {"nl", "one: n is 1"}, - {"nb", "one: n is 1"}, - {"pa", "one: n is 1"}, - {"pl", "one: n is 1; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n is not 1 and n mod 10 in 0..1 or n mod 10 in 5..9 or n mod 100 in 12..14"}, - {"ps", "one: n is 1"}, - {"pt", "one: n is 1"}, - {"ro", "one: n is 1; few: n is 0 or n is not 1 and n mod 100 in 1..19"}, - {"ru", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"}, - {"si", "other: null"}, - {"sk", "one: n is 1; few: n in 2..4"}, - {"sl", "one: n mod 100 is 1; two: n mod 100 is 2; few: n mod 100 in 3..4"}, - {"sq", "one: n is 1"}, - {"sr", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"}, - {"sv", "one: n is 1"}, - {"sw", "one: n is 1"}, - {"ta", "one: n is 1"}, - {"te", "one: n is 1"}, - {"th", "other: null"}, - {"tr", "other: null"}, - {"uk", "one: n mod 10 is 1 and n mod 100 is not 11; few: n mod 10 in 2..4 and n mod 100 not in 12..14; many: n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14"}, - {"ur", "one: n is 1"}, - {"uz", "other: null"}, - {"vi", "other: null"}, - {"zh", "other: null"}, - {"zu", "one: n is 1"}, - }; } diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/plurals.txt b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/plurals.txt new file mode 100644 index 00000000000..b2159bc2ff4 --- /dev/null +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/plurals.txt @@ -0,0 +1,1957 @@ +# Copyright (C) 2013, Google Inc, International Business Machines Corporation and others +af 0.0 other other other +af 0.1 other one one +af 0.3 other other other +af 1.0 one other other +af 1.3 one other other +af 3.0 other other other +af 3.1 other one one +af 0.00 other other other +af 0.01 other one one +af 0.20 other other other +af 0.21 other other one +af 0.03 other other other +af 1.00 one other other +af 1.20 one other other +af 1.21 one other one +af 1.03 one other other +af 3.00 other other other +af 3.01 other one one +af 0.000 other other other +af 0.001 other one one +af 0.020 other other other +af 0.021 other other one +af 0.003 other other other +af 1.000 one other other +af 1.020 one other other +af 1.021 one other one +af 1.003 one other other +af 3.000 other other other +af 3.001 other one one +am 0.0 one one one +am 0.1 one one one +am 0.3 one other other +am 1.0 one one one +am 1.3 one other other +am 3.0 other one one +am 3.1 other one one +am 0.00 one one one +am 0.01 one one one +am 0.20 one other one +am 0.21 one other one +am 0.03 one other other +am 1.00 one one one +am 1.20 one other one +am 1.21 one other one +am 1.03 one other other +am 3.00 other one one +am 3.01 other one one +am 0.000 one one one +am 0.001 one one one +am 0.020 one other one +am 0.021 one other one +am 0.003 one other other +am 1.000 one one one +am 1.020 one other one +am 1.021 one other one +am 1.003 one other other +am 3.000 other one one +am 3.001 other one one +ar 0.0 zero zero zero +ar 0.1 zero one one +ar 0.2 zero two two +ar 0.4 zero few few +ar 1.0 one zero zero +ar 1.2 one two two +ar 1.4 one few few +ar 2.0 two zero zero +ar 2.1 two one one +ar 2.4 two few few +ar 4.0 few zero zero +ar 4.1 few one one +ar 4.2 few two two +ar 12.0 many zero zero +ar 12.1 many one one +ar 12.2 many two two +ar 12.4 many few few +ar 101.0 other zero zero +ar 101.1 other one one +ar 101.2 other two two +ar 101.4 other few few +ar 0.00 zero zero zero +ar 0.01 zero one one +ar 0.02 zero two two +ar 0.04 zero few few +ar 0.30 zero many zero +ar 0.21 zero many one +ar 0.22 zero many two +ar 0.14 zero many few +ar 1.00 one zero zero +ar 1.02 one two two +ar 1.04 one few few +ar 1.30 one many zero +ar 1.21 one many one +ar 1.22 one many two +ar 1.14 one many few +ar 2.00 two zero zero +ar 2.01 two one one +ar 2.04 two few few +ar 2.30 two many zero +ar 2.21 two many one +ar 2.22 two many two +ar 2.14 two many few +ar 4.00 few zero zero +ar 4.01 few one one +ar 4.02 few two two +ar 4.30 few many zero +ar 4.21 few many one +ar 4.22 few many two +ar 4.14 few many few +ar 12.00 many zero zero +ar 12.01 many one one +ar 12.02 many two two +ar 12.04 many few few +ar 101.00 other zero zero +ar 101.01 other one one +ar 101.02 other two two +ar 101.04 other few few +ar 101.30 other many zero +ar 101.21 other many one +ar 101.22 other many two +ar 101.14 other many few +ar 0.000 zero zero zero +ar 0.001 zero one one +ar 0.002 zero two two +ar 0.110 zero few zero +ar 0.004 zero few few +ar 0.030 zero many zero +ar 0.021 zero many one +ar 0.022 zero many two +ar 0.014 zero many few +ar 0.200 zero other zero +ar 0.201 zero other one +ar 0.202 zero other two +ar 1.000 one zero zero +ar 1.002 one two two +ar 1.110 one few zero +ar 1.004 one few few +ar 1.030 one many zero +ar 1.021 one many one +ar 1.022 one many two +ar 1.014 one many few +ar 1.200 one other zero +ar 1.201 one other one +ar 1.202 one other two +ar 2.000 two zero zero +ar 2.001 two one one +ar 2.110 two few zero +ar 2.004 two few few +ar 2.030 two many zero +ar 2.021 two many one +ar 2.022 two many two +ar 2.014 two many few +ar 2.200 two other zero +ar 2.201 two other one +ar 2.202 two other two +ar 4.000 few zero zero +ar 4.001 few one one +ar 4.002 few two two +ar 4.030 few many zero +ar 4.021 few many one +ar 4.022 few many two +ar 4.014 few many few +ar 4.200 few other zero +ar 4.201 few other one +ar 4.202 few other two +ar 12.000 many zero zero +ar 12.001 many one one +ar 12.002 many two two +ar 12.110 many few zero +ar 12.004 many few few +ar 12.200 many other zero +ar 12.201 many other one +ar 12.202 many other two +ar 101.000 other zero zero +ar 101.001 other one one +ar 101.002 other two two +ar 101.110 other few zero +ar 101.004 other few few +ar 101.030 other many zero +ar 101.021 other many one +ar 101.022 other many two +ar 101.014 other many few +bg 0.0 other other other +bg 0.1 other one one +bg 0.3 other other other +bg 1.0 one other other +bg 1.3 one other other +bg 3.0 other other other +bg 3.1 other one one +bg 0.00 other other other +bg 0.01 other one one +bg 0.20 other other other +bg 0.21 other other one +bg 0.03 other other other +bg 1.00 one other other +bg 1.20 one other other +bg 1.21 one other one +bg 1.03 one other other +bg 3.00 other other other +bg 3.01 other one one +bg 0.000 other other other +bg 0.001 other one one +bg 0.020 other other other +bg 0.021 other other one +bg 0.003 other other other +bg 1.000 one other other +bg 1.020 one other other +bg 1.021 one other one +bg 1.003 one other other +bg 3.000 other other other +bg 3.001 other one one +bn 0.0 other other other +bn 0.1 other one one +bn 0.3 other other other +bn 1.0 one other other +bn 1.3 one other other +bn 3.0 other other other +bn 3.1 other one one +bn 0.00 other other other +bn 0.01 other one one +bn 0.20 other other other +bn 0.21 other other one +bn 0.03 other other other +bn 1.00 one other other +bn 1.20 one other other +bn 1.21 one other one +bn 1.03 one other other +bn 3.00 other other other +bn 3.01 other one one +bn 0.000 other other other +bn 0.001 other one one +bn 0.020 other other other +bn 0.021 other other one +bn 0.003 other other other +bn 1.000 one other other +bn 1.020 one other other +bn 1.021 one other one +bn 1.003 one other other +bn 3.000 other other other +bn 3.001 other one one +br 0.0 other other other +br 0.4 other few few +br 0.6 other other other +br 21.0 one other other +br 21.4 one few few +br 21.6 one other other +br 22.0 two other other +br 22.4 two few few +br 22.6 two other other +br 4.0 few other other +br 4.6 few other other +br 1000000.0 many other other +br 1000000.4 many few few +br 1000000.6 many other other +br 6.0 other other other +br 6.4 other few few +br 0.00 other other other +br 0.21 other one one +br 0.22 other two two +br 0.04 other few few +br 0.20 other other other +br 0.71 other other one +br 0.72 other other two +br 0.14 other other few +br 0.06 other other other +br 21.00 one other other +br 21.22 one two two +br 21.04 one few few +br 21.20 one other other +br 21.71 one other one +br 21.72 one other two +br 21.14 one other few +br 21.06 one other other +br 22.00 two other other +br 22.21 two one one +br 22.04 two few few +br 22.20 two other other +br 22.71 two other one +br 22.72 two other two +br 22.14 two other few +br 22.06 two other other +br 4.00 few other other +br 4.21 few one one +br 4.22 few two two +br 4.20 few other other +br 4.71 few other one +br 4.72 few other two +br 4.14 few other few +br 4.06 few other other +br 1000000.00 many other other +br 1000000.21 many one one +br 1000000.22 many two two +br 1000000.04 many few few +br 1000000.20 many other other +br 1000000.71 many other one +br 1000000.72 many other two +br 1000000.14 many other few +br 1000000.06 many other other +br 6.00 other other other +br 6.21 other one one +br 6.22 other two two +br 6.04 other few few +br 0.000 other other other +br 0.021 other one one +br 0.022 other two two +br 0.004 other few few +br 0.020 other other other +br 0.071 other other one +br 0.072 other other two +br 0.014 other other few +br 0.006 other other other +br 21.000 one other other +br 21.022 one two two +br 21.004 one few few +br 21.020 one other other +br 21.071 one other one +br 21.072 one other two +br 21.014 one other few +br 21.006 one other other +br 22.000 two other other +br 22.021 two one one +br 22.004 two few few +br 22.020 two other other +br 22.071 two other one +br 22.072 two other two +br 22.014 two other few +br 22.006 two other other +br 4.000 few other other +br 4.021 few one one +br 4.022 few two two +br 4.020 few other other +br 4.071 few other one +br 4.072 few other two +br 4.014 few other few +br 4.006 few other other +br 1000000.000 many other other +br 1000000.021 many one one +br 1000000.022 many two two +br 1000000.004 many few few +br 1000000.020 many other other +br 1000000.071 many other one +br 1000000.072 many other two +br 1000000.014 many other few +br 1000000.006 many other other +br 6.000 other other other +br 6.021 other one one +br 6.022 other two two +br 6.004 other few few +ca 0.0 other other other +ca 0.1 other one one +ca 0.3 other other other +ca 1.0 one other other +ca 1.3 one other other +ca 3.0 other other other +ca 3.1 other one one +ca 0.00 other other other +ca 0.01 other one one +ca 0.20 other other other +ca 0.21 other other one +ca 0.03 other other other +ca 1.00 one other other +ca 1.20 one other other +ca 1.21 one other one +ca 1.03 one other other +ca 3.00 other other other +ca 3.01 other one one +ca 0.000 other other other +ca 0.001 other one one +ca 0.020 other other other +ca 0.021 other other one +ca 0.003 other other other +ca 1.000 one other other +ca 1.020 one other other +ca 1.021 one other one +ca 1.003 one other other +ca 3.000 other other other +ca 3.001 other one one +cs 0.0 other other other +cs 0.1 other one one +cs 0.3 other few few +cs 0.6 other other other +cs 1.0 one other other +cs 1.3 one few few +cs 1.6 one other other +cs 3.0 few other other +cs 3.1 few one one +cs 3.6 few other other +cs 6.0 other other other +cs 6.1 other one one +cs 6.3 other few few +cs 0.00 other other other +cs 0.01 other one one +cs 0.03 other few few +cs 0.20 other other other +cs 0.21 other other one +cs 0.13 other other few +cs 0.06 other other other +cs 1.00 one other other +cs 1.03 one few few +cs 1.20 one other other +cs 1.21 one other one +cs 1.13 one other few +cs 1.06 one other other +cs 3.00 few other other +cs 3.01 few one one +cs 3.20 few other other +cs 3.21 few other one +cs 3.13 few other few +cs 3.06 few other other +cs 6.00 other other other +cs 6.01 other one one +cs 6.03 other few few +cs 0.000 other other other +cs 0.001 other one one +cs 0.003 other few few +cs 0.020 other other other +cs 0.021 other other one +cs 0.013 other other few +cs 0.006 other other other +cs 1.000 one other other +cs 1.003 one few few +cs 1.020 one other other +cs 1.021 one other one +cs 1.013 one other few +cs 1.006 one other other +cs 3.000 few other other +cs 3.001 few one one +cs 3.020 few other other +cs 3.021 few other one +cs 3.013 few other few +cs 3.006 few other other +cs 6.000 other other other +cs 6.001 other one one +cs 6.003 other few few +da 0.0 other other other +da 0.1 other one one +da 0.3 other other other +da 1.0 one other other +da 1.3 one other other +da 3.0 other other other +da 3.1 other one one +da 0.00 other other other +da 0.01 other one one +da 0.20 other other other +da 0.21 other other one +da 0.03 other other other +da 1.00 one other other +da 1.20 one other other +da 1.21 one other one +da 1.03 one other other +da 3.00 other other other +da 3.01 other one one +da 0.000 other other other +da 0.001 other one one +da 0.020 other other other +da 0.021 other other one +da 0.003 other other other +da 1.000 one other other +da 1.020 one other other +da 1.021 one other one +da 1.003 one other other +da 3.000 other other other +da 3.001 other one one +de 0.0 other other other +de 0.1 other one one +de 0.3 other other other +de 1.0 one other other +de 1.3 one other other +de 3.0 other other other +de 3.1 other one one +de 0.00 other other other +de 0.01 other one one +de 0.20 other other other +de 0.21 other other one +de 0.03 other other other +de 1.00 one other other +de 1.20 one other other +de 1.21 one other one +de 1.03 one other other +de 3.00 other other other +de 3.01 other one one +de 0.000 other other other +de 0.001 other one one +de 0.020 other other other +de 0.021 other other one +de 0.003 other other other +de 1.000 one other other +de 1.020 one other other +de 1.021 one other one +de 1.003 one other other +de 3.000 other other other +de 3.001 other one one +dz 0.0 other other other +dz 0.2 other other other +dz 2.0 other other other +dz 0.00 other other other +dz 0.20 other other other +dz 0.02 other other other +dz 2.00 other other other +dz 0.000 other other other +dz 0.020 other other other +dz 0.002 other other other +dz 2.000 other other other +el 0.0 other other other +el 0.1 other one one +el 0.3 other other other +el 1.0 one other other +el 1.3 one other other +el 3.0 other other other +el 3.1 other one one +el 0.00 other other other +el 0.01 other one one +el 0.20 other other other +el 0.21 other other one +el 0.03 other other other +el 1.00 one other other +el 1.20 one other other +el 1.21 one other one +el 1.03 one other other +el 3.00 other other other +el 3.01 other one one +el 0.000 other other other +el 0.001 other one one +el 0.020 other other other +el 0.021 other other one +el 0.003 other other other +el 1.000 one other other +el 1.020 one other other +el 1.021 one other one +el 1.003 one other other +el 3.000 other other other +el 3.001 other one one +es 0.0 other other other +es 0.1 other one one +es 0.3 other other other +es 1.0 one other other +es 1.3 one other other +es 3.0 other other other +es 3.1 other one one +es 0.00 other other other +es 0.01 other one one +es 0.20 other other other +es 0.21 other other one +es 0.03 other other other +es 1.00 one other other +es 1.20 one other other +es 1.21 one other one +es 1.03 one other other +es 3.00 other other other +es 3.01 other one one +es 0.000 other other other +es 0.001 other one one +es 0.020 other other other +es 0.021 other other one +es 0.003 other other other +es 1.000 one other other +es 1.020 one other other +es 1.021 one other one +es 1.003 one other other +es 3.000 other other other +es 3.001 other one one +et 0.0 other other other +et 0.1 other one one +et 0.3 other other other +et 1.0 one other other +et 1.3 one other other +et 3.0 other other other +et 3.1 other one one +et 0.00 other other other +et 0.01 other one one +et 0.20 other other other +et 0.21 other other one +et 0.03 other other other +et 1.00 one other other +et 1.20 one other other +et 1.21 one other one +et 1.03 one other other +et 3.00 other other other +et 3.01 other one one +et 0.000 other other other +et 0.001 other one one +et 0.020 other other other +et 0.021 other other one +et 0.003 other other other +et 1.000 one other other +et 1.020 one other other +et 1.021 one other one +et 1.003 one other other +et 3.000 other other other +et 3.001 other one one +eu 0.0 other other other +eu 0.1 other one one +eu 0.3 other other other +eu 1.0 one other other +eu 1.3 one other other +eu 3.0 other other other +eu 3.1 other one one +eu 0.00 other other other +eu 0.01 other one one +eu 0.20 other other other +eu 0.21 other other one +eu 0.03 other other other +eu 1.00 one other other +eu 1.20 one other other +eu 1.21 one other one +eu 1.03 one other other +eu 3.00 other other other +eu 3.01 other one one +eu 0.000 other other other +eu 0.001 other one one +eu 0.020 other other other +eu 0.021 other other one +eu 0.003 other other other +eu 1.000 one other other +eu 1.020 one other other +eu 1.021 one other one +eu 1.003 one other other +eu 3.000 other other other +eu 3.001 other one one +fa 0.0 other other other +fa 0.2 other other other +fa 2.0 other other other +fa 0.00 other other other +fa 0.20 other other other +fa 0.02 other other other +fa 2.00 other other other +fa 0.000 other other other +fa 0.020 other other other +fa 0.002 other other other +fa 2.000 other other other +fi 0.0 other other other +fi 0.1 other one one +fi 0.3 other other other +fi 1.0 one other other +fi 1.3 one other other +fi 3.0 other other other +fi 3.1 other one one +fi 0.00 other other other +fi 0.01 other one one +fi 0.20 other other other +fi 0.21 other other one +fi 0.03 other other other +fi 1.00 one other other +fi 1.20 one other other +fi 1.21 one other one +fi 1.03 one other other +fi 3.00 other other other +fi 3.01 other one one +fi 0.000 other other other +fi 0.001 other one one +fi 0.020 other other other +fi 0.021 other other one +fi 0.003 other other other +fi 1.000 one other other +fi 1.020 one other other +fi 1.021 one other one +fi 1.003 one other other +fi 3.000 other other other +fi 3.001 other one one +fil 0.0 one one one +fil 0.1 one one one +fil 0.3 one other other +fil 1.0 one one one +fil 1.3 one other other +fil 3.0 other one one +fil 3.1 other one one +fil 0.00 one one one +fil 0.01 one one one +fil 0.20 one other one +fil 0.21 one other one +fil 0.03 one other other +fil 1.00 one one one +fil 1.20 one other one +fil 1.21 one other one +fil 1.03 one other other +fil 3.00 other one one +fil 3.01 other one one +fil 0.000 one one one +fil 0.001 one one one +fil 0.020 one other one +fil 0.021 one other one +fil 0.003 one other other +fil 1.000 one one one +fil 1.020 one other one +fil 1.021 one other one +fil 1.003 one other other +fil 3.000 other one one +fil 3.001 other one one +fr 0.0 one one one +fr 0.1 one one one +fr 0.3 one other other +fr 1.0 one one one +fr 1.3 one other other +fr 3.0 other one one +fr 3.1 other one one +fr 0.00 one one one +fr 0.01 one one one +fr 0.20 one other one +fr 0.21 one other one +fr 0.03 one other other +fr 1.00 one one one +fr 1.20 one other one +fr 1.21 one other one +fr 1.03 one other other +fr 3.00 other one one +fr 3.01 other one one +fr 0.000 one one one +fr 0.001 one one one +fr 0.020 one other one +fr 0.021 one other one +fr 0.003 one other other +fr 1.000 one one one +fr 1.020 one other one +fr 1.021 one other one +fr 1.003 one other other +fr 3.000 other one one +fr 3.001 other one one +gl 0.0 other other other +gl 0.1 other one one +gl 0.3 other other other +gl 1.0 one other other +gl 1.3 one other other +gl 3.0 other other other +gl 3.1 other one one +gl 0.00 other other other +gl 0.01 other one one +gl 0.20 other other other +gl 0.21 other other one +gl 0.03 other other other +gl 1.00 one other other +gl 1.20 one other other +gl 1.21 one other one +gl 1.03 one other other +gl 3.00 other other other +gl 3.01 other one one +gl 0.000 other other other +gl 0.001 other one one +gl 0.020 other other other +gl 0.021 other other one +gl 0.003 other other other +gl 1.000 one other other +gl 1.020 one other other +gl 1.021 one other one +gl 1.003 one other other +gl 3.000 other other other +gl 3.001 other one one +gu 0.0 other other other +gu 0.1 other one one +gu 0.3 other other other +gu 1.0 one other other +gu 1.3 one other other +gu 3.0 other other other +gu 3.1 other one one +gu 0.00 other other other +gu 0.01 other one one +gu 0.20 other other other +gu 0.21 other other one +gu 0.03 other other other +gu 1.00 one other other +gu 1.20 one other other +gu 1.21 one other one +gu 1.03 one other other +gu 3.00 other other other +gu 3.01 other one one +gu 0.000 other other other +gu 0.001 other one one +gu 0.020 other other other +gu 0.021 other other one +gu 0.003 other other other +gu 1.000 one other other +gu 1.020 one other other +gu 1.021 one other one +gu 1.003 one other other +gu 3.000 other other other +gu 3.001 other one one +he 0.0 other other other +he 0.1 other one one +he 0.2 other two two +he 0.4 other other other +he 1.0 one other other +he 1.2 one two two +he 1.4 one other other +he 2.0 two other other +he 2.1 two one one +he 2.4 two other other +he 20.0 many other other +he 20.1 many one one +he 20.2 many two two +he 20.4 many other other +he 4.0 other other other +he 4.1 other one one +he 4.2 other two two +he 0.00 other other other +he 0.01 other one one +he 0.02 other two two +he 0.20 other many other +he 0.21 other other one +he 0.22 other other two +he 0.04 other other other +he 1.00 one other other +he 1.02 one two two +he 1.20 one many other +he 1.21 one other one +he 1.22 one other two +he 1.04 one other other +he 2.00 two other other +he 2.01 two one one +he 2.20 two many other +he 2.21 two other one +he 2.22 two other two +he 2.04 two other other +he 20.00 many other other +he 20.01 many one one +he 20.02 many two two +he 20.21 many other one +he 20.22 many other two +he 20.04 many other other +he 4.00 other other other +he 4.01 other one one +he 4.02 other two two +he 4.20 other many other +he 0.000 other other other +he 0.001 other one one +he 0.002 other two two +he 0.020 other many other +he 0.021 other other one +he 0.022 other other two +he 0.004 other other other +he 1.000 one other other +he 1.002 one two two +he 1.020 one many other +he 1.021 one other one +he 1.022 one other two +he 1.004 one other other +he 2.000 two other other +he 2.001 two one one +he 2.020 two many other +he 2.021 two other one +he 2.022 two other two +he 2.004 two other other +he 20.000 many other other +he 20.001 many one one +he 20.002 many two two +he 20.021 many other one +he 20.022 many other two +he 20.004 many other other +he 4.000 other other other +he 4.001 other one one +he 4.002 other two two +he 4.020 other many other +hi 0.0 one one one +hi 0.1 one one one +hi 0.3 one other other +hi 1.0 one one one +hi 1.3 one other other +hi 3.0 other one one +hi 3.1 other one one +hi 0.00 one one one +hi 0.01 one one one +hi 0.20 one other one +hi 0.21 one other one +hi 0.03 one other other +hi 1.00 one one one +hi 1.20 one other one +hi 1.21 one other one +hi 1.03 one other other +hi 3.00 other one one +hi 3.01 other one one +hi 0.000 one one one +hi 0.001 one one one +hi 0.020 one other one +hi 0.021 one other one +hi 0.003 one other other +hi 1.000 one one one +hi 1.020 one other one +hi 1.021 one other one +hi 1.003 one other other +hi 3.000 other one one +hi 3.001 other one one +hr 0.0 many many many +hr 0.3 many few few +hr 0.6 many many many +hr 21.0 one many many +hr 21.3 one few few +hr 21.6 one many many +hr 3.0 few many many +hr 3.6 few many many +hr 6.0 many many many +hr 6.3 many few few +hr 0.00 many many many +hr 0.21 many one one +hr 0.03 many few few +hr 0.20 many many many +hr 0.13 many many few +hr 0.06 many many many +hr 21.00 one many many +hr 21.03 one few few +hr 21.20 one many many +hr 21.13 one many few +hr 21.06 one many many +hr 3.00 few many many +hr 3.21 few one one +hr 3.20 few many many +hr 3.13 few many few +hr 3.06 few many many +hr 6.00 many many many +hr 6.21 many one one +hr 6.03 many few few +hr 0.000 many many many +hr 0.021 many one one +hr 0.003 many few few +hr 0.020 many many many +hr 0.111 many many one +hr 0.013 many many few +hr 0.006 many many many +hr 21.000 one many many +hr 21.003 one few few +hr 21.020 one many many +hr 21.111 one many one +hr 21.013 one many few +hr 21.006 one many many +hr 3.000 few many many +hr 3.021 few one one +hr 3.020 few many many +hr 3.111 few many one +hr 3.013 few many few +hr 3.006 few many many +hr 6.000 many many many +hr 6.021 many one one +hr 6.003 many few few +hu 0.0 other other other +hu 0.2 other other other +hu 2.0 other other other +hu 0.00 other other other +hu 0.20 other other other +hu 0.02 other other other +hu 2.00 other other other +hu 0.000 other other other +hu 0.020 other other other +hu 0.002 other other other +hu 2.000 other other other +id 0.0 other other other +id 0.2 other other other +id 2.0 other other other +id 0.00 other other other +id 0.20 other other other +id 0.02 other other other +id 2.00 other other other +id 0.000 other other other +id 0.020 other other other +id 0.002 other other other +id 2.000 other other other +is 0.0 other other other +is 0.1 other one one +is 0.3 other other other +is 1.0 one other other +is 1.3 one other other +is 3.0 other other other +is 3.1 other one one +is 0.00 other other other +is 0.01 other one one +is 0.20 other other other +is 0.21 other other one +is 0.03 other other other +is 1.00 one other other +is 1.20 one other other +is 1.21 one other one +is 1.03 one other other +is 3.00 other other other +is 3.01 other one one +is 0.000 other other other +is 0.001 other one one +is 0.020 other other other +is 0.021 other other one +is 0.003 other other other +is 1.000 one other other +is 1.020 one other other +is 1.021 one other one +is 1.003 one other other +is 3.000 other other other +is 3.001 other one one +it 0.0 other other other +it 0.1 other one one +it 0.3 other other other +it 1.0 one other other +it 1.3 one other other +it 3.0 other other other +it 3.1 other one one +it 0.00 other other other +it 0.01 other one one +it 0.20 other other other +it 0.21 other other one +it 0.03 other other other +it 1.00 one other other +it 1.20 one other other +it 1.21 one other one +it 1.03 one other other +it 3.00 other other other +it 3.01 other one one +it 0.000 other other other +it 0.001 other one one +it 0.020 other other other +it 0.021 other other one +it 0.003 other other other +it 1.000 one other other +it 1.020 one other other +it 1.021 one other one +it 1.003 one other other +it 3.000 other other other +it 3.001 other one one +ja 0.0 other other other +ja 0.2 other other other +ja 2.0 other other other +ja 0.00 other other other +ja 0.20 other other other +ja 0.02 other other other +ja 2.00 other other other +ja 0.000 other other other +ja 0.020 other other other +ja 0.002 other other other +ja 2.000 other other other +km 0.0 other other other +km 0.2 other other other +km 2.0 other other other +km 0.00 other other other +km 0.20 other other other +km 0.02 other other other +km 2.00 other other other +km 0.000 other other other +km 0.020 other other other +km 0.002 other other other +km 2.000 other other other +kn 0.0 other other other +kn 0.2 other other other +kn 2.0 other other other +kn 0.00 other other other +kn 0.20 other other other +kn 0.02 other other other +kn 2.00 other other other +kn 0.000 other other other +kn 0.020 other other other +kn 0.002 other other other +kn 2.000 other other other +ko 0.0 other other other +ko 0.2 other other other +ko 2.0 other other other +ko 0.00 other other other +ko 0.20 other other other +ko 0.02 other other other +ko 2.00 other other other +ko 0.000 other other other +ko 0.020 other other other +ko 0.002 other other other +ko 2.000 other other other +lo 0.0 other other other +lo 0.2 other other other +lo 2.0 other other other +lo 0.00 other other other +lo 0.20 other other other +lo 0.02 other other other +lo 2.00 other other other +lo 0.000 other other other +lo 0.020 other other other +lo 0.002 other other other +lo 2.000 other other other +lt 0.0 other other other +lt 0.3 other few few +lt 21.0 one other other +lt 21.3 one few few +lt 3.0 few other other +lt 11.0 other other other +lt 11.3 other few few +lt 0.00 other other other +lt 0.21 other one one +lt 0.03 other few few +lt 0.20 other other other +lt 0.13 other other few +lt 21.00 one other other +lt 21.03 one few few +lt 21.20 one other other +lt 21.13 one other few +lt 3.00 few other other +lt 3.21 few one one +lt 3.20 few other other +lt 3.13 few other few +lt 11.00 other other other +lt 11.21 other one one +lt 11.03 other few few +lt 0.000 other other other +lt 0.021 other one one +lt 0.003 other few few +lt 0.020 other other other +lt 0.111 other other one +lt 0.013 other other few +lt 21.000 one other other +lt 21.003 one few few +lt 21.020 one other other +lt 21.111 one other one +lt 21.013 one other few +lt 3.000 few other other +lt 3.021 few one one +lt 3.020 few other other +lt 3.111 few other one +lt 3.013 few other few +lt 11.000 other other other +lt 11.021 other one one +lt 11.003 other few few +lv 0.0 zero zero zero +lv 0.3 zero other other +lv 21.0 one zero zero +lv 21.3 one other other +lv 3.0 other zero zero +lv 0.00 zero zero zero +lv 0.21 zero one one +lv 0.20 zero other zero +lv 0.03 zero other other +lv 21.00 one zero zero +lv 21.20 one other zero +lv 21.03 one other other +lv 3.00 other zero zero +lv 3.21 other one one +lv 0.000 zero zero zero +lv 0.021 zero one one +lv 0.020 zero other zero +lv 0.111 zero other one +lv 0.003 zero other other +lv 21.000 one zero zero +lv 21.020 one other zero +lv 21.111 one other one +lv 21.003 one other other +lv 3.000 other zero zero +lv 3.021 other one one +ml 0.0 other other other +ml 0.1 other one one +ml 0.3 other other other +ml 1.0 one other other +ml 1.3 one other other +ml 3.0 other other other +ml 3.1 other one one +ml 0.00 other other other +ml 0.01 other one one +ml 0.20 other other other +ml 0.21 other other one +ml 0.03 other other other +ml 1.00 one other other +ml 1.20 one other other +ml 1.21 one other one +ml 1.03 one other other +ml 3.00 other other other +ml 3.01 other one one +ml 0.000 other other other +ml 0.001 other one one +ml 0.020 other other other +ml 0.021 other other one +ml 0.003 other other other +ml 1.000 one other other +ml 1.020 one other other +ml 1.021 one other one +ml 1.003 one other other +ml 3.000 other other other +ml 3.001 other one one +mr 0.0 other other other +mr 0.1 other one one +mr 0.3 other other other +mr 1.0 one other other +mr 1.3 one other other +mr 3.0 other other other +mr 3.1 other one one +mr 0.00 other other other +mr 0.01 other one one +mr 0.20 other other other +mr 0.21 other other one +mr 0.03 other other other +mr 1.00 one other other +mr 1.20 one other other +mr 1.21 one other one +mr 1.03 one other other +mr 3.00 other other other +mr 3.01 other one one +mr 0.000 other other other +mr 0.001 other one one +mr 0.020 other other other +mr 0.021 other other one +mr 0.003 other other other +mr 1.000 one other other +mr 1.020 one other other +mr 1.021 one other one +mr 1.003 one other other +mr 3.000 other other other +mr 3.001 other one one +ms 0.0 other other other +ms 0.2 other other other +ms 2.0 other other other +ms 0.00 other other other +ms 0.20 other other other +ms 0.02 other other other +ms 2.00 other other other +ms 0.000 other other other +ms 0.020 other other other +ms 0.002 other other other +ms 2.000 other other other +nb 0.0 other other other +nb 0.1 other one one +nb 0.3 other other other +nb 1.0 one other other +nb 1.3 one other other +nb 3.0 other other other +nb 3.1 other one one +nb 0.00 other other other +nb 0.01 other one one +nb 0.20 other other other +nb 0.21 other other one +nb 0.03 other other other +nb 1.00 one other other +nb 1.20 one other other +nb 1.21 one other one +nb 1.03 one other other +nb 3.00 other other other +nb 3.01 other one one +nb 0.000 other other other +nb 0.001 other one one +nb 0.020 other other other +nb 0.021 other other one +nb 0.003 other other other +nb 1.000 one other other +nb 1.020 one other other +nb 1.021 one other one +nb 1.003 one other other +nb 3.000 other other other +nb 3.001 other one one +ne 0.0 other other other +ne 0.1 other one one +ne 0.3 other other other +ne 1.0 one other other +ne 1.3 one other other +ne 3.0 other other other +ne 3.1 other one one +ne 0.00 other other other +ne 0.01 other one one +ne 0.20 other other other +ne 0.21 other other one +ne 0.03 other other other +ne 1.00 one other other +ne 1.20 one other other +ne 1.21 one other one +ne 1.03 one other other +ne 3.00 other other other +ne 3.01 other one one +ne 0.000 other other other +ne 0.001 other one one +ne 0.020 other other other +ne 0.021 other other one +ne 0.003 other other other +ne 1.000 one other other +ne 1.020 one other other +ne 1.021 one other one +ne 1.003 one other other +ne 3.000 other other other +ne 3.001 other one one +nl 0.0 other other other +nl 0.1 other one one +nl 0.3 other other other +nl 1.0 one other other +nl 1.3 one other other +nl 3.0 other other other +nl 3.1 other one one +nl 0.00 other other other +nl 0.01 other one one +nl 0.20 other other other +nl 0.21 other other one +nl 0.03 other other other +nl 1.00 one other other +nl 1.20 one other other +nl 1.21 one other one +nl 1.03 one other other +nl 3.00 other other other +nl 3.01 other one one +nl 0.000 other other other +nl 0.001 other one one +nl 0.020 other other other +nl 0.021 other other one +nl 0.003 other other other +nl 1.000 one other other +nl 1.020 one other other +nl 1.021 one other one +nl 1.003 one other other +nl 3.000 other other other +nl 3.001 other one one +pl 0.0 many many many +pl 0.1 many one one +pl 0.3 many few few +pl 0.6 many many many +pl 1.0 one many many +pl 1.3 one few few +pl 1.6 one many many +pl 3.0 few many many +pl 3.1 few one one +pl 3.6 few many many +pl 6.0 many many many +pl 6.1 many one one +pl 6.3 many few few +pl 0.00 many many many +pl 0.01 many one one +pl 0.03 many few few +pl 0.20 many many many +pl 0.21 many many one +pl 0.13 many many few +pl 0.06 many many many +pl 1.00 one many many +pl 1.03 one few few +pl 1.20 one many many +pl 1.21 one many one +pl 1.13 one many few +pl 1.06 one many many +pl 3.00 few many many +pl 3.01 few one one +pl 3.20 few many many +pl 3.21 few many one +pl 3.13 few many few +pl 3.06 few many many +pl 6.00 many many many +pl 6.01 many one one +pl 6.03 many few few +pl 0.000 many many many +pl 0.001 many one one +pl 0.003 many few few +pl 0.020 many many many +pl 0.021 many many one +pl 0.013 many many few +pl 0.006 many many many +pl 1.000 one many many +pl 1.003 one few few +pl 1.020 one many many +pl 1.021 one many one +pl 1.013 one many few +pl 1.006 one many many +pl 3.000 few many many +pl 3.001 few one one +pl 3.020 few many many +pl 3.021 few many one +pl 3.013 few many few +pl 3.006 few many many +pl 6.000 many many many +pl 6.001 many one one +pl 6.003 many few few +pt 0.0 other other other +pt 0.1 other one one +pt 0.3 other other other +pt 1.0 one other other +pt 1.3 one other other +pt 3.0 other other other +pt 3.1 other one one +pt 0.00 other other other +pt 0.01 other one one +pt 0.20 other other other +pt 0.21 other other one +pt 0.03 other other other +pt 1.00 one other other +pt 1.20 one other other +pt 1.21 one other one +pt 1.03 one other other +pt 3.00 other other other +pt 3.01 other one one +pt 0.000 other other other +pt 0.001 other one one +pt 0.020 other other other +pt 0.021 other other one +pt 0.003 other other other +pt 1.000 one other other +pt 1.020 one other other +pt 1.021 one other one +pt 1.003 one other other +pt 3.000 other other other +pt 3.001 other one one +pt_PT 0.0 other other other +pt_PT 0.1 other one one +pt_PT 0.3 other other other +pt_PT 1.0 one other other +pt_PT 1.3 one other other +pt_PT 3.0 other other other +pt_PT 3.1 other one one +pt_PT 0.00 other other other +pt_PT 0.01 other one one +pt_PT 0.20 other other other +pt_PT 0.21 other other one +pt_PT 0.03 other other other +pt_PT 1.00 one other other +pt_PT 1.20 one other other +pt_PT 1.21 one other one +pt_PT 1.03 one other other +pt_PT 3.00 other other other +pt_PT 3.01 other one one +pt_PT 0.000 other other other +pt_PT 0.001 other one one +pt_PT 0.020 other other other +pt_PT 0.021 other other one +pt_PT 0.003 other other other +pt_PT 1.000 one other other +pt_PT 1.020 one other other +pt_PT 1.021 one other one +pt_PT 1.003 one other other +pt_PT 3.000 other other other +pt_PT 3.001 other one one +ro 0.0 few few few +ro 0.1 few one one +ro 0.3 few few few +ro 1.0 one few few +ro 1.3 one few few +ro 3.0 few few few +ro 3.1 few one one +ro 21.0 other few few +ro 21.1 other one one +ro 21.3 other few few +ro 0.00 few few few +ro 0.01 few one one +ro 0.03 few few few +ro 0.30 few other few +ro 0.31 few other one +ro 0.23 few other few +ro 1.00 one few few +ro 1.03 one few few +ro 1.30 one other few +ro 1.31 one other one +ro 1.23 one other few +ro 3.00 few few few +ro 3.01 few one one +ro 3.30 few other few +ro 3.31 few other one +ro 3.23 few other few +ro 21.00 other few few +ro 21.01 other one one +ro 21.03 other few few +ro 0.000 few few few +ro 0.001 few one one +ro 0.110 few few few +ro 0.101 few few one +ro 0.003 few few few +ro 0.030 few other few +ro 0.031 few other one +ro 0.023 few other few +ro 1.000 one few few +ro 1.110 one few few +ro 1.101 one few one +ro 1.003 one few few +ro 1.030 one other few +ro 1.031 one other one +ro 1.023 one other few +ro 3.000 few few few +ro 3.001 few one one +ro 3.030 few other few +ro 3.031 few other one +ro 3.023 few other few +ro 21.000 other few few +ro 21.001 other one one +ro 21.110 other few few +ro 21.101 other few one +ro 21.003 other few few +ru 0.0 many many many +ru 0.3 many few few +ru 0.6 many many many +ru 21.0 one many many +ru 21.3 one few few +ru 21.6 one many many +ru 3.0 few many many +ru 3.6 few many many +ru 6.0 many many many +ru 6.3 many few few +ru 0.00 many many many +ru 0.21 many one one +ru 0.03 many few few +ru 0.20 many many many +ru 0.13 many many few +ru 0.06 many many many +ru 21.00 one many many +ru 21.03 one few few +ru 21.20 one many many +ru 21.13 one many few +ru 21.06 one many many +ru 3.00 few many many +ru 3.21 few one one +ru 3.20 few many many +ru 3.13 few many few +ru 3.06 few many many +ru 6.00 many many many +ru 6.21 many one one +ru 6.03 many few few +ru 0.000 many many many +ru 0.021 many one one +ru 0.003 many few few +ru 0.020 many many many +ru 0.111 many many one +ru 0.013 many many few +ru 0.006 many many many +ru 21.000 one many many +ru 21.003 one few few +ru 21.020 one many many +ru 21.111 one many one +ru 21.013 one many few +ru 21.006 one many many +ru 3.000 few many many +ru 3.021 few one one +ru 3.020 few many many +ru 3.111 few many one +ru 3.013 few many few +ru 3.006 few many many +ru 6.000 many many many +ru 6.021 many one one +ru 6.003 many few few +si 0.0 other other other +si 0.2 other other other +si 2.0 other other other +si 0.00 other other other +si 0.20 other other other +si 0.02 other other other +si 2.00 other other other +si 0.000 other other other +si 0.020 other other other +si 0.002 other other other +si 2.000 other other other +sk 0.0 other other other +sk 0.1 other one one +sk 0.3 other few few +sk 0.6 other other other +sk 1.0 one other other +sk 1.3 one few few +sk 1.6 one other other +sk 3.0 few other other +sk 3.1 few one one +sk 3.6 few other other +sk 6.0 other other other +sk 6.1 other one one +sk 6.3 other few few +sk 0.00 other other other +sk 0.01 other one one +sk 0.03 other few few +sk 0.20 other other other +sk 0.21 other other one +sk 0.13 other other few +sk 0.06 other other other +sk 1.00 one other other +sk 1.03 one few few +sk 1.20 one other other +sk 1.21 one other one +sk 1.13 one other few +sk 1.06 one other other +sk 3.00 few other other +sk 3.01 few one one +sk 3.20 few other other +sk 3.21 few other one +sk 3.13 few other few +sk 3.06 few other other +sk 6.00 other other other +sk 6.01 other one one +sk 6.03 other few few +sk 0.000 other other other +sk 0.001 other one one +sk 0.003 other few few +sk 0.020 other other other +sk 0.021 other other one +sk 0.013 other other few +sk 0.006 other other other +sk 1.000 one other other +sk 1.003 one few few +sk 1.020 one other other +sk 1.021 one other one +sk 1.013 one other few +sk 1.006 one other other +sk 3.000 few other other +sk 3.001 few one one +sk 3.020 few other other +sk 3.021 few other one +sk 3.013 few other few +sk 3.006 few other other +sk 6.000 other other other +sk 6.001 other one one +sk 6.003 other few few +sl 0.0 other other other +sl 0.4 other few few +sl 0.6 other other other +sl 101.0 one other other +sl 101.4 one few few +sl 101.6 one other other +sl 102.0 two other other +sl 102.4 two few few +sl 102.6 two other other +sl 4.0 few other other +sl 4.6 few other other +sl 6.0 other other other +sl 6.4 other few few +sl 0.00 other other other +sl 0.04 other few few +sl 0.20 other other other +sl 0.21 other other one +sl 0.22 other other two +sl 0.14 other other few +sl 0.06 other other other +sl 101.00 one other other +sl 101.04 one few few +sl 101.20 one other other +sl 101.21 one other one +sl 101.22 one other two +sl 101.14 one other few +sl 101.06 one other other +sl 102.00 two other other +sl 102.04 two few few +sl 102.20 two other other +sl 102.21 two other one +sl 102.22 two other two +sl 102.14 two other few +sl 102.06 two other other +sl 4.00 few other other +sl 4.20 few other other +sl 4.21 few other one +sl 4.22 few other two +sl 4.14 few other few +sl 4.06 few other other +sl 6.00 other other other +sl 6.04 other few few +sl 0.000 other other other +sl 0.101 other one one +sl 0.102 other two two +sl 0.004 other few few +sl 0.020 other other other +sl 0.021 other other one +sl 0.022 other other two +sl 0.014 other other few +sl 0.006 other other other +sl 101.000 one other other +sl 101.102 one two two +sl 101.004 one few few +sl 101.020 one other other +sl 101.021 one other one +sl 101.022 one other two +sl 101.014 one other few +sl 101.006 one other other +sl 102.000 two other other +sl 102.101 two one one +sl 102.004 two few few +sl 102.020 two other other +sl 102.021 two other one +sl 102.022 two other two +sl 102.014 two other few +sl 102.006 two other other +sl 4.000 few other other +sl 4.101 few one one +sl 4.102 few two two +sl 4.020 few other other +sl 4.021 few other one +sl 4.022 few other two +sl 4.014 few other few +sl 4.006 few other other +sl 6.000 other other other +sl 6.101 other one one +sl 6.102 other two two +sl 6.004 other few few +sr 0.0 many many many +sr 0.3 many few few +sr 0.6 many many many +sr 21.0 one many many +sr 21.3 one few few +sr 21.6 one many many +sr 3.0 few many many +sr 3.6 few many many +sr 6.0 many many many +sr 6.3 many few few +sr 0.00 many many many +sr 0.21 many one one +sr 0.03 many few few +sr 0.20 many many many +sr 0.13 many many few +sr 0.06 many many many +sr 21.00 one many many +sr 21.03 one few few +sr 21.20 one many many +sr 21.13 one many few +sr 21.06 one many many +sr 3.00 few many many +sr 3.21 few one one +sr 3.20 few many many +sr 3.13 few many few +sr 3.06 few many many +sr 6.00 many many many +sr 6.21 many one one +sr 6.03 many few few +sr 0.000 many many many +sr 0.021 many one one +sr 0.003 many few few +sr 0.020 many many many +sr 0.111 many many one +sr 0.013 many many few +sr 0.006 many many many +sr 21.000 one many many +sr 21.003 one few few +sr 21.020 one many many +sr 21.111 one many one +sr 21.013 one many few +sr 21.006 one many many +sr 3.000 few many many +sr 3.021 few one one +sr 3.020 few many many +sr 3.111 few many one +sr 3.013 few many few +sr 3.006 few many many +sr 6.000 many many many +sr 6.021 many one one +sr 6.003 many few few +sv 0.0 other other other +sv 0.1 other one one +sv 0.3 other other other +sv 1.0 one other other +sv 1.3 one other other +sv 3.0 other other other +sv 3.1 other one one +sv 0.00 other other other +sv 0.01 other one one +sv 0.20 other other other +sv 0.21 other other one +sv 0.03 other other other +sv 1.00 one other other +sv 1.20 one other other +sv 1.21 one other one +sv 1.03 one other other +sv 3.00 other other other +sv 3.01 other one one +sv 0.000 other other other +sv 0.001 other one one +sv 0.020 other other other +sv 0.021 other other one +sv 0.003 other other other +sv 1.000 one other other +sv 1.020 one other other +sv 1.021 one other one +sv 1.003 one other other +sv 3.000 other other other +sv 3.001 other one one +sw 0.0 other other other +sw 0.1 other one one +sw 0.3 other other other +sw 1.0 one other other +sw 1.3 one other other +sw 3.0 other other other +sw 3.1 other one one +sw 0.00 other other other +sw 0.01 other one one +sw 0.20 other other other +sw 0.21 other other one +sw 0.03 other other other +sw 1.00 one other other +sw 1.20 one other other +sw 1.21 one other one +sw 1.03 one other other +sw 3.00 other other other +sw 3.01 other one one +sw 0.000 other other other +sw 0.001 other one one +sw 0.020 other other other +sw 0.021 other other one +sw 0.003 other other other +sw 1.000 one other other +sw 1.020 one other other +sw 1.021 one other one +sw 1.003 one other other +sw 3.000 other other other +sw 3.001 other one one +ta 0.0 other other other +ta 0.1 other one one +ta 0.3 other other other +ta 1.0 one other other +ta 1.3 one other other +ta 3.0 other other other +ta 3.1 other one one +ta 0.00 other other other +ta 0.01 other one one +ta 0.20 other other other +ta 0.21 other other one +ta 0.03 other other other +ta 1.00 one other other +ta 1.20 one other other +ta 1.21 one other one +ta 1.03 one other other +ta 3.00 other other other +ta 3.01 other one one +ta 0.000 other other other +ta 0.001 other one one +ta 0.020 other other other +ta 0.021 other other one +ta 0.003 other other other +ta 1.000 one other other +ta 1.020 one other other +ta 1.021 one other one +ta 1.003 one other other +ta 3.000 other other other +ta 3.001 other one one +te 0.0 other other other +te 0.1 other one one +te 0.3 other other other +te 1.0 one other other +te 1.3 one other other +te 3.0 other other other +te 3.1 other one one +te 0.00 other other other +te 0.01 other one one +te 0.20 other other other +te 0.21 other other one +te 0.03 other other other +te 1.00 one other other +te 1.20 one other other +te 1.21 one other one +te 1.03 one other other +te 3.00 other other other +te 3.01 other one one +te 0.000 other other other +te 0.001 other one one +te 0.020 other other other +te 0.021 other other one +te 0.003 other other other +te 1.000 one other other +te 1.020 one other other +te 1.021 one other one +te 1.003 one other other +te 3.000 other other other +te 3.001 other one one +th 0.0 other other other +th 0.2 other other other +th 2.0 other other other +th 0.00 other other other +th 0.20 other other other +th 0.02 other other other +th 2.00 other other other +th 0.000 other other other +th 0.020 other other other +th 0.002 other other other +th 2.000 other other other +tr 0.0 other other other +tr 0.2 other other other +tr 2.0 other other other +tr 0.00 other other other +tr 0.20 other other other +tr 0.02 other other other +tr 2.00 other other other +tr 0.000 other other other +tr 0.020 other other other +tr 0.002 other other other +tr 2.000 other other other +uk 0.0 many many many +uk 0.3 many few few +uk 0.6 many many many +uk 21.0 one many many +uk 21.3 one few few +uk 21.6 one many many +uk 3.0 few many many +uk 3.6 few many many +uk 6.0 many many many +uk 6.3 many few few +uk 0.00 many many many +uk 0.21 many one one +uk 0.03 many few few +uk 0.20 many many many +uk 0.13 many many few +uk 0.06 many many many +uk 21.00 one many many +uk 21.03 one few few +uk 21.20 one many many +uk 21.13 one many few +uk 21.06 one many many +uk 3.00 few many many +uk 3.21 few one one +uk 3.20 few many many +uk 3.13 few many few +uk 3.06 few many many +uk 6.00 many many many +uk 6.21 many one one +uk 6.03 many few few +uk 0.000 many many many +uk 0.021 many one one +uk 0.003 many few few +uk 0.020 many many many +uk 0.111 many many one +uk 0.013 many many few +uk 0.006 many many many +uk 21.000 one many many +uk 21.003 one few few +uk 21.020 one many many +uk 21.111 one many one +uk 21.013 one many few +uk 21.006 one many many +uk 3.000 few many many +uk 3.021 few one one +uk 3.020 few many many +uk 3.111 few many one +uk 3.013 few many few +uk 3.006 few many many +uk 6.000 many many many +uk 6.021 many one one +uk 6.003 many few few +ur 0.0 other other other +ur 0.1 other one one +ur 0.3 other other other +ur 1.0 one other other +ur 1.3 one other other +ur 3.0 other other other +ur 3.1 other one one +ur 0.00 other other other +ur 0.01 other one one +ur 0.20 other other other +ur 0.21 other other one +ur 0.03 other other other +ur 1.00 one other other +ur 1.20 one other other +ur 1.21 one other one +ur 1.03 one other other +ur 3.00 other other other +ur 3.01 other one one +ur 0.000 other other other +ur 0.001 other one one +ur 0.020 other other other +ur 0.021 other other one +ur 0.003 other other other +ur 1.000 one other other +ur 1.020 one other other +ur 1.021 one other one +ur 1.003 one other other +ur 3.000 other other other +ur 3.001 other one one +vi 0.0 other other other +vi 0.2 other other other +vi 2.0 other other other +vi 0.00 other other other +vi 0.20 other other other +vi 0.02 other other other +vi 2.00 other other other +vi 0.000 other other other +vi 0.020 other other other +vi 0.002 other other other +vi 2.000 other other other +zh 0.0 other other other +zh 0.2 other other other +zh 2.0 other other other +zh 0.00 other other other +zh 0.20 other other other +zh 0.02 other other other +zh 2.00 other other other +zh 0.000 other other other +zh 0.020 other other other +zh 0.002 other other other +zh 2.000 other other other +zh_Hant 0.0 other other other +zh_Hant 0.2 other other other +zh_Hant 2.0 other other other +zh_Hant 0.00 other other other +zh_Hant 0.20 other other other +zh_Hant 0.02 other other other +zh_Hant 2.00 other other other +zh_Hant 0.000 other other other +zh_Hant 0.020 other other other +zh_Hant 0.002 other other other +zh_Hant 2.000 other other other diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/CompatibilityTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/CompatibilityTest.java index 584ea57a606..678fddec1b3 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/CompatibilityTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/CompatibilityTest.java @@ -1,6 +1,6 @@ /* ******************************************************************************* - * Copyright (C) 1996-2012, International Business Machines Corporation and * + * Copyright (C) 1996-2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -125,6 +125,32 @@ public class CompatibilityTest extends TestFmwk private static final String[][] SKIP_CASES = { {"ICU_3.8.1", "com.ibm.icu.text.PluralFormat.dat"}, {"ICU_3.8.1", "com.ibm.icu.text.PluralRules.dat"}, + // ICU 52 is not serialization-compatible with previous versions. + {"ICU_3.8.1", "com.ibm.icu.text.PluralFormat.dat"}, + {"ICU_3.8.1", "com.ibm.icu.text.PluralRules.dat"}, + {"ICU_4.0", "com.ibm.icu.text.PluralFormat.dat"}, + {"ICU_4.0", "com.ibm.icu.text.PluralRules.dat"}, + {"ICU_4.2.1", "com.ibm.icu.text.PluralFormat.dat"}, + {"ICU_4.2.1", "com.ibm.icu.text.PluralRules.dat"}, + {"ICU_4.4", "com.ibm.icu.text.PluralFormat.dat"}, + {"ICU_4.4", "com.ibm.icu.text.PluralRules.dat"}, + {"ICU_4.4", "com.ibm.icu.text.CurrencyPluralInfo.dat"}, + {"ICU_4.6", "com.ibm.icu.text.PluralFormat.dat"}, + {"ICU_4.6", "com.ibm.icu.text.PluralRules.dat"}, + {"ICU_4.6", "com.ibm.icu.text.CurrencyPluralInfo.dat"}, + {"ICU_4.8", "com.ibm.icu.text.PluralFormat.dat"}, + {"ICU_4.8", "com.ibm.icu.text.PluralRules.dat"}, + {"ICU_4.8", "com.ibm.icu.text.CurrencyPluralInfo.dat"}, + {"ICU_49.1", "com.ibm.icu.text.CurrencyPluralInfo.dat"}, + {"ICU_49.1", "com.ibm.icu.text.PluralFormat.dat"}, + {"ICU_49.1", "com.ibm.icu.text.PluralRules.dat"}, + {"ICU_50.1", "com.ibm.icu.text.CurrencyPluralInfo.dat"}, + {"ICU_50.1", "com.ibm.icu.text.PluralFormat.dat"}, + {"ICU_50.1", "com.ibm.icu.text.PluralRules.dat"}, + {"ICU_51.1", "com.ibm.icu.text.CurrencyPluralInfo.dat"}, + {"ICU_51.1", "com.ibm.icu.text.PluralFormat.dat"}, + {"ICU_51.1", "com.ibm.icu.text.PluralRules.dat"}, + {"ICU_3.6", "com.ibm.icu.text.RuleBasedNumberFormat.dat"}, {"ICU_3.8.1", "com.ibm.icu.text.RuleBasedNumberFormat.dat"}, {"ICU_4.0", "com.ibm.icu.text.RuleBasedNumberFormat.dat"}, diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/FormatTests.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/FormatTests.java index 73f84cc7afa..97b9e8ea3e7 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/FormatTests.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/FormatTests.java @@ -1,6 +1,6 @@ /* ******************************************************************************* - * Copyright (c) 2004-2012, International Business Machines + * Copyright (c) 2004-2013, International Business Machines * Corporation and others. All Rights Reserved. ******************************************************************************* * @@ -2192,6 +2192,19 @@ public class FormatTests return a.equals(b); } } + + public static class PluralRulesSerialProxyHandler implements SerializableTest.Handler { + // Tested through PluralRules, so just a stub here to keep CoverageTest happy + final String[] cannedRules = {}; + + public Object[] getTestObjects() { + return new PluralRules[cannedRules.length]; + } + public boolean hasSameBehavior(Object a, Object b) { + return a.equals(b); + } + } + public static class TimeUnitFormatHandler implements SerializableTest.Handler { diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/SerializableTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/SerializableTest.java index e8c52dd229b..b334237d83c 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/SerializableTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/SerializableTest.java @@ -1,6 +1,6 @@ /* ******************************************************************************* - * Copyright (C) 1996-2012, International Business Machines Corporation and * + * Copyright (C) 1996-2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -672,6 +672,7 @@ public class SerializableTest extends TestFmwk.TestGroup map.put("com.ibm.icu.impl.DateNumberFormat", new FormatTests.DateNumberFormatHandler()); map.put("com.ibm.icu.text.PluralFormat", new FormatTests.PluralFormatHandler()); map.put("com.ibm.icu.text.PluralRules", new FormatTests.PluralRulesHandler()); + map.put("com.ibm.icu.text.PluralRulesSerialProxy", new FormatTests.PluralRulesSerialProxyHandler()); map.put("com.ibm.icu.text.TimeUnitFormat", new FormatTests.TimeUnitFormatHandler()); map.put("com.ibm.icu.text.SelectFormat", new FormatTests.SelectFormatHandler()); map.put("com.ibm.icu.impl.TimeZoneNamesImpl", new FormatTests.TimeZoneNamesHandler());