Home | History | Annotate | Download | only in tool
      1 package org.unicode.cldr.tool;
      2 
      3 import java.io.IOException;
      4 import java.io.PrintWriter;
      5 import java.util.Comparator;
      6 import java.util.EnumMap;
      7 import java.util.HashMap;
      8 import java.util.HashSet;
      9 import java.util.LinkedHashSet;
     10 import java.util.List;
     11 import java.util.Map;
     12 import java.util.Objects;
     13 import java.util.Set;
     14 import java.util.TreeMap;
     15 import java.util.TreeSet;
     16 
     17 import org.unicode.cldr.draft.FileUtilities;
     18 import org.unicode.cldr.util.Builder;
     19 import org.unicode.cldr.util.Builder.CBuilder;
     20 import org.unicode.cldr.util.CLDRConfig;
     21 import org.unicode.cldr.util.CLDRFile;
     22 import org.unicode.cldr.util.CLDRFile.Status;
     23 import org.unicode.cldr.util.CLDRPaths;
     24 import org.unicode.cldr.util.Counter;
     25 import org.unicode.cldr.util.CoverageInfo;
     26 import org.unicode.cldr.util.DtdType;
     27 import org.unicode.cldr.util.Factory;
     28 import org.unicode.cldr.util.LanguageTagParser;
     29 import org.unicode.cldr.util.Level;
     30 import org.unicode.cldr.util.SupplementalDataInfo;
     31 import org.unicode.cldr.util.SupplementalDataInfo.PluralType;
     32 import org.unicode.cldr.util.XPathParts;
     33 
     34 import com.ibm.icu.impl.Relation;
     35 import com.ibm.icu.impl.Row;
     36 import com.ibm.icu.impl.Row.R2;
     37 import com.ibm.icu.impl.Row.R3;
     38 import com.ibm.icu.impl.Row.R5;
     39 import com.ibm.icu.text.NumberFormat;
     40 import com.ibm.icu.text.Transform;
     41 
     42 public class GenerateCoverageLevels {
     43     // see ShowLocaleCoverage.java
     44     private static boolean SKIP_UNCONFIRMED = true;
     45     private static int SHOW_EXAMPLES = 5;
     46     private static final String FILES = ".*";
     47     private static final String MAIN_DIRECTORY = CLDRPaths.MAIN_DIRECTORY;// CldrUtility.SUPPLEMENTAL_DIRECTORY;
     48     // //CldrUtility.MAIN_DIRECTORY;
     49     private static final String COLLATION_DIRECTORY = CLDRPaths.COMMON_DIRECTORY + "/collation/";// CldrUtility.SUPPLEMENTAL_DIRECTORY;
     50     // //CldrUtility.MAIN_DIRECTORY;
     51     private static final String RBNF_DIRECTORY = CLDRPaths.COMMON_DIRECTORY + "/rbnf/";// CldrUtility.SUPPLEMENTAL_DIRECTORY;
     52     // //CldrUtility.MAIN_DIRECTORY;
     53     private static final String OUT_DIRECTORY = CLDRPaths.GEN_DIRECTORY + "/coverage/"; // CldrUtility.MAIN_DIRECTORY;
     54     private static final Factory cldrFactory = Factory.make(MAIN_DIRECTORY, FILES);
     55     private static final Comparator<String> attributeComparator = CLDRFile.getAttributeOrdering();
     56     private static final CLDRFile english = cldrFactory.make("en", true);
     57     private static SupplementalDataInfo supplementalData = CLDRConfig.getInstance().getSupplementalDataInfo();
     58     // SupplementalDataInfo.getInstance(english.getSupplementalDirectory());
     59     private static Set<String> defaultContents = supplementalData.getDefaultContentLocales();
     60     private static Map<String, R2<List<String>, String>> languageAliasInfo = supplementalData.getLocaleAliasInfo().get(
     61         "language");
     62     private static LocaleFilter localeFilter = new LocaleFilter(true);
     63     private static BooleanLocaleFilter nonAliasLocaleFilter = new BooleanLocaleFilter();
     64 
     65     private static final long COLLATION_WEIGHT = 50;
     66     private static final Level COLLATION_LEVEL = Level.POSIX;
     67     private static final long PLURALS_WEIGHT = 20;
     68     private static final Level PLURALS_LEVEL = Level.MINIMAL;
     69     private static final long RBNF_WEIGHT = 20;
     70     private static final Level RBNF_LEVEL = Level.MODERATE;
     71 
     72     static int totalCount = 0;
     73 
     74     enum Inheritance {
     75         actual, inherited
     76     }
     77 
     78     public static void main(String[] args) throws IOException {
     79         if (true) {
     80             throw new IllegalArgumentException("See ShowLocaleCoverage (TODO: merge these).");
     81         }
     82         PrintWriter out = FileUtilities.openUTF8Writer(OUT_DIRECTORY, "fullpaths.txt");
     83         showEnglish(out);
     84         out.close();
     85 
     86         System.out.println("*** TODO check collations, RBNF, Transforms (if non-Latin)");
     87         PrintWriter summary = FileUtilities.openUTF8Writer(OUT_DIRECTORY, "summary.txt");
     88         PrintWriter samples = FileUtilities.openUTF8Writer(OUT_DIRECTORY, "samples.txt");
     89         PrintWriter counts = FileUtilities.openUTF8Writer(OUT_DIRECTORY, "counts.txt");
     90         summarizeCoverage(summary, samples, counts);
     91         summary.close();
     92         samples.close();
     93         counts.close();
     94     }
     95 
     96     private static void showEnglish(PrintWriter out) throws IOException {
     97         CLDRFile cldrFile = english;
     98         String locale = "en";
     99         Set<String> sorted = Builder.with(new TreeSet<String>()).addAll(cldrFile.iterator())
    100             .addAll(cldrFile.getExtraPaths()).get();
    101         Set<R3<Level, String, Inheritance>> items = new TreeSet<R3<Level, String, Inheritance>>(new RowComparator());
    102         for (String path : sorted) {
    103             if (path.endsWith("/alias")) {
    104                 continue;
    105             }
    106             String source = cldrFile.getSourceLocaleID(path, null);
    107             Inheritance inherited = !source.equals(locale) ? Inheritance.inherited : Inheritance.actual;
    108 
    109 //            Level level = supplementalData.getCoverageLevel(path, locale);
    110             Level level = CLDRConfig.getInstance().getCoverageInfo().getCoverageLevel(path, locale);
    111 
    112             items.add(Row.of(level, path, inherited));
    113         }
    114 
    115         PathStore store = new PathStore();
    116         for (R3<Level, String, Inheritance> item : items) {
    117             show(out, cldrFile, item, store);
    118         }
    119         show(out, cldrFile, null, store);
    120     }
    121 
    122     private static class RowComparator implements Comparator<R3<Level, String, Inheritance>> {
    123 
    124         public int compare(R3<Level, String, Inheritance> o1, R3<Level, String, Inheritance> o2) {
    125             int result = o1.get0().compareTo(o2.get0());
    126             if (result != 0) return result;
    127             result = CLDRFile.getComparator(DtdType.ldml).compare(o1.get1(), o2.get1());
    128             if (result != 0) return result;
    129             result = o1.get2().compareTo(o2.get2());
    130             return result;
    131         }
    132     }
    133 
    134     private static void show(PrintWriter out, CLDRFile cldrFile, R3<Level, String, Inheritance> next, PathStore store) {
    135         R5<Level, Inheritance, Integer, String, TreeMap<String, Relation<String, String>>> results = store.add(next);
    136         if (results != null) {
    137             Level lastLevel = results.get0();
    138             int count = results.get2();
    139             String path = results.get3();
    140             totalCount += count;
    141             try {
    142                 StringBuilder resultString = new StringBuilder();
    143                 TreeMap<String, Relation<String, String>> types = results.get4();
    144                 for (String key : types.keySet()) {
    145                     Relation<String, String> attr_values = types.get(key);
    146                     for (String attr : attr_values.keySet()) {
    147                         resultString.append("\t").append(key + ":\u200b" + attr).append("=\u200b")
    148                             .append(attr_values.getAll(attr));
    149                     }
    150                 }
    151                 out.println(lastLevel.ordinal()
    152                     + "\t" + lastLevel
    153                     + "\t" + count
    154                     + "\t" + totalCount
    155                     + "\t" + path + resultString);
    156             } catch (RuntimeException e) {
    157                 throw e;
    158             }
    159         }
    160     }
    161 
    162     static class PathStore {
    163         XPathParts lastParts = new XPathParts();
    164         XPathParts nextParts = new XPathParts();
    165         Level lastLevel;
    166         Inheritance lastInheritance;
    167         int count = 0;
    168 
    169         TreeMap<String, Relation<String, String>> differences = new TreeMap<String, Relation<String, String>>();
    170 
    171         R5<Level, Inheritance, Integer, String, TreeMap<String, Relation<String, String>>> add(
    172             R3<Level, String, Inheritance> next) {
    173             count++;
    174             boolean wasNull = lastLevel == null;
    175             Level level = null;
    176             String path = null;
    177             Inheritance inherited = null;
    178 
    179             if (next != null) {
    180                 level = next.get0();
    181                 path = next.get1();
    182                 inherited = next.get2();
    183 
    184                 setParts(nextParts, path);
    185                 if (sameElements()) {
    186                     addDifferences();
    187                     return null;
    188                 }
    189             }
    190             // clear the values
    191             clean(lastParts, differences);
    192             R5<Level, Inheritance, Integer, String, TreeMap<String, Relation<String, String>>> results = Row.of(
    193                 lastLevel, lastInheritance, count - 1, lastParts.toString().replace("/", "\u200B/"), differences);
    194             lastParts = nextParts;
    195             differences = new TreeMap<String, Relation<String, String>>();
    196             nextParts = new XPathParts();
    197             lastLevel = level;
    198             lastInheritance = inherited;
    199             count = 1;
    200             if (wasNull) return null;
    201             return results;
    202         }
    203 
    204         private void clean(XPathParts lastParts2, TreeMap<String, Relation<String, String>> differences2) {
    205             for (int i = 0; i < lastParts.size(); ++i) {
    206                 String element = lastParts.getElement(i);
    207                 Relation<String, String> attr_values = differences2.get(element);
    208                 if (attr_values == null) continue;
    209                 for (String attr : attr_values.keySet()) {
    210                     lastParts.putAttributeValue(i, attr, "*");
    211                 }
    212             }
    213         }
    214 
    215         private void setParts(XPathParts parts, String path) {
    216             parts.set(path);
    217             if (path.startsWith("//ldml/dates/timeZoneNames/metazone")
    218                 || path.startsWith("//ldml/dates/timeZoneNames/zone")) {
    219                 String element = nextParts.getElement(-1);
    220                 nextParts.setElement(-1, "zoneChoice");
    221                 nextParts.putAttributeValue(-1, "type", element);
    222                 element = nextParts.getElement(-2);
    223                 nextParts.setElement(-2, "zoneLength");
    224                 nextParts.putAttributeValue(-2, "type", element);
    225             } else if (path.startsWith("//ldml/dates/calendars/calendar")) {
    226                 if (!"gregorian".equals(parts.getAttributeValue(3, "type"))) {
    227                     for (int i = parts.size() - 1; i > 3; --i) {
    228                         parts.removeElement(i);
    229                     }
    230                     parts.addElement("*");
    231                 }
    232             }
    233         }
    234 
    235         private void addDifferences() {
    236             for (int i = 0; i < lastParts.size(); ++i) {
    237                 Map<String, String> lastAttrs = lastParts.getAttributes(i);
    238                 Map<String, String> nextAttrs = nextParts.getAttributes(i);
    239                 if (!lastAttrs.equals(nextAttrs)) {
    240                     String element = lastParts.getElement(i);
    241                     Relation<String, String> old = differences.get(element);
    242                     if (old == null) {
    243                         old = Relation.of(new TreeMap<String, Set<String>>(attributeComparator), TreeSet.class);
    244                         differences.put(element, old);
    245                     }
    246                     Set<String> union = Builder.with(new TreeSet<String>()).addAll(lastAttrs.keySet())
    247                         .addAll(nextAttrs.keySet()).get();
    248                     for (String key : union) {
    249                         String lastValue = lastAttrs.get(key);
    250                         String nextValue = nextAttrs.get(key);
    251                         if (!Objects.equals(lastValue, nextValue)) {
    252                             if (lastValue != null) old.put(key, lastValue);
    253                             if (nextValue != null) old.put(key, nextValue);
    254                         }
    255                     }
    256                 }
    257             }
    258         }
    259 
    260         private boolean sameElements() {
    261             if (lastParts.size() != nextParts.size()) return false;
    262             for (int i = 0; i < lastParts.size(); ++i) {
    263                 if (!lastParts.getElement(i).equals(nextParts.getElement(i))) return false;
    264             }
    265             return true;
    266         }
    267 
    268     }
    269 
    270     private static void summarizeCoverage(PrintWriter summary, PrintWriter samples2, PrintWriter counts) {
    271         final Factory cldrFactory = Factory.make(MAIN_DIRECTORY, FILES);
    272         final Factory collationFactory = Factory.make(COLLATION_DIRECTORY, FILES);
    273         final Factory rbnfFactory = Factory.make(RBNF_DIRECTORY, FILES);
    274 
    275         // CLDRFile sd = CLDRFile.make(CLDRFile.SUPPLEMENTAL_NAME, CldrUtility.SUPPLEMENTAL_DIRECTORY, true);
    276         // CLDRFile smd = CLDRFile.make(CLDRFile.SUPPLEMENTAL_METADATA, CldrUtility.SUPPLEMENTAL_DIRECTORY, true);
    277         //
    278         // CoverageLevel.init(sd, smd);
    279 
    280         NumberFormat percent = NumberFormat.getPercentInstance();
    281         NumberFormat decimal = NumberFormat.getInstance();
    282         decimal.setGroupingUsed(true);
    283         decimal.setMaximumFractionDigits(2);
    284         percent.setMaximumFractionDigits(2);
    285         NumberFormat integer = NumberFormat.getIntegerInstance();
    286         Set<String> localesFound = new TreeSet<String>();
    287 
    288         // get list of locales
    289         LocaleLevelData mapLevelData = new LocaleLevelData();
    290         TreeSet<String> mainAvailableSource = new TreeSet<String>(cldrFactory.getAvailable());
    291         TreeSet<String> mainAvailable = new TreeSet<String>();
    292         Relation<String, String> localeToVariants = Relation.of(new HashMap(), HashSet.class);
    293         for (String locale : mainAvailableSource) {
    294             if (localeFilter.skipLocale(locale, localeToVariants)) {
    295                 continue;
    296             }
    297             mainAvailable.add(locale);
    298         }
    299 
    300         System.out.println("gathering rbnf data");
    301         Set<String> ordinals = new TreeSet<String>();
    302         Set<String> spellout = new TreeSet<String>();
    303         localesFound.clear();
    304         for (String locale : rbnfFactory.getAvailable()) {
    305             if (localeFilter.skipLocale(locale, null)) continue;
    306             System.out.println(locale + "\t" + english.getName(locale));
    307             getRBNFData(locale, rbnfFactory.make(locale, true), ordinals, spellout, localesFound);
    308         }
    309         markData("RBNF-Ordinals", ordinals, mapLevelData, mainAvailable, RBNF_LEVEL, RBNF_WEIGHT,
    310             Row.of("//ldml/rbnf/ordinals", "?"));
    311         markData("RBNF-Spellout", spellout, mapLevelData, mainAvailable, RBNF_LEVEL, RBNF_WEIGHT,
    312             Row.of("//ldml/rbnf/spellout", "?"));
    313         if (localesFound.size() != 0) {
    314             System.out.println("Other rbnf found:\t" + localesFound);
    315         }
    316 
    317         System.out.println("gathering plural data");
    318         localesFound = new TreeSet<String>(supplementalData.getPluralLocales(PluralType.cardinal));
    319         markData("Plurals", localesFound, mapLevelData, mainAvailable, PLURALS_LEVEL, PLURALS_WEIGHT,
    320             Row.of("//supplementalData/plurals", "UCA"));
    321 
    322         System.out.println("gathering collation data");
    323         localesFound.clear();
    324         for (String locale : collationFactory.getAvailable()) {
    325             if (localeFilter.skipLocale(locale, null)) continue;
    326             System.out.println(locale + "\t" + english.getName(locale));
    327             getCollationData(locale, collationFactory.make(locale, true), localesFound);
    328         }
    329         markData("Collation", localesFound, mapLevelData, mainAvailable, COLLATION_LEVEL, COLLATION_WEIGHT,
    330             Row.of("//ldml/collations", "UCA"));
    331 
    332         System.out.println("gathering main data");
    333         for (String locale : mainAvailable) {
    334             System.out.println(locale + "\t" + english.getName(locale));
    335             LevelData levelData = mapLevelData.get(locale);
    336             getMainData(locale, levelData, cldrFactory.make(locale, true));
    337         }
    338 
    339         System.out.println("printing data");
    340         String summaryLineHeader = "Code\tName\tWeighted Missing:\tFound:\tScore:";
    341         summary.println(summaryLineHeader);
    342         LanguageTagParser languageTagParser = new LanguageTagParser();
    343 
    344         StringBuilder header = new StringBuilder();
    345         //EnumSet<Level> skipLevels = EnumSet.of(Level.CORE, Level.POSIX, Level.COMPREHENSIVE, Level.OPTIONAL);
    346         for (String locale : mapLevelData.keySet()) {
    347             LevelData levelData = mapLevelData.get(locale);
    348             String max = LikelySubtags.maximize(locale, supplementalData.getLikelySubtags());
    349             String lang = languageTagParser.set(max).getLanguage();
    350             String script = languageTagParser.set(max).getScript();
    351 
    352             Counter<Level> missing = levelData.missing;
    353             Counter<Level> found = levelData.found;
    354             Relation<Level, R2<String, String>> samples = levelData.samples;
    355             StringBuilder countLine = new StringBuilder(
    356                 script
    357                     + "\t" + english.getName(CLDRFile.SCRIPT_NAME, script)
    358                     + "\t" + lang
    359                     + "\t" + english.getName(CLDRFile.LANGUAGE_NAME, lang));
    360             if (header != null) {
    361                 header.append("Code\tScript\tCode\tLocale");
    362             }
    363             // Now print the information
    364             samples2.println();
    365             samples2.println(locale + "\t" + english.getName(locale));
    366             double weightedFound = 0;
    367             double weightedMissing = 0;
    368             long missingCountTotal = 0;
    369             long foundCountTotal = 0;
    370 
    371             for (Level level : Level.values()) {
    372                 if (level == Level.UNDETERMINED) {
    373                     continue;
    374                 }
    375                 long missingCount = missing.get(level);
    376                 missingCountTotal += missingCount;
    377                 long foundCount = found.get(level);
    378                 foundCountTotal += foundCount;
    379                 weightedFound += foundCount * level.getValue();
    380                 weightedMissing += missingCount * level.getValue();
    381 
    382                 countLine.append('\t').append(missingCountTotal).append('\t').append(foundCountTotal);
    383                 if (header != null) {
    384                     header.append("\t" + level + "-Missing\tFound");
    385                 }
    386 
    387                 samples2.println(level + "\tMissing:\t" + integer.format(missingCount) + "\tFound:\t"
    388                     + integer.format(foundCount)
    389                     + "\tScore:\t" + percent.format(foundCount / (double) (foundCount + missingCount))
    390                     + "\tLevel-Value:\t" + level.getValue());
    391                 Set<R2<String, String>> samplesAlready = samples.getAll(level);
    392                 if (samplesAlready != null) {
    393                     for (R2<String, String> row : samplesAlready) {
    394                         samples2.println("\t" + row);
    395                     }
    396                     if (samplesAlready.size() >= SHOW_EXAMPLES) {
    397                         samples2.println("\t...");
    398                     }
    399                 }
    400             }
    401             int base = Level.POSIX.getValue();
    402             double foundCount = weightedFound / base;
    403             double missingCount = weightedMissing / base;
    404             String summaryLine = "Weighted Missing:\t" + decimal.format(missingCount) + "\tFound:\t"
    405                 + decimal.format(foundCount) + "\tScore:\t"
    406                 + percent.format(foundCount / (foundCount + missingCount));
    407             String summaryLine2 = "\t" + decimal.format(missingCount) + "\t" + decimal.format(foundCount) + "\t"
    408                 + percent.format(foundCount / (foundCount + missingCount));
    409             samples2.println(summaryLine);
    410             summary.println(locale + "\t" + english.getName(locale) + "\t" + summaryLine2);
    411             if (header != null) {
    412                 counts.println(header);
    413                 header = null;
    414             }
    415             counts.println(countLine);
    416         }
    417     }
    418 
    419     private static void getRBNFData(String locale, CLDRFile cldrFile, Set<String> ordinals, Set<String> spellout,
    420         Set<String> others) {
    421         XPathParts parts = new XPathParts();
    422         for (String path : cldrFile) {
    423             if (path.endsWith("/alias")) {
    424                 continue;
    425             }
    426             if (!path.contains("rulesetGrouping")) {
    427                 continue;
    428             }
    429             if (skipUnconfirmed(path)) {
    430                 continue;
    431             }
    432             parts.set(path);
    433             String ruleSetGrouping = parts.getAttributeValue(2, "type");
    434             if (ruleSetGrouping.equals("SpelloutRules")) {
    435                 spellout.add(locale);
    436             } else if (ruleSetGrouping.equals("OrdinalRules")) {
    437                 ordinals.add(locale);
    438             } else {
    439                 others.add(ruleSetGrouping);
    440             }
    441         }
    442     }
    443 
    444     private static void markData(String title, Set<String> localesFound, LocaleLevelData mapLevelData,
    445         TreeSet<String> mainAvailable, Level level, long weight, R2<String, String> samples) {
    446         if (!mainAvailable.containsAll(localesFound)) {
    447             final CBuilder<String, TreeSet<String>> cb = Builder.with(new TreeSet<String>());
    448             System.out.println(title + " Locales that are not in main: " + cb
    449                 .addAll(localesFound)
    450                 .removeAll(mainAvailable)
    451                 .filter(nonAliasLocaleFilter).get());
    452         }
    453         for (String locale : mainAvailable) {
    454             if (localesFound.contains(locale)) {
    455                 mapLevelData.get(locale).found.add(level, weight);
    456             } else {
    457                 System.out.println(locale + "\t" + english.getName(locale) + "\t" + "missing " + title);
    458                 mapLevelData.get(locale).missing.add(level, weight);
    459                 mapLevelData.get(locale).samples.put(level, samples);
    460             }
    461         }
    462     }
    463 
    464     enum LocaleStatus {
    465         BASE, ALIAS, VARIANT, DEFAULT_CONTENTS
    466     }
    467 
    468     private static class LocaleFilter implements Transform<String, LocaleStatus> {
    469         private final LanguageTagParser ltp = new LanguageTagParser();
    470         private final boolean checkAliases;
    471 
    472         public LocaleFilter(boolean checkAliases) {
    473             this.checkAliases = checkAliases;
    474         }
    475 
    476         private boolean skipLocale(String locale, Relation<String, String> localeToVariants) {
    477             LocaleStatus result = transform(locale);
    478             if (localeToVariants != null) {
    479                 localeToVariants.put(ltp.getLanguageScript(), ltp.getRegion());
    480             }
    481             return result != LocaleStatus.BASE;
    482         }
    483 
    484         public LocaleStatus transform(String locale) {
    485             ltp.set(locale);
    486             if (checkAliases) {
    487                 String language = ltp.getLanguage();
    488                 if (languageAliasInfo.get(language) != null) {
    489                     return LocaleStatus.ALIAS;
    490                 }
    491             }
    492             if (ltp.getRegion().length() != 0 || !ltp.getVariants().isEmpty()) {
    493                 // skip country locales, variants
    494                 return LocaleStatus.VARIANT;
    495             }
    496             if (defaultContents.contains(locale)) {
    497                 return LocaleStatus.DEFAULT_CONTENTS;
    498             }
    499             return LocaleStatus.BASE;
    500         }
    501     }
    502 
    503     private static class BooleanLocaleFilter implements Transform<String, Boolean> {
    504         private final LocaleFilter filter = new LocaleFilter(false);
    505 
    506         public Boolean transform(String locale) {
    507             return filter.transform(locale) == LocaleStatus.BASE ? Boolean.TRUE : Boolean.FALSE;
    508         }
    509     }
    510 
    511     private static void getCollationData(String locale, CLDRFile cldrFile, Set<String> localesFound) {
    512         XPathParts parts = new XPathParts();
    513         for (String path : cldrFile) {
    514             if (path.endsWith("/alias")) {
    515                 continue;
    516             }
    517             if (!path.contains("collations")) {
    518                 continue;
    519             }
    520             if (skipUnconfirmed(path)) {
    521                 continue;
    522             }
    523             localesFound.add(locale);
    524 
    525             String fullPath = cldrFile.getFullXPath(path);
    526             if (fullPath == null) fullPath = path;
    527             try {
    528                 parts.set(fullPath);
    529             } catch (RuntimeException e) {
    530                 throw e;
    531             }
    532             String validSubLocales = parts.getAttributeValue(1, "validSubLocales");
    533             if (validSubLocales != null) {
    534                 String[] sublocales = validSubLocales.split("\\s+");
    535                 for (String sublocale : sublocales) {
    536                     if (localeFilter.skipLocale(locale, null)) continue;
    537                     localesFound.add(sublocale);
    538                 }
    539             }
    540             break;
    541         }
    542     }
    543 
    544     public static boolean skipUnconfirmed(String path) {
    545         return SKIP_UNCONFIRMED && (path.contains("unconfirmed") || path.contains("provisional"));
    546     }
    547 
    548     private static void getMainData(String locale, LevelData levelData, CLDRFile cldrFile) {
    549         Status status = new Status();
    550         Set<String> sorted = Builder.with(new TreeSet<String>()).addAll(cldrFile.iterator())
    551             .addAll(cldrFile.getExtraPaths()).get();
    552         CoverageInfo coverageInfo = CLDRConfig.getInstance().getCoverageInfo();
    553         for (String path : sorted) {
    554             if (path.endsWith("/alias")) {
    555                 continue;
    556             }
    557 
    558             String fullPath = cldrFile.getFullXPath(path);
    559             String source = cldrFile.getSourceLocaleID(path, status);
    560             Inheritance inherited = !source.equals(locale) || skipUnconfirmed(path)
    561                 ? Inheritance.inherited
    562                 : Inheritance.actual;
    563 
    564 //            Level level = sdi.getCoverageLevel(fullPath, locale);
    565             Level level = coverageInfo.getCoverageLevel(fullPath, locale);
    566             if (inherited == Inheritance.actual) {
    567                 levelData.found.add(level, 1);
    568             } else {
    569                 levelData.missing.add(level, 1);
    570                 if (SHOW_EXAMPLES > 0) {
    571                     Set<R2<String, String>> samplesAlready = levelData.samples.getAll(level);
    572                     if (samplesAlready == null || samplesAlready.size() < SHOW_EXAMPLES) {
    573                         levelData.samples.put(level, Row.of(path, cldrFile.getStringValue(path)));
    574                     }
    575                 }
    576             }
    577         }
    578     }
    579 
    580     static class LevelData {
    581         Counter<Level> missing = new Counter<Level>();
    582         Relation<Level, R2<String, String>> samples = Relation.of(new EnumMap<Level, Set<R2<String, String>>>(
    583             Level.class), LinkedHashSet.class);
    584         Counter<Level> found = new Counter<Level>();
    585     }
    586 
    587     static class LocaleLevelData {
    588         Map<String, LevelData> locale_levelData = new TreeMap<String, LevelData>();
    589 
    590         public LevelData get(String locale) {
    591             if (locale.equals("zh_Hans") || locale.equals("iw")) {
    592                 throw new IllegalArgumentException();
    593             }
    594             LevelData result = locale_levelData.get(locale);
    595             if (result == null) {
    596                 locale_levelData.put(locale, result = new LevelData());
    597             }
    598             return result;
    599         }
    600 
    601         public Set<String> keySet() {
    602             return locale_levelData.keySet();
    603         }
    604     }
    605 
    606 }
    607