• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  ******************************************************************************
3  * Copyright (C) 2004-2013, International Business Machines Corporation and   *
4  * others. All Rights Reserved.                                               *
5  ******************************************************************************
6  */
7 package org.unicode.cldr.tool;
8 
9 import java.io.BufferedReader;
10 import java.io.File;
11 import java.io.IOException;
12 import java.io.PrintWriter;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Collection;
16 import java.util.Comparator;
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.Iterator;
20 import java.util.LinkedHashMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Map.Entry;
24 import java.util.Set;
25 import java.util.TreeMap;
26 import java.util.TreeSet;
27 import java.util.regex.Matcher;
28 import java.util.regex.Pattern;
29 
30 import org.unicode.cldr.draft.FileUtilities;
31 import org.unicode.cldr.util.CLDRConfig;
32 import org.unicode.cldr.util.CLDRFile;
33 import org.unicode.cldr.util.CLDRPaths;
34 import org.unicode.cldr.util.CldrUtility;
35 import org.unicode.cldr.util.Factory;
36 import org.unicode.cldr.util.Iso639Data;
37 import org.unicode.cldr.util.IsoCurrencyParser;
38 import org.unicode.cldr.util.IsoCurrencyParser.Data;
39 import org.unicode.cldr.util.IsoRegionData;
40 import org.unicode.cldr.util.Level;
41 import org.unicode.cldr.util.Log;
42 import org.unicode.cldr.util.Organization;
43 import org.unicode.cldr.util.Pair;
44 import org.unicode.cldr.util.PatternCache;
45 import org.unicode.cldr.util.StandardCodes;
46 import org.unicode.cldr.util.SupplementalDataInfo;
47 import org.unicode.cldr.util.Tabber;
48 import org.unicode.cldr.util.TimezoneFormatter;
49 import org.unicode.cldr.util.UnicodeSetPrettyPrinter;
50 import org.unicode.cldr.util.XPathParts;
51 import org.unicode.cldr.util.props.ICUPropertyFactory;
52 
53 import com.ibm.icu.dev.util.CollectionUtilities;
54 import com.ibm.icu.dev.util.UnicodeMap;
55 import com.ibm.icu.dev.util.UnicodeMapIterator;
56 import com.ibm.icu.impl.Relation;
57 import com.ibm.icu.impl.Row;
58 import com.ibm.icu.impl.Row.R2;
59 import com.ibm.icu.impl.Row.R3;
60 import com.ibm.icu.text.Collator;
61 import com.ibm.icu.text.NumberFormat;
62 import com.ibm.icu.text.RuleBasedCollator;
63 import com.ibm.icu.text.Transform;
64 import com.ibm.icu.text.UnicodeSet;
65 import com.ibm.icu.util.ULocale;
66 
67 /**
68  * Simple program to count the amount of data in CLDR. Internal Use.
69  */
70 public class CountItems {
71 
72     private static final Collator ROOT_PRIMARY_COLLATOR = Collator.getInstance(ULocale.ROOT)
73         .setStrength2(Collator.PRIMARY);
74 
75     static final String needsTranslationString = "America/Buenos_Aires " // America/Rio_Branco
76         + " America/Manaus America/Belem "
77         + " America/Campo_Grande America/Sao_Paulo "
78         + " Australia/Perth Australia/Darwin Australia/Brisbane Australia/Adelaide Australia/Sydney Australia/Hobart "
79         + " America/Vancouver America/Edmonton America/Regina America/Winnipeg America/Toronto America/Halifax America/St_Johns "
80         + " Asia/Jakarta "
81         + " America/Tijuana America/Hermosillo America/Chihuahua America/Mexico_City "
82         + " Europe/Moscow Europe/Kaliningrad Europe/Moscow Asia/Yekaterinburg Asia/Novosibirsk Asia/Yakutsk Asia/Vladivostok"
83         + " Pacific/Honolulu America/Indiana/Indianapolis America/Anchorage "
84         + " America/Los_Angeles America/Phoenix America/Denver America/Chicago America/Indianapolis"
85         + " America/New_York";
86 
87     static final Map<String, String> country_map = CollectionUtilities.asMap(new String[][] {
88         { "AQ", "http://www.worldtimezone.com/time-antarctica24.php" },
89         { "AR", "http://www.worldtimezone.com/time-south-america24.php" },
90         { "AU", "http://www.worldtimezone.com/time-australia24.php" },
91         { "BR", "http://www.worldtimezone.com/time-south-america24.php" },
92         { "CA", "http://www.worldtimezone.com/time-canada24.php" },
93         { "CD", "http://www.worldtimezone.com/time-africa24.php" },
94         { "CL", "http://www.worldtimezone.com/time-south-america24.php" },
95         { "CN", "http://www.worldtimezone.com/time-cis24.php" },
96         { "EC", "http://www.worldtimezone.com/time-south-america24.php" },
97         { "ES", "http://www.worldtimezone.com/time-europe24.php" },
98         { "FM", "http://www.worldtimezone.com/time-oceania24.php" },
99         { "GL", "http://www.worldtimezone.com/index24.php" },
100         { "ID", "http://www.worldtimezone.com/time-asia24.php" },
101         { "KI", "http://www.worldtimezone.com/time-oceania24.php" },
102         { "KZ", "http://www.worldtimezone.com/time-cis24.php" },
103         { "MH", "http://www.worldtimezone.com/time-oceania24.php" },
104         { "MN", "http://www.worldtimezone.com/time-cis24.php" },
105         { "MX", "http://www.worldtimezone.com/index24.php" },
106         { "MY", "http://www.worldtimezone.com/time-asia24.php" },
107         { "NZ", "http://www.worldtimezone.com/time-oceania24.php" },
108         { "PF", "http://www.worldtimezone.com/time-oceania24.php" },
109         { "PT", "http://www.worldtimezone.com/time-europe24.php" },
110         { "RU", "http://www.worldtimezone.com/time-russia24.php" },
111         { "SJ", "http://www.worldtimezone.com/index24.php" },
112         { "UA", "http://www.worldtimezone.com/time-cis24.php" },
113         { "UM", "http://www.worldtimezone.com/time-oceania24.php" },
114         { "US", "http://www.worldtimezone.com/time-usa24.php" },
115         { "UZ", "http://www.worldtimezone.com/time-cis24.php" }, });
116 
117     /**
118      * Count the data.
119      *
120      * @throws IOException
121      */
main(String[] args)122     public static void main(String[] args) throws Exception {
123         double deltaTime = System.currentTimeMillis();
124         try {
125             String methodName = System.getProperty("method");
126             if (methodName != null) {
127                 CldrUtility.callMethod(methodName, CountItems.class);
128             } else {
129                 ShowZoneEquivalences.getZoneEquivalences();
130             }
131         } finally {
132             deltaTime = System.currentTimeMillis() - deltaTime;
133             System.out.println("Elapsed: " + deltaTime / 1000.0 + " seconds");
134             System.out.println("Done");
135         }
136     }
137 
subheader(PrintWriter out, Tabber tabber)138     static void subheader(PrintWriter out, Tabber tabber) {
139         // out.println("<tr><td colspan='6' class='gap'>&nbsp;</td></tr>");
140         out.println(tabber.process("Cnty" + "\t" + "Grp" + "\t" + "ZoneID" + "\t"
141             + "Formatted ID" + "\t" + "MaxOffset" + "\t" + "MinOffset"));
142     }
143 
144     /**
145      *
146      */
getPatternBlocks()147     private static void getPatternBlocks() {
148         UnicodeSet patterns = new UnicodeSet("[:pattern_syntax:]");
149         UnicodeSet unassigned = new UnicodeSet("[:unassigned:]");
150         UnicodeSet punassigned = new UnicodeSet(patterns).retainAll(unassigned);
151         UnicodeMap<String> blocks = ICUPropertyFactory.make().getProperty("block")
152             .getUnicodeMap();
153         blocks.setMissing("<Reserved-Block>");
154         // blocks.composeWith(new UnicodeMap().putAll(new UnicodeSet(patterns).retainAll(unassigned),"<reserved>"),
155         // new UnicodeMap.Composer() {
156         // public Object compose(int codePoint, Object a, Object b) {
157         // if (a == null) {
158         // return b;
159         // }
160         // if (b == null) {
161         // return a;
162         // }
163         // return a.toString() + " " + b.toString();
164         // }});
165         for (UnicodeMapIterator<String> it = new UnicodeMapIterator<String>(blocks); it
166             .nextRange();) {
167             UnicodeSet range = new UnicodeSet(it.codepoint, it.codepointEnd);
168             boolean hasPat = range.containsSome(patterns);
169             String prefix = !hasPat ? "Not-Syntax"
170                 : !range.containsSome(unassigned) ? "Closed" : !range
171                     .containsSome(punassigned) ? "Closed2" : "Open";
172 
173             boolean show = (prefix.equals("Open") || prefix.equals("Closed2"));
174 
175             if (show)
176                 System.out.println();
177             System.out.println(prefix + "\t" + range + "\t" + it.value);
178             if (show) {
179                 System.out.println(new UnicodeMap<String>().putAll(unassigned, "<reserved>")
180                     .putAll(punassigned, "<reserved-for-syntax>").setMissing(
181                         "<assigned>")
182                     .putAll(range.complement(), null));
183             }
184         }
185     }
186 
187     /**
188      * @throws IOException
189      *
190      */
showExemplars()191     private static void showExemplars() throws IOException {
192         PrintWriter out = FileUtilities.openUTF8Writer(CLDRPaths.GEN_DIRECTORY, "fixed_exemplars.txt");
193         Factory cldrFactory = Factory.make(CLDRPaths.MAIN_DIRECTORY, ".*");
194         Set<String> locales = cldrFactory.getAvailable();
195         for (Iterator<String> it = locales.iterator(); it.hasNext();) {
196             System.out.print('.');
197             String locale = it.next();
198             CLDRFile cldrfile = cldrFactory.make(locale, false);
199             String v = cldrfile
200                 .getStringValue("//ldml/characters/exemplarCharacters");
201             if (v == null)
202                 continue;
203             UnicodeSet exemplars = new UnicodeSet(v);
204             if (exemplars.size() != 0 && exemplars.size() < 500) {
205                 Collator col = Collator.getInstance(new ULocale(locale));
206                 Collator spaceCol = Collator.getInstance(new ULocale(locale));
207                 spaceCol.setStrength(Collator.PRIMARY);
208                 out.println(locale + ":\t\u200E" + v + '\u200E');
209                 // String fixedFull = CollectionUtilities.prettyPrint(exemplars, col, false);
210                 // System.out.println(" =>\t" + fixedFull);
211                 // verifyEquality(exemplars, new UnicodeSet(fixedFull));
212                 String fixed = new UnicodeSetPrettyPrinter()
213                     .setOrdering(col != null ? col : Collator.getInstance(ULocale.ROOT))
214                     .setSpaceComparator(spaceCol != null ? spaceCol : ROOT_PRIMARY_COLLATOR)
215                     .setCompressRanges(true)
216                     .format(exemplars);
217                 out.println(" =>\t\u200E" + fixed + '\u200E');
218 
219                 verifyEquality(exemplars, new UnicodeSet(fixed));
220                 out.flush();
221             }
222         }
223         out.close();
224     }
225 
226     /**
227      *
228      */
verifyEquality(UnicodeSet exemplars, UnicodeSet others)229     private static void verifyEquality(UnicodeSet exemplars, UnicodeSet others) {
230         if (others.equals(exemplars))
231             return;
232         System.out.println("FAIL\ta-b\t"
233             + new UnicodeSet(exemplars).removeAll(others));
234         System.out.println("\tb-a\t" + new UnicodeSet(others).removeAll(exemplars));
235     }
236 
237     /**
238      *
239      */
generateSupplementalCurrencyItems()240     public static void generateSupplementalCurrencyItems() {
241         IsoCurrencyParser isoCurrencyParser = IsoCurrencyParser.getInstance();
242         Relation<String, Data> codeList = isoCurrencyParser.getCodeList();
243         Map<String, String> numericTocurrencyCode = new TreeMap<String, String>();
244         StringBuffer list = new StringBuffer();
245 
246         for (Iterator<String> it = codeList.keySet().iterator(); it.hasNext();) {
247             String currencyCode = it.next();
248             int numericCode = -1;
249             Set<Data> dataSet = codeList.getAll(currencyCode);
250             boolean first = true;
251             for (Data data : dataSet) {
252                 if (first) {
253                     first = false;
254                 }
255                 numericCode = data.getNumericCode();
256             }
257 
258             String strNumCode = "" + numericCode;
259             String otherCode = numericTocurrencyCode.get(strNumCode);
260             if (otherCode != null) {
261                 System.out.println("Warning: duplicate code " + otherCode +
262                     "for " + numericCode);
263             }
264             numericTocurrencyCode.put(strNumCode, currencyCode);
265             if (list.length() != 0)
266                 list.append(" ");
267             String currencyLine = "<currencyCodes type=" + "\"" + currencyCode +
268                 "\"" + " numeric=" + "\"" + numericCode + "\"/>";
269             list.append(currencyLine);
270             System.out.println(currencyLine);
271 
272         }
273         System.out.println();
274 
275     }
276 
277     /**
278      *
279      */
generateCurrencyItems()280     public static void generateCurrencyItems() {
281         IsoCurrencyParser isoCurrencyParser = IsoCurrencyParser.getInstance();
282         Relation<String, Data> codeList = isoCurrencyParser.getCodeList();
283         StringBuffer list = new StringBuffer();
284         for (Iterator<String> it = codeList.keySet().iterator(); it.hasNext();) {
285             // String lastField = (String) it.next();
286             // String zone = (String) fullMap.get(lastField);
287             String currencyCode = it.next();
288             Set<Data> dataSet = codeList.getAll(currencyCode);
289             boolean first = true;
290             for (Data data : dataSet) {
291                 if (first) {
292                     System.out.print(currencyCode);
293                     first = false;
294                 }
295                 System.out.println("\t" + data);
296             }
297 
298             if (list.length() != 0)
299                 list.append(" ");
300             list.append(currencyCode);
301 
302         }
303         System.out.println();
304         String sep = CldrUtility.LINE_SEPARATOR + "\t\t\t\t";
305         // "((?:[-+_A-Za-z0-9]+[/])+[A-Za-z0-9])[-+_A-Za-z0-9]*"
306         String broken = CldrUtility.breakLines(list.toString(), sep, PatternCache.get(
307             "([A-Z])[A-Z][A-Z]").matcher(""), 80);
308         assert (list.toString().equals(broken.replace(sep, " ")));
309         //System.out.println("\t\t\t<variable id=\"$currency\" type=\"choice\">"
310         //    + broken + CldrUtility.LINE_SEPARATOR + "\t\t\t</variable>");
311         Set<String> isoTextFileCodes = StandardCodes.make().getAvailableCodes(
312             "currency");
313         Set<String> temp = new TreeSet<String>(codeList.keySet());
314         temp.removeAll(isoTextFileCodes);
315         if (temp.size() != 0) {
316             throw new IllegalArgumentException("Missing from ISO4217.txt file: " + temp);
317         }
318     }
319 
genSupplementalZoneData()320     public static void genSupplementalZoneData() throws IOException {
321         genSupplementalZoneData(false);
322     }
323 
genSupplementalZoneData(boolean skipUnaliased)324     public static void genSupplementalZoneData(boolean skipUnaliased)
325         throws IOException {
326         RuleBasedCollator col = (RuleBasedCollator) Collator.getInstance();
327         col.setNumericCollation(true);
328         StandardCodes sc = StandardCodes.make();
329         Map<String, String> zone_country = sc.getZoneToCounty();
330         Map<String, Set<String>> country_zone = sc.getCountryToZoneSet();
331         Factory cldrFactory = Factory.make(CLDRPaths.MAIN_DIRECTORY, ".*");
332         CLDRFile english = cldrFactory.make("en", true);
333 
334         writeZonePrettyPath(col, zone_country, english);
335         writeMetazonePrettyPath();
336 
337         Map<String, String> old_new = sc.getZoneLinkold_new();
338         Map<String, Set<String>> new_old = new TreeMap<String, Set<String>>();
339 
340         for (Iterator<String> it = old_new.keySet().iterator(); it.hasNext();) {
341             String old = it.next();
342             String newOne = old_new.get(old);
343             Set<String> oldSet = new_old.get(newOne);
344             if (oldSet == null)
345                 new_old.put(newOne, oldSet = new TreeSet<String>());
346             oldSet.add(old);
347         }
348         Map<String, String> fullMap = new TreeMap<String, String>(col);
349         for (Iterator<String> it = zone_country.keySet().iterator(); it.hasNext();) {
350             String zone = it.next();
351             String defaultName = TimezoneFormatter.getFallbackName(zone);
352             Object already = fullMap.get(defaultName);
353             if (already != null)
354                 System.out.println("CONFLICT: " + already + ", " + zone);
355             fullMap.put(defaultName, zone);
356         }
357         // fullSet.addAll(zone_country.keySet());
358         // fullSet.addAll(new_old.keySet());
359 
360         System.out
361             .println("<!-- Generated by org.unicode.cldr.tool.CountItems -->");
362         System.out.println("<supplementalData>");
363         System.out.println("\t<timezoneData>");
364         System.out.println();
365 
366         Set<String> multizone = new TreeSet<String>();
367         for (Iterator<String> it = country_zone.keySet().iterator(); it.hasNext();) {
368             String country = it.next();
369             Set<String> zones = country_zone.get(country);
370             if (zones != null && zones.size() != 1)
371                 multizone.add(country);
372         }
373 
374         System.out.println("\t\t<zoneFormatting multizone=\""
375             + toString(multizone, " ") + "\"" + " tzidVersion=\""
376             + sc.getZoneVersion() + "\"" + ">");
377 
378         Set<String> orderedSet = new TreeSet<String>(col);
379         orderedSet.addAll(zone_country.keySet());
380         orderedSet.addAll(sc.getDeprecatedZoneIDs());
381         StringBuffer tzid = new StringBuffer();
382 
383         for (Iterator<String> it = orderedSet.iterator(); it.hasNext();) {
384             // String lastField = (String) it.next();
385             // String zone = (String) fullMap.get(lastField);
386             String zone = it.next();
387             if (tzid.length() != 0)
388                 tzid.append(' ');
389             tzid.append(zone);
390 
391             String country = zone_country.get(zone);
392             if (country == null)
393                 continue; // skip deprecated
394 
395             Set<String> aliases = new_old.get(zone);
396             if (aliases != null) {
397                 aliases = new TreeSet<String>(aliases);
398                 aliases.remove(zone);
399             }
400             if (skipUnaliased)
401                 if (aliases == null || aliases.size() == 0)
402                     continue;
403 
404             System.out.println("\t\t\t<zoneItem"
405                 + " type=\""
406                 + zone
407                 + "\""
408                 + " territory=\""
409                 + country
410                 + "\""
411                 + (aliases != null && aliases.size() > 0 ? " aliases=\""
412                     + toString(aliases, " ") + "\"" : "")
413                 + "/>");
414         }
415 
416         System.out.println("\t\t</zoneFormatting>");
417         System.out.println();
418         System.out.println("\t</timezoneData>");
419         System.out.println("</supplementalData>");
420         System.out.println();
421         String sep = CldrUtility.LINE_SEPARATOR + "\t\t\t\t";
422         // "((?:[-+_A-Za-z0-9]+[/])+[A-Za-z0-9])[-+_A-Za-z0-9]*"
423         String broken = CldrUtility.breakLines(tzid, sep, PatternCache.get(
424             "((?:[-+_A-Za-z0-9]+[/])+[-+_A-Za-z0-9])[-+_A-Za-z0-9]*").matcher(""),
425             80);
426         assert (tzid.toString().equals(broken.replace(sep, " ")));
427         System.out.println("\t\t\t<variable id=\"$tzid\" type=\"choice\">" + broken
428             + CldrUtility.LINE_SEPARATOR + "\t\t\t</variable>");
429     }
430 
writeMetazonePrettyPath()431     public static void writeMetazonePrettyPath() {
432         CLDRConfig testInfo = ToolConfig.getToolInstance();
433         Map<String, Map<String, String>> map = testInfo.getSupplementalDataInfo().getMetazoneToRegionToZone();
434         Map zoneToCountry = testInfo.getStandardCodes().getZoneToCounty();
435         Set<Pair<String, String>> results = new TreeSet<Pair<String, String>>();
436         Map<String, String> countryToContinent = getCountryToContinent(testInfo.getSupplementalDataInfo(),
437             testInfo.getEnglish());
438 
439         for (String metazone : map.keySet()) {
440             Map<String, String> regionToZone = map.get(metazone);
441             String zone = regionToZone.get("001");
442             if (zone == null) {
443                 throw new IllegalArgumentException("Missing 001 for metazone " + metazone);
444             }
445             String continent = zone.split("/")[0];
446 
447             final Object country = zoneToCountry.get(zone);
448             results.add(new Pair<String, String>(continent + "\t" + country + "\t" + countryToContinent.get(country)
449                 + "\t" + metazone, metazone));
450         }
451         for (Pair<String, String> line : results) {
452             System.out.println("'" + line.getSecond() + "'\t>\t'\t" + line.getFirst() + "\t'");
453         }
454     }
455 
getCountryToContinent(SupplementalDataInfo supplementalDataInfo, CLDRFile english)456     private static Map<String, String> getCountryToContinent(SupplementalDataInfo supplementalDataInfo, CLDRFile english) {
457         Relation<String, String> countryToContinent = Relation.of(new TreeMap<String, Set<String>>(), TreeSet.class);
458         Set<String> continents = new HashSet<String>(Arrays.asList("002", "019", "142", "150", "009"));
459         // note: we don't need more than 3 levels
460         for (String continent : continents) {
461             final Set<String> subcontinents = supplementalDataInfo.getContained(continent);
462             countryToContinent.putAll(subcontinents, continent);
463             for (String subcontinent : subcontinents) {
464                 if (subcontinent.equals("EU")) continue;
465                 final Set<String> countries = supplementalDataInfo.getContained(subcontinent);
466                 countryToContinent.putAll(countries, continent);
467             }
468         }
469         // convert to map
470         Map<String, String> results = new TreeMap<String, String>();
471         for (String item : countryToContinent.keySet()) {
472             final Set<String> containees = countryToContinent.getAll(item);
473             if (containees.size() != 1) {
474                 throw new IllegalArgumentException(item + "\t" + containees);
475             }
476             results.put(item, english.getName(CLDRFile.TERRITORY_NAME, containees.iterator().next()));
477         }
478         return results;
479     }
480 
writeZonePrettyPath(RuleBasedCollator col, Map<String, String> zone_country, CLDRFile english)481     private static void writeZonePrettyPath(RuleBasedCollator col, Map<String, String> zone_country,
482         CLDRFile english) throws IOException {
483         System.out.println("Writing zonePrettyPath");
484         Set<String> masked = new HashSet<String>();
485         Map<String, String> zoneNew_Old = new TreeMap<String, String>(col);
486         String lastZone = "XXX";
487         for (String zone : new TreeSet<String>(zone_country.keySet())) {
488             String[] parts = zone.split("/");
489             String newPrefix = zone_country.get(zone); // english.getName("tzid", zone_country.get(zone),
490             // false).replace(' ', '_');
491             if (newPrefix.equals("001")) {
492                 newPrefix = "ZZ";
493             }
494             parts[0] = newPrefix;
495             String newName;
496             if (parts.length > 2) {
497                 System.out.println("\tMultifield: " + zone);
498                 if (parts.length == 3 && parts[1].equals("Argentina")) {
499                     newName = parts[0] + "/" + parts[1];
500                 } else {
501                     newName = CldrUtility.join(parts, "/");
502                 }
503             } else {
504                 newName = CldrUtility.join(parts, "/");
505             }
506             zoneNew_Old.put(newName, zone);
507             if (zone.startsWith(lastZone)) {
508                 masked.add(zone); // find "masked items" and do them first.
509             } else {
510                 lastZone = zone;
511             }
512         }
513 
514         Log.setLog(CLDRPaths.GEN_DIRECTORY + "/supplemental/prettyPathZone.txt");
515         String lastCountry = "";
516         for (int i = 0; i < 2; ++i) {
517             Set<String> orderedList = zoneNew_Old.keySet();
518             if (i == 0) {
519                 Log
520                     .println("# Short IDs for zone names: country code + last part of TZID");
521                 Log
522                     .println("# First are items that would be masked, and are moved forwards and sorted in reverse order");
523                 Log.println();
524                 //Comparator c;
525                 Set<String> temp = new TreeSet<String>(new ReverseComparator<Object>(col));
526                 temp.addAll(orderedList);
527                 orderedList = temp;
528             } else {
529                 Log.println();
530                 Log.println("# Normal items, sorted by country code");
531                 Log.println();
532             }
533 
534             // do masked items first
535 
536             for (String newName : orderedList) {
537                 String oldName = zoneNew_Old.get(newName);
538                 if (masked.contains(oldName) != (i == 0)) {
539                     continue;
540                 }
541                 String newCountry = newName.split("/")[0];
542                 if (!newCountry.equals(lastCountry)) {
543                     Log.println("# " + newCountry + "\t"
544                         + english.getName("territory", newCountry));
545                     lastCountry = newCountry;
546                 }
547                 Log.println("\t'" + oldName + "'\t>\t'" + newName + "';");
548             }
549         }
550         Log.close();
551         System.out.println("Done Writing zonePrettyPath");
552     }
553 
554     public static class ReverseComparator<T> implements Comparator<T> {
555         Comparator<T> other;
556 
ReverseComparator(Comparator<T> other)557         public ReverseComparator(Comparator<T> other) {
558             this.other = other;
559         }
560 
compare(T o1, T o2)561         public int compare(T o1, T o2) {
562             return other.compare(o2, o1);
563         }
564     }
565 
getSubtagVariables2()566     public static void getSubtagVariables2() throws IOException {
567         Log.setLogNoBOM(CLDRPaths.GEN_DIRECTORY + "/supplemental", "supplementalMetadata.xml");
568         BufferedReader oldFile = FileUtilities.openUTF8Reader(CLDRPaths.SUPPLEMENTAL_DIRECTORY, "supplementalMetadata.xml");
569         CldrUtility.copyUpTo(oldFile, PatternCache.get("\\s*<!-- start of data generated with CountItems.*"),
570             Log.getLog(), true);
571 
572         Map<String, String> variableSubstitutions = getVariables(VariableType.partial);
573         for (Entry<String, String> type : variableSubstitutions.entrySet()) {
574             Log.println(type.getValue());
575         }
576 
577         // String sep = CldrUtility.LINE_SEPARATOR + "\t\t\t";
578         // String broken = CldrUtility.breakLines(CldrUtility.join(defaultLocaleContent," "), sep,
579         // PatternCache.get("(\\S)\\S*").matcher(""), 80);
580         //
581         // Log.println("\t\t<defaultContent locales=\"" + broken + "\"");
582         // Log.println("\t\t/>");
583 
584         // Log.println("</supplementalData>");
585         CldrUtility.copyUpTo(oldFile, PatternCache.get("\\s<!-- end of data generated by CountItems.*"), null, true);
586         CldrUtility.copyUpTo(oldFile, null, Log.getLog(), true);
587 
588         Log.close();
589         oldFile.close();
590     }
591 
592     static final SupplementalDataInfo supplementalData = SupplementalDataInfo
593         .getInstance(CLDRPaths.SUPPLEMENTAL_DIRECTORY);
594     static final StandardCodes sc = StandardCodes.make();
595 
getSubtagVariables()596     public static void getSubtagVariables() {
597 //        This section no longer necessary, as it has been replaced by the new attributeValueValidity.xml
598 //
599 //        System.out.println("Validity variables");
600 //        System.out.println("Cut/paste into supplementalMetadata.xml under the line");
601 //        System.out.println("<!-- start of data generated with CountItems tool ...");
602 //        Map<String, String> variableSubstitutions = getVariables(VariableType.partial);
603 
604 //        for (Entry<String, String> type : variableSubstitutions.entrySet()) {
605 //            System.out.println(type.getValue());
606 //        }
607 //        System.out.println("<!-- end of Validity variables generated with CountItems tool ...");
608 //        System.out.println();
609         System.out.println("Language aliases");
610         System.out.println("Cut/paste into supplementalMetadata.xml under the line");
611         System.out.println("<!-- start of data generated with CountItems tool ...");
612 
613         Map<String, Map<String, String>> languageReplacement = StandardCodes.getLStreg().get("language");
614         Map<String, Map<String, R2<List<String>, String>>> localeAliasInfo = supplementalData.getLocaleAliasInfo();
615         Map<String, R2<List<String>, String>> languageAliasInfo = localeAliasInfo.get("language");
616 
617         Set<String> available = Iso639Data.getAvailable();
618         // <languageAlias type="aju" replacement="jrb"/> <!-- Moroccan Judeo-Arabic ⇒ Judeo-Arabic -->
619         Set<String> bad3letter = new HashSet<String>();
620         for (String lang : available) {
621             if (lang.length() != 2) continue;
622             String target = lang;
623             Map<String, String> lstregData = languageReplacement.get(lang);
624             if (lstregData == null) {
625                 throw new IllegalArgumentException("illegal language code");
626             } else {
627                 String replacement = lstregData.get("Preferred-Value");
628                 if (replacement != null) {
629                     target = replacement;
630                 }
631             }
632             String alpha3 = Iso639Data.toAlpha3(lang);
633             bad3letter.add(alpha3);
634             String targetAliased;
635             if (languageAliasInfo.containsKey(target)) {
636                 targetAliased = CollectionUtilities.join(languageAliasInfo.get(target).get0(), " ");
637             } else {
638                 targetAliased = target;
639             }
640             System.out.println("\t\t\t<languageAlias type=\"" + alpha3 + "\" replacement=\"" + targetAliased
641                 + "\" reason=\"overlong\"/> <!-- " +
642                 Iso639Data.getNames(target) + " -->");
643         }
644         System.out.println("\t\t\t<!-- Bibliographic -->");
645         TreeMap<String, String> sorted = new TreeMap<>();
646         for (String hasBiblio : Iso639Data.hasBiblio3()) {
647             String biblio = Iso639Data.toBiblio3(hasBiblio);
648             sorted.put(biblio, hasBiblio);
649         }
650         for (Entry<String, String> entry : sorted.entrySet()) {
651             String biblio = entry.getKey();
652             String hasBiblio = entry.getValue();
653             System.out.println("\t\t\t<languageAlias type=\"" + biblio + "\" replacement=\"" + hasBiblio
654                 + "\" reason=\"bibliographic\"/> <!-- " +
655                 Iso639Data.getNames(hasBiblio) + " -->");
656         }
657         System.out.println("<!-- end of Language alises generated with CountItems tool ...");
658 
659         Set<String> encompassed = Iso639Data.getEncompassed();
660         Set<String> macros = Iso639Data.getMacros();
661         Map<String, String> encompassed_macro = new HashMap<String, String>();
662         for (Entry<String, R2<List<String>, String>> typeAndData : languageAliasInfo.entrySet()) {
663             String type = typeAndData.getKey();
664             R2<List<String>, String> data = typeAndData.getValue();
665             List<String> replacements = data.get0();
666             if (!encompassed.contains(type)) continue;
667             if (replacements == null || replacements.size() != 1) continue;
668             String replacement = replacements.get(0);
669             if (macros.contains(replacement)) {
670                 // we have a match, encompassed => replacement
671                 encompassed_macro.put(type, replacement);
672             }
673         }
674         Set<String> missing = new TreeSet<String>();
675         missing.addAll(macros);
676         missing.remove("no");
677         missing.remove("sh");
678 
679         missing.removeAll(encompassed_macro.values());
680         if (missing.size() != 0) {
681             for (String missingMacro : missing) {
682                 System.err.println("ERROR: Missing <languageAlias type=\"" + "???" + "\" replacement=\"" + missingMacro
683                     + "\"/> <!-- ??? => " +
684                     Iso639Data.getNames(missingMacro) + " -->");
685                 System.out.println("\tOptions for ???:");
686                 for (String enc : Iso639Data.getEncompassedForMacro(missingMacro)) {
687                     System.out.println("\t" + enc + "\t// " + Iso639Data.getNames(enc));
688                 }
689             }
690         }
691         // verify that every macro language has a encompassed mapping to it
692         // and remember those codes
693 
694         // verify that nobody contains a bad code
695 
696         for (Entry<String, R2<List<String>, String>> typeAndData : languageAliasInfo.entrySet()) {
697             String type = typeAndData.getKey();
698             List<String> replacements = typeAndData.getValue().get0();
699             if (replacements == null) continue;
700             for (String replacement : replacements) {
701                 if (bad3letter.contains(replacement)) {
702                     System.err.println("ERROR: Replacement(s) for type=\"" + type +
703                         "\" contains " + replacement + ", which should be: " + Iso639Data.fromAlpha3(replacement));
704                 }
705             }
706         }
707 
708         // get the bad ISO codes
709 
710         Factory cldrFactory = Factory.make(CLDRPaths.MAIN_DIRECTORY, ".*");
711         CLDRFile english = cldrFactory.make("en", true);
712 
713         Set<String> territories = new TreeSet<String>();
714         Relation<String, String> containers = supplementalData.getTerritoryToContained();
715         for (String region : sc.getAvailableCodes("territory")) {
716             if (containers.containsKey(region)) continue;
717             territories.add(region);
718         }
719         System.out.println();
720         System.out.println("Territory aliases");
721         System.out.println("Cut/paste into supplementalMetadata.xml under the line");
722         System.out.println("<!-- start of data generated with CountItems tool ...");
723         //final Map<String, R2<List<String>, String>> territoryAliasInfo = localeAliasInfo.get("territory");
724 
725         addRegions(english, territories, "alpha3", "EA,EU,IC".split(","), new Transform<String, String>() {
726             public String transform(String region) {
727                 return IsoRegionData.get_alpha3(region);
728             }
729         });
730         addRegions(english, territories, "numeric", "AC,CP,DG,EA,EU,IC,TA".split(","), new Transform<String, String>() {
731             public String transform(String region) {
732                 return IsoRegionData.getNumeric(region);
733             }
734         });
735         System.out.println("<!-- end of Territory alises generated with CountItems tool ...");
736         System.out.println();
737         System.out.println("Deprecated codes check (informational)");
738         // check that all deprecated codes are in fact deprecated
739         Map<String, Map<String, Map<String, String>>> fullData = StandardCodes.getLStreg();
740 
741         checkCodes("language", sc, localeAliasInfo, fullData);
742         checkCodes("script", sc, localeAliasInfo, fullData);
743         checkCodes("territory", sc, localeAliasInfo, fullData);
744         System.out.println("End of Deprecated codes check...");
745 
746         // generate mapping equivalences
747         // { "aar", "aar", "aa" }, // Afar
748         // b, t, bcp47
749         System.out.println();
750         System.out.println("Mapping equivalences - (Informational only...)");
751         System.out.println("{ bib , tech , bcp47 }");
752 
753         Set<R3<String, String, String>> rows = new TreeSet<R3<String, String, String>>();
754         for (String lang : Iso639Data.getAvailable()) {
755             String bib = Iso639Data.toBiblio3(lang);
756             String tech = Iso639Data.toAlpha3(lang);
757             R3<String, String, String> row = Row.of(tech, bib, lang);
758             rows.add(row);
759         }
760         for (R3<String, String, String> row : rows) {
761             String tech = row.get0();
762             String bib = row.get1();
763             String lang = row.get2();
764             String name = Iso639Data.getNames(lang).iterator().next(); // english.getName(lang);
765             if ((bib != null && !lang.equals(bib)) || (tech != null && !lang.equals(tech))) {
766                 System.out.println("  { \"" + bib + "\", \"" + tech + "\", \"" + lang + "\" },  // " + name);
767             }
768         }
769         System.out.println("End of Mapping equivalences...");
770 
771         // generate the codeMappings
772         // <codeMappings>
773         // <territoryCodes type="CS" numeric="891" alpha3="SCG" fips10="YI"/>
774 
775         System.out.println();
776         System.out.println("Code Mappings");
777         System.out.println("Cut/paste into supplementaData.xml under the line");
778         System.out.println("<!-- start of data generated with CountItems tool ...");
779         List<String> warnings = new ArrayList<String>();
780         territories.add("QO");
781         territories.add("EU");
782         // territories.add("MF");
783         //Map<String, R2<List<String>, String>> territoryAliases = supplementalData.getLocaleAliasInfo().get("territory");
784         Relation<String, String> numeric2region = Relation.of(new HashMap<String, Set<String>>(), TreeSet.class);
785         Relation<String, String> alpha32region = Relation.of(new HashMap<String, Set<String>>(), TreeSet.class);
786         for (String region : territories) {
787             String numeric = IsoRegionData.getNumeric(region);
788             String alpha3 = IsoRegionData.get_alpha3(region);
789             numeric2region.put(numeric, region);
790             alpha32region.put(alpha3, region);
791         }
792 
793         System.out.println("    <codeMappings>");
794 
795         for (String region : territories) {
796             String numeric = IsoRegionData.getNumeric(region);
797             String alpha3 = IsoRegionData.get_alpha3(region);
798             String fips10 = IsoRegionData.get_fips10(region);
799             System.out.println("        <territoryCodes"
800                 + " type=\"" + region + "\""
801                 + (numeric == null ? "" : " numeric=\"" + numeric + "\"")
802                 + (alpha3 == null ? "" : " alpha3=\"" + alpha3 + "\"")
803                 + (fips10 == null || fips10.equals(region) ? "" : " fips10=\"" + fips10 + "\"")
804                 + "/>");
805         }
806         System.out.println("    </codeMappings>");
807         System.out.println("<!-- end of Code Mappings generated with CountItems tool ...");
808         System.out.println(CollectionUtilities.join(warnings, CldrUtility.LINE_SEPARATOR));
809     }
810 
811     enum VariableType {
812         full, partial
813     }
814 
getVariables(VariableType variableType)815     public static Map<String, String> getVariables(VariableType variableType) {
816         String sep = CldrUtility.LINE_SEPARATOR + "\t\t\t\t";
817         Map<String, String> variableSubstitutions = new LinkedHashMap<String, String>();
818         for (String type : new String[] { "grandfathered", "territory", "script", "variant" }) {
819             Set<String> i;
820             i = (variableType == VariableType.full || type.equals("grandfathered")) ? sc.getAvailableCodes(type) : sc.getGoodAvailableCodes(type);
821             addVariable(variableSubstitutions, type, i, sep);
822         }
823 
824         Relation<String, String> bcp47Keys = supplementalData.getBcp47Keys();
825         Relation<R2<String, String>, String> aliases = supplementalData.getBcp47Aliases();
826         for (String key : bcp47Keys.keySet()) {
827             Set<String> keyAliases = aliases.getAll(Row.of(key, ""));
828             Set<String> rawsubtypes = bcp47Keys.getAll(key);
829             TreeSet<String> subtypes = new TreeSet<String>();
830             for (String subtype : rawsubtypes) {
831                 Set<String> keySubtypeAliases = aliases.getAll(Row.of(key, subtype));
832                 if (keySubtypeAliases != null) {
833                     subtypes.addAll(keySubtypeAliases);
834                 }
835             }
836             subtypes.addAll(rawsubtypes);
837             String alias = (keyAliases == null ? key : keyAliases.iterator().next()) + "_XXX";
838             addVariable(variableSubstitutions, alias, subtypes, sep);
839         }
840         return variableSubstitutions;
841     }
842 
843     private static final Pattern BreakerPattern = PatternCache.get("([-_A-Za-z0-9])[-/+_A-Za-z0-9]*");
844 
addVariable(Map<String, String> variableSubstitutions, String type, Set<String> sinput, String sep)845     private static void addVariable(Map<String, String> variableSubstitutions, String type, Set<String> sinput,
846         String sep) {
847         TreeSet<String> s = new TreeSet<String>(ROOT_PRIMARY_COLLATOR);
848         s.addAll(sinput);
849 
850         StringBuffer b = new StringBuffer();
851         for (String code : s) {
852             if (b.length() != 0)
853                 b.append(' ');
854             b.append(code);
855         }
856         // "((?:[-+_A-Za-z0-9]+[/])+[A-Za-z0-9])[-+_A-Za-z0-9]*"
857         String broken = CldrUtility.breakLines(b, sep, BreakerPattern.matcher(""), 80);
858         assert (b.toString().equals(broken.replace(sep, " ")));
859         variableSubstitutions.put(type, "\t\t\t<variable id=\"$" + type
860             + "\" type=\"choice\">" + broken + CldrUtility.LINE_SEPARATOR + "\t\t\t</variable>");
861     }
862 
checkCodes(String type, StandardCodes sc, Map<String, Map<String, R2<List<String>, String>>> localeAliasInfo, Map<String, Map<String, Map<String, String>>> fullData)863     private static void checkCodes(String type, StandardCodes sc,
864         Map<String, Map<String, R2<List<String>, String>>> localeAliasInfo,
865         Map<String, Map<String, Map<String, String>>> fullData) {
866         Map<String, Map<String, String>> typeData = fullData.get("territory".equals(type) ? "region" : type);
867         Map<String, R2<List<String>, String>> aliasInfo = localeAliasInfo.get(type);
868         for (String code : sc.getAvailableCodes(type)) {
869             Map<String, String> subdata = typeData.get(code);
870             String deprecated = subdata.get("Deprecated");
871             if (deprecated == null) continue;
872             String replacement = subdata.get("Preferred-Value");
873             R2<List<String>, String> supplementalReplacements = aliasInfo.get(code);
874             if (supplementalReplacements == null) {
875                 System.out.println("Deprecated in LSTR, but not in supplementalData: " + type + "\t" + code + "\t"
876                     + replacement);
877             }
878         }
879     }
880 
addRegions(CLDRFile english, Set<String> availableCodes, String codeType, String[] exceptions, Transform<String, String> trans)881     private static void addRegions(CLDRFile english, Set<String> availableCodes, String codeType, String[] exceptions,
882         Transform<String, String> trans) {
883         Set<String> missingRegions = new TreeSet<String>();
884         Set<String> exceptionSet = new HashSet<String>(Arrays.asList(exceptions));
885         List<String> duplicateDestroyer = new ArrayList<String>();
886         for (String region : availableCodes) {
887 
888             if (exceptionSet.contains(region)) continue;
889             String alpha3 = trans.transform(region);
890             if (alpha3 == null) {
891                 missingRegions.add(region);
892                 continue;
893             }
894             Map<String, R2<List<String>, String>> territoryAliasInfo = supplementalData.getLocaleAliasInfo().get("territory");
895             String result;
896             if (territoryAliasInfo.containsKey(region)) {
897                 result = CollectionUtilities.join(territoryAliasInfo.get(region).get0(), " ");
898             } else {
899                 result = region;
900             }
901             String name = english.getName(CLDRFile.TERRITORY_NAME, result);
902             if (!(duplicateDestroyer.contains(alpha3 + result + name))) {
903                 duplicateDestroyer.add(alpha3 + result + name);
904                 System.out.println("\t\t\t<territoryAlias type=\"" + alpha3 + "\" replacement=\"" + result
905                     + "\" reason=\"overlong\"/> <!-- " + name + " -->");
906             }
907         }
908         for (String region : missingRegions) {
909             String name = english.getName(CLDRFile.TERRITORY_NAME, region);
910             System.err.println("ERROR: Missing " + codeType + " code for " + region + "\t" + name);
911         }
912     }
913 
914     /**
915      *
916      */
toString(Collection aliases, String separator)917     private static String toString(Collection aliases, String separator) {
918         StringBuffer result = new StringBuffer();
919         boolean first = true;
920         for (Iterator<Object> it = aliases.iterator(); it.hasNext();) {
921             Object item = it.next();
922             if (first)
923                 first = false;
924             else
925                 result.append(separator);
926             result.append(item);
927         }
928         return result.toString();
929     }
930 
showZoneInfo()931     public static void showZoneInfo() throws IOException {
932         StandardCodes sc = StandardCodes.make();
933         Map<String, String> m = sc.getZoneLinkold_new();
934         int i = 0;
935         System.out.println("/* Generated by org.unicode.cldr.tool.CountItems */");
936         System.out.println();
937         i = 0;
938         System.out.println("/* zoneID, canonical zoneID */");
939         for (Iterator<String> it = m.keySet().iterator(); it.hasNext();) {
940             String old = it.next();
941             String newOne = m.get(old);
942             System.out.println("{\"" + old + "\", \"" + newOne + "\"},");
943             ++i;
944         }
945         System.out.println("/* Total: " + i + " */");
946 
947         System.out.println();
948         i = 0;
949         System.out.println("/* All canonical zoneIDs */");
950         for (Iterator<String> it = sc.getZoneData().keySet().iterator(); it.hasNext();) {
951             String old = it.next();
952             System.out.println("\"" + old + "\",");
953             ++i;
954         }
955         System.out.println("/* Total: " + i + " */");
956 
957         Factory mainCldrFactory = Factory.make(CLDRPaths.COMMON_DIRECTORY + "main"
958             + File.separator, ".*");
959         CLDRFile desiredLocaleFile = mainCldrFactory.make("root", true);
960         String temp = desiredLocaleFile
961             .getFullXPath("//ldml/dates/timeZoneNames/singleCountries");
962         String singleCountriesList = new XPathParts(null, null).set(temp)
963             .findAttributes("singleCountries").get("list");
964         Set<String> singleCountriesSet = new TreeSet<String>(CldrUtility.splitList(singleCountriesList,
965             ' '));
966 
967         Map<String, String> zone_countries = StandardCodes.make().getZoneToCounty();
968         Map<String, Set<String>> countries_zoneSet = StandardCodes.make().getCountryToZoneSet();
969         System.out.println();
970         i = 0;
971         System.out.println("/* zoneID, country, isSingle */");
972         for (Iterator<String> it = zone_countries.keySet().iterator(); it.hasNext();) {
973             String old = it.next();
974             String newOne = zone_countries.get(old);
975             Set<String> s = countries_zoneSet.get(newOne);
976             String isSingle = (s != null && s.size() == 1 || singleCountriesSet
977                 .contains(old)) ? "T" : "F";
978             System.out.println("{\"" + old + "\", \"" + newOne + "\", \"" + isSingle
979                 + "\"},");
980             ++i;
981         }
982         System.out.println("/* Total: " + i + " */");
983 
984         if (true)
985             return;
986 
987         Factory cldrFactory = Factory.make(CLDRPaths.MAIN_DIRECTORY, ".*");
988         Map<Organization, Map<String, Level>> platform_locale_status = StandardCodes.make().getLocaleTypes();
989         Map<String, Level> onlyLocales = platform_locale_status.get(Organization.ibm);
990         Set<String> locales = onlyLocales.keySet();
991         CLDRFile english = cldrFactory.make("en", true);
992         for (Iterator<String> it = locales.iterator(); it.hasNext();) {
993             String locale = it.next();
994             System.out.println(locale + "\t" + english.getName(locale) + "\t"
995                 + onlyLocales.get(locale));
996         }
997     }
998 
999     static final NumberFormat decimal = NumberFormat.getNumberInstance();
1000     static {
1001         decimal.setGroupingUsed(true);
1002     }
1003 
countItems()1004     public static void countItems() {
1005         // CLDRKey.main(new String[]{"-mde.*"});
1006         String dir = CldrUtility.getProperty("source", CLDRPaths.MAIN_DIRECTORY);
1007         Factory cldrFactory = Factory.make(dir, ".*");
1008         countItems(cldrFactory, false);
1009     }
1010 
1011     /**
1012      * @param cldrFactory
1013      * @param resolved
1014      */
countItems(Factory cldrFactory, boolean resolved)1015     private static int countItems(Factory cldrFactory, boolean resolved) {
1016         int count = 0;
1017         int resolvedCount = 0;
1018         Set<String> locales = cldrFactory.getAvailable();
1019         Set<String> keys = new HashSet<String>();
1020         Set<String> values = new HashSet<String>();
1021         Set<String> fullpaths = new HashSet<String>();
1022         Matcher alt = CLDRFile.ALT_PROPOSED_PATTERN.matcher("");
1023 
1024         Set<String> temp = new HashSet<String>();
1025         for (Iterator<String> it = locales.iterator(); it.hasNext();) {
1026             String locale = it.next();
1027             if (CLDRFile.isSupplementalName(locale))
1028                 continue;
1029             CLDRFile item = cldrFactory.make(locale, false);
1030 
1031             temp.clear();
1032             for (Iterator<String> it2 = item.iterator(); it2.hasNext();) {
1033                 String path = it2.next();
1034                 if (alt.reset(path).matches()) {
1035                     continue;
1036                 }
1037                 temp.add(path);
1038                 keys.add(path);
1039                 values.add(item.getStringValue(path));
1040                 fullpaths.add(item.getFullXPath(path));
1041             }
1042             int current = temp.size();
1043 
1044             CLDRFile itemResolved = cldrFactory.make(locale, true);
1045             temp.clear();
1046             CollectionUtilities.addAll(itemResolved.iterator(), temp);
1047             int resolvedCurrent = temp.size();
1048 
1049             System.out.println(locale + "\tPlain:\t" + current + "\tResolved:\t"
1050                 + resolvedCurrent + "\tUnique Paths:\t" + keys.size()
1051                 + "\tUnique Values:\t" + values.size() + "\tUnique Full Paths:\t"
1052                 + fullpaths.size());
1053             count += current;
1054             resolvedCount += resolvedCurrent;
1055         }
1056         System.out.println("Total Items\t" + decimal.format(count));
1057         System.out
1058             .println("Total Resolved Items\t" + decimal.format(resolvedCount));
1059         System.out.println("Unique Paths\t" + decimal.format(keys.size()));
1060         System.out.println("Unique Values\t" + decimal.format(values.size()));
1061         System.out
1062             .println("Unique Full Paths\t" + decimal.format(fullpaths.size()));
1063         return count;
1064     }
1065 
1066 }
1067