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