001package org.hl7.fhir.common.hapi.validation.support; 002 003import ca.uhn.fhir.i18n.Msg; 004import ca.uhn.fhir.context.ConfigurationException; 005import ca.uhn.fhir.context.FhirContext; 006import ca.uhn.fhir.context.support.ConceptValidationOptions; 007import ca.uhn.fhir.context.support.IValidationSupport; 008import ca.uhn.fhir.context.support.ValidationSupportContext; 009import ca.uhn.fhir.util.ClasspathUtil; 010import com.fasterxml.jackson.core.JsonProcessingException; 011import com.fasterxml.jackson.databind.ObjectMapper; 012import com.fasterxml.jackson.databind.node.ArrayNode; 013import com.fasterxml.jackson.databind.node.ObjectNode; 014import org.apache.commons.lang3.StringUtils; 015import org.apache.commons.lang3.Validate; 016import org.fhir.ucum.UcumEssenceService; 017import org.fhir.ucum.UcumException; 018import org.hl7.fhir.common.hapi.validation.validator.VersionSpecificWorkerContextWrapper; 019import org.hl7.fhir.convertors.advisors.impl.BaseAdvisor_30_40; 020import org.hl7.fhir.convertors.advisors.impl.BaseAdvisor_40_50; 021import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_40; 022import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; 023import org.hl7.fhir.dstu2.model.ValueSet; 024import org.hl7.fhir.instance.model.api.IBaseResource; 025import org.hl7.fhir.r4.model.CodeSystem; 026import org.slf4j.Logger; 027import org.slf4j.LoggerFactory; 028 029import javax.annotation.Nonnull; 030import javax.annotation.Nullable; 031import java.io.InputStream; 032import java.util.Collections; 033import java.util.HashMap; 034import java.util.Map; 035import java.util.Optional; 036 037import static org.apache.commons.lang3.StringUtils.defaultString; 038import static org.apache.commons.lang3.StringUtils.isBlank; 039import static org.apache.commons.lang3.StringUtils.isNotBlank; 040import static org.hl7.fhir.common.hapi.validation.support.SnapshotGeneratingValidationSupport.newVersionTypeConverter; 041 042/** 043 * This {@link IValidationSupport validation support module} can be used to validate codes against common 044 * CodeSystems that are commonly used, but are not distriuted with the FHIR specification for various reasons 045 * (size, complexity, etc.). 046 * <p> 047 * See <a href="https://hapifhir.io/hapi-fhir/docs/validation/validation_support_modules.html#CommonCodeSystemsTerminologyService">CommonCodeSystemsTerminologyService</a> in the HAPI FHIR documentation 048 * for details about what is and isn't covered by this class. 049 * </p> 050 */ 051public class CommonCodeSystemsTerminologyService implements IValidationSupport { 052 public static final String LANGUAGES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/languages"; 053 public static final String LANGUAGES_CODESYSTEM_URL = "urn:ietf:bcp:47"; 054 public static final String MIMETYPES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/mimetypes"; 055 public static final String MIMETYPES_CODESYSTEM_URL = "urn:ietf:bcp:13"; 056 public static final String CURRENCIES_CODESYSTEM_URL = "urn:iso:std:iso:4217"; 057 public static final String CURRENCIES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/currencies"; 058 public static final String COUNTRIES_CODESYSTEM_URL = "urn:iso:std:iso:3166"; 059 public static final String UCUM_CODESYSTEM_URL = "http://unitsofmeasure.org"; 060 public static final String UCUM_VALUESET_URL = "http://hl7.org/fhir/ValueSet/ucum-units"; 061 public static final String ALL_LANGUAGES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/all-languages"; 062 private static final String USPS_CODESYSTEM_URL = "https://www.usps.com/"; 063 private static final String USPS_VALUESET_URL = "http://hl7.org/fhir/us/core/ValueSet/us-core-usps-state"; 064 private static final Logger ourLog = LoggerFactory.getLogger(CommonCodeSystemsTerminologyService.class); 065 private static Map<String, String> USPS_CODES = Collections.unmodifiableMap(buildUspsCodes()); 066 private static Map<String, String> ISO_4217_CODES = Collections.unmodifiableMap(buildIso4217Codes()); 067 private static Map<String, String> ISO_3166_CODES = Collections.unmodifiableMap(buildIso3166Codes()); 068 private final FhirContext myFhirContext; 069 private final VersionSpecificWorkerContextWrapper.IVersionTypeConverter myVersionConverter; 070 private volatile org.hl7.fhir.r5.model.ValueSet myLanguagesVs; 071 private volatile Map<String, String> myLanguagesLanugageMap; 072 private volatile Map<String, String> myLanguagesRegionMap; 073 074 /** 075 * Constructor 076 */ 077 public CommonCodeSystemsTerminologyService(FhirContext theFhirContext) { 078 Validate.notNull(theFhirContext); 079 080 myFhirContext = theFhirContext; 081 myVersionConverter = newVersionTypeConverter(myFhirContext.getVersion().getVersion()); 082 } 083 084 @Override 085 public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) { 086 String url = getValueSetUrl(theValueSet); 087 return validateCode(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, url); 088 } 089 090 @Override 091 public CodeValidationResult validateCode(@Nonnull ValidationSupportContext theValidationSupportContext, @Nonnull ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) { 092 /* ************************************************************************************** 093 * NOTE: Update validation_support_modules.html if any of the support in this module 094 * changes in any way! 095 * **************************************************************************************/ 096 097 Map<String, String> handlerMap = null; 098 String expectSystem = null; 099 switch (defaultString(theValueSetUrl)) { 100 case USPS_VALUESET_URL: 101 handlerMap = USPS_CODES; 102 expectSystem = USPS_CODESYSTEM_URL; 103 break; 104 105 case CURRENCIES_VALUESET_URL: 106 handlerMap = ISO_4217_CODES; 107 expectSystem = CURRENCIES_CODESYSTEM_URL; 108 break; 109 110 case LANGUAGES_VALUESET_URL: 111 if (!LANGUAGES_CODESYSTEM_URL.equals(theCodeSystem) && !(theCodeSystem == null && theOptions.isInferSystem())) { 112 return new CodeValidationResult() 113 .setSeverity(IssueSeverity.ERROR) 114 .setMessage("Inappropriate CodeSystem URL \"" + theCodeSystem + "\" for ValueSet: " + theValueSetUrl); 115 } 116 117 IBaseResource languagesVs = myLanguagesVs; 118 if (languagesVs == null) { 119 languagesVs = theValidationSupportContext.getRootValidationSupport().fetchValueSet("http://hl7.org/fhir/ValueSet/languages"); 120 myLanguagesVs = (org.hl7.fhir.r5.model.ValueSet) myVersionConverter.toCanonical(languagesVs); 121 } 122 Optional<org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent> match = myLanguagesVs 123 .getCompose() 124 .getInclude() 125 .stream() 126 .flatMap(t -> t.getConcept().stream()) 127 .filter(t -> theCode.equals(t.getCode())) 128 .findFirst(); 129 if (match.isPresent()) { 130 return new CodeValidationResult() 131 .setCode(theCode) 132 .setDisplay(match.get().getDisplay()); 133 } else { 134 return new CodeValidationResult() 135 .setSeverity(IssueSeverity.ERROR) 136 .setMessage("Code \"" + theCode + "\" is not in valueset: " + theValueSetUrl); 137 } 138 139 case ALL_LANGUAGES_VALUESET_URL: 140 if (!LANGUAGES_CODESYSTEM_URL.equals(theCodeSystem) && !(theCodeSystem == null && theOptions.isInferSystem())) { 141 return new CodeValidationResult() 142 .setSeverity(IssueSeverity.ERROR) 143 .setMessage("Inappropriate CodeSystem URL \"" + theCodeSystem + "\" for ValueSet: " + theValueSetUrl); 144 } 145 146 LookupCodeResult outcome = lookupLanguageCode(theCode); 147 if (outcome.isFound()) { 148 return new CodeValidationResult() 149 .setCode(theCode) 150 .setDisplay(outcome.getCodeDisplay()); 151 } else { 152 return new CodeValidationResult() 153 .setSeverity(IssueSeverity.ERROR) 154 .setMessage("Code \"" + theCode + "\" is not in valueset: " + theValueSetUrl); 155 } 156 157 case MIMETYPES_VALUESET_URL: 158 // This is a pretty naive implementation - Should be enhanced in future 159 return new CodeValidationResult() 160 .setCode(theCode) 161 .setDisplay(theDisplay); 162 163 case UCUM_VALUESET_URL: { 164 String system = theCodeSystem; 165 if (system == null && theOptions.isInferSystem()) { 166 system = UCUM_CODESYSTEM_URL; 167 } 168 CodeValidationResult validationResult = validateLookupCode(theValidationSupportContext, theCode, system); 169 if (validationResult != null) { 170 return validationResult; 171 } 172 } 173 } 174 175 if (handlerMap != null) { 176 String display = handlerMap.get(theCode); 177 if (display != null) { 178 if (expectSystem.equals(theCodeSystem) || theOptions.isInferSystem()) { 179 return new CodeValidationResult() 180 .setCode(theCode) 181 .setDisplay(display); 182 } 183 } 184 185 return new CodeValidationResult() 186 .setSeverity(IssueSeverity.ERROR) 187 .setMessage("Code \"" + theCode + "\" is not in system: " + USPS_CODESYSTEM_URL); 188 } 189 190 if (isBlank(theValueSetUrl)) { 191 CodeValidationResult validationResult = validateLookupCode(theValidationSupportContext, theCode, theCodeSystem); 192 return validationResult; 193 } 194 195 return null; 196 } 197 198 @Nullable 199 public CodeValidationResult validateLookupCode(ValidationSupportContext theValidationSupportContext, String theCode, String theSystem) { 200 LookupCodeResult lookupResult = lookupCode(theValidationSupportContext, theSystem, theCode); 201 CodeValidationResult validationResult = null; 202 if (lookupResult != null) { 203 if (lookupResult.isFound()) { 204 validationResult = new CodeValidationResult() 205 .setCode(lookupResult.getSearchedForCode()) 206 .setDisplay(lookupResult.getCodeDisplay()); 207 } 208 } 209 210 return validationResult; 211 } 212 213 214 @Override 215 public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode, String theDisplayLanguage) { 216 Map<String, String> map; 217 switch (theSystem) { 218 case LANGUAGES_CODESYSTEM_URL: 219 return lookupLanguageCode(theCode); 220 case UCUM_CODESYSTEM_URL: 221 return lookupUcumCode(theCode); 222 case MIMETYPES_CODESYSTEM_URL: 223 return lookupMimetypeCode(theCode); 224 case COUNTRIES_CODESYSTEM_URL: 225 map = ISO_3166_CODES; 226 break; 227 case CURRENCIES_CODESYSTEM_URL: 228 map = ISO_4217_CODES; 229 break; 230 case USPS_CODESYSTEM_URL: 231 map = USPS_CODES; 232 break; 233 default: 234 return null; 235 } 236 237 String display = map.get(theCode); 238 if (isNotBlank(display)) { 239 LookupCodeResult retVal = new LookupCodeResult(); 240 retVal.setSearchedForCode(theCode); 241 retVal.setSearchedForSystem(theSystem); 242 retVal.setFound(true); 243 retVal.setCodeDisplay(display); 244 return retVal; 245 } 246 247 // If we get here it means we know the codesystem but the code was bad 248 LookupCodeResult retVal = new LookupCodeResult(); 249 retVal.setSearchedForCode(theCode); 250 retVal.setSearchedForSystem(theSystem); 251 retVal.setFound(false); 252 return retVal; 253 254 } 255 256 private LookupCodeResult lookupLanguageCode(String theCode) { 257 if (myLanguagesLanugageMap == null || myLanguagesRegionMap == null) { 258 initializeBcp47LanguageMap(); 259 } 260 261 int langRegionSeparatorIndex = StringUtils.indexOfAny(theCode, '-', '_'); 262 boolean hasRegionAndCodeSegments = langRegionSeparatorIndex > 0; 263 String language; 264 String region; 265 266 if (hasRegionAndCodeSegments) { 267 // we look for languages in lowercase only 268 // this will allow case insensitivity for language portion of code 269 language = myLanguagesLanugageMap.get(theCode.substring(0, langRegionSeparatorIndex).toLowerCase()); 270 region = myLanguagesRegionMap.get(theCode.substring(langRegionSeparatorIndex + 1).toUpperCase()); 271 272 if (language == null || region == null) { 273 //In case the user provides both a language and a region, they must both be valid for the lookup to succeed. 274 ourLog.warn("Couldn't find a valid bcp47 language-region combination from code: {}", theCode); 275 return buildNotFoundLookupCodeResult(theCode); 276 } else { 277 return buildLookupResultForLanguageAndRegion(theCode, language, region); 278 } 279 } else { 280 //In case user has only provided a language, we build the lookup from only that. 281 //NB: we only use the lowercase version of the language 282 language = myLanguagesLanugageMap.get(theCode.toLowerCase()); 283 if (language == null) { 284 ourLog.warn("Couldn't find a valid bcp47 language from code: {}", theCode); 285 return buildNotFoundLookupCodeResult(theCode); 286 } else { 287 return buildLookupResultForLanguage(theCode, language); 288 } 289 } 290 } 291 private LookupCodeResult buildLookupResultForLanguageAndRegion(@Nonnull String theOriginalCode, @Nonnull String theLanguage, @Nonnull String theRegion) { 292 LookupCodeResult lookupCodeResult = buildNotFoundLookupCodeResult(theOriginalCode); 293 lookupCodeResult.setCodeDisplay(theLanguage + " " + theRegion); 294 lookupCodeResult.setFound(true); 295 return lookupCodeResult; 296 } 297 private LookupCodeResult buildLookupResultForLanguage(@Nonnull String theOriginalCode, @Nonnull String theLanguage) { 298 LookupCodeResult lookupCodeResult = buildNotFoundLookupCodeResult(theOriginalCode); 299 lookupCodeResult.setCodeDisplay(theLanguage); 300 lookupCodeResult.setFound(true); 301 return lookupCodeResult; 302 } 303 304 private LookupCodeResult buildNotFoundLookupCodeResult(@Nonnull String theOriginalCode) { 305 LookupCodeResult lookupCodeResult = new LookupCodeResult(); 306 lookupCodeResult.setFound(false); 307 lookupCodeResult.setSearchedForSystem(LANGUAGES_CODESYSTEM_URL); 308 lookupCodeResult.setSearchedForCode(theOriginalCode); 309 return lookupCodeResult; 310 } 311 312 private void initializeBcp47LanguageMap() { 313 Map<String, String> regionsMap; 314 Map<String, String> languagesMap; 315 ourLog.info("Loading BCP47 Language Registry"); 316 317 String input = ClasspathUtil.loadResource("org/hl7/fhir/common/hapi/validation/support/registry.json"); 318 ArrayNode map; 319 try { 320 map = (ArrayNode) new ObjectMapper().readTree(input); 321 } catch (JsonProcessingException e) { 322 throw new ConfigurationException(Msg.code(694) + e); 323 } 324 325 languagesMap = new HashMap<>(); 326 regionsMap = new HashMap<>(); 327 328 for (int i = 0; i < map.size(); i++) { 329 ObjectNode next = (ObjectNode) map.get(i); 330 String type = next.get("Type").asText(); 331 if ("language".equals(type)) { 332 String language = next.get("Subtag").asText(); 333 ArrayNode descriptions = (ArrayNode) next.get("Description"); 334 String description = null; 335 if (descriptions.size() > 0) { 336 description = descriptions.get(0).asText(); 337 } 338 languagesMap.put(language, description); 339 } 340 if ("region".equals(type)) { 341 String region = next.get("Subtag").asText(); 342 ArrayNode descriptions = (ArrayNode) next.get("Description"); 343 String description = null; 344 if (descriptions.size() > 0) { 345 description = descriptions.get(0).asText(); 346 } 347 regionsMap.put(region, description); 348 } 349 } 350 351 ourLog.info("Have {} languages and {} regions", languagesMap.size(), regionsMap.size()); 352 353 myLanguagesLanugageMap = languagesMap; 354 myLanguagesRegionMap = regionsMap; 355 } 356 357 @Nonnull 358 private LookupCodeResult lookupMimetypeCode(String theCode) { 359 // This is a pretty naive implementation - Should be enhanced in future 360 LookupCodeResult mimeRetVal = new LookupCodeResult(); 361 mimeRetVal.setSearchedForCode(theCode); 362 mimeRetVal.setSearchedForSystem(MIMETYPES_CODESYSTEM_URL); 363 mimeRetVal.setFound(true); 364 return mimeRetVal; 365 } 366 367 @Nonnull 368 private LookupCodeResult lookupUcumCode(String theCode) { 369 InputStream input = ClasspathUtil.loadResourceAsStream("/ucum-essence.xml"); 370 String outcome = null; 371 try { 372 UcumEssenceService svc = new UcumEssenceService(input); 373 outcome = svc.analyse(theCode); 374 } catch (UcumException e) { 375 ourLog.warn("Failed parse UCUM code: {}", theCode, e); 376 } finally { 377 ClasspathUtil.close(input); 378 } 379 LookupCodeResult retVal = new LookupCodeResult(); 380 retVal.setSearchedForCode(theCode); 381 retVal.setSearchedForSystem(UCUM_CODESYSTEM_URL); 382 if (outcome != null) { 383 retVal.setFound(true); 384 retVal.setCodeDisplay(outcome); 385 } 386 return retVal; 387 } 388 389 @Override 390 public IBaseResource fetchCodeSystem(String theSystem) { 391 392 Map<String, String> map; 393 switch (defaultString(theSystem)) { 394 case COUNTRIES_CODESYSTEM_URL: 395 map = ISO_3166_CODES; 396 break; 397 case CURRENCIES_CODESYSTEM_URL: 398 map = ISO_4217_CODES; 399 break; 400 default: 401 return null; 402 } 403 404 CodeSystem retVal = new CodeSystem(); 405 retVal.setContent(CodeSystem.CodeSystemContentMode.COMPLETE); 406 retVal.setUrl(theSystem); 407 for (Map.Entry<String, String> nextEntry : map.entrySet()) { 408 retVal.addConcept().setCode(nextEntry.getKey()).setDisplay(nextEntry.getValue()); 409 } 410 411 IBaseResource normalized = null; 412 switch (getFhirContext().getVersion().getVersion()) { 413 case DSTU2: 414 case DSTU2_HL7ORG: 415 case DSTU2_1: 416 return null; 417 case DSTU3: 418 normalized = VersionConvertorFactory_30_40.convertResource(retVal, new BaseAdvisor_30_40(false)); 419 break; 420 case R4: 421 normalized = retVal; 422 break; 423 case R5: 424 normalized = VersionConvertorFactory_40_50.convertResource(retVal, new BaseAdvisor_40_50(false)); 425 break; 426 } 427 428 Validate.notNull(normalized); 429 430 return normalized; 431 } 432 433 @Override 434 public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { 435 436 switch (theSystem) { 437 case COUNTRIES_CODESYSTEM_URL: 438 case UCUM_CODESYSTEM_URL: 439 case MIMETYPES_CODESYSTEM_URL: 440 case USPS_CODESYSTEM_URL: 441 case LANGUAGES_CODESYSTEM_URL: 442 return true; 443 } 444 445 return false; 446 } 447 448 @Override 449 public boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) { 450 451 switch (theValueSetUrl) { 452 case CURRENCIES_VALUESET_URL: 453 case LANGUAGES_VALUESET_URL: 454 case ALL_LANGUAGES_VALUESET_URL: 455 case MIMETYPES_VALUESET_URL: 456 case UCUM_VALUESET_URL: 457 case USPS_VALUESET_URL: 458 return true; 459 } 460 461 return false; 462 } 463 464 @Override 465 public FhirContext getFhirContext() { 466 return myFhirContext; 467 } 468 469 public static String getValueSetUrl(@Nonnull IBaseResource theValueSet) { 470 String url; 471 switch (theValueSet.getStructureFhirVersionEnum()) { 472 case DSTU2: { 473 url = ((ca.uhn.fhir.model.dstu2.resource.ValueSet) theValueSet).getUrl(); 474 break; 475 } 476 case DSTU2_HL7ORG: { 477 url = ((ValueSet) theValueSet).getUrl(); 478 break; 479 } 480 case DSTU3: { 481 url = ((org.hl7.fhir.dstu3.model.ValueSet) theValueSet).getUrl(); 482 break; 483 } 484 case R4: { 485 url = ((org.hl7.fhir.r4.model.ValueSet) theValueSet).getUrl(); 486 break; 487 } 488 case R5: { 489 url = ((org.hl7.fhir.r5.model.ValueSet) theValueSet).getUrl(); 490 break; 491 } 492 case DSTU2_1: 493 default: 494 throw new IllegalArgumentException(Msg.code(695) + "Can not handle version: " + theValueSet.getStructureFhirVersionEnum()); 495 } 496 return url; 497 } 498 499 public static String getCodeSystemUrl(@Nonnull IBaseResource theCodeSystem) { 500 String url; 501 switch (theCodeSystem.getStructureFhirVersionEnum()) { 502 case R4: { 503 url = ((org.hl7.fhir.r4.model.CodeSystem) theCodeSystem).getUrl(); 504 break; 505 } 506 case R5: { 507 url = ((org.hl7.fhir.r5.model.CodeSystem) theCodeSystem).getUrl(); 508 break; 509 } 510 case DSTU3: 511 default: 512 throw new IllegalArgumentException(Msg.code(696) + "Can not handle version: " + theCodeSystem.getStructureFhirVersionEnum()); 513 } 514 return url; 515 } 516 517 public static String getValueSetVersion(@Nonnull IBaseResource theValueSet) { 518 String version; 519 switch (theValueSet.getStructureFhirVersionEnum()) { 520 case DSTU3: { 521 version = ((org.hl7.fhir.dstu3.model.ValueSet) theValueSet).getVersion(); 522 break; 523 } 524 case R4: { 525 version = ((org.hl7.fhir.r4.model.ValueSet) theValueSet).getVersion(); 526 break; 527 } 528 case R5: { 529 version = ((org.hl7.fhir.r5.model.ValueSet) theValueSet).getVersion(); 530 break; 531 } 532 case DSTU2: 533 case DSTU2_HL7ORG: 534 case DSTU2_1: 535 default: 536 version = null; 537 } 538 return version; 539 } 540 541 private static HashMap<String, String> buildUspsCodes() { 542 HashMap<String, String> uspsCodes = new HashMap<>(); 543 uspsCodes.put("AK", "Alaska"); 544 uspsCodes.put("AL", "Alabama"); 545 uspsCodes.put("AR", "Arkansas"); 546 uspsCodes.put("AS", "American Samoa"); 547 uspsCodes.put("AZ", "Arizona"); 548 uspsCodes.put("CA", "California"); 549 uspsCodes.put("CO", "Colorado"); 550 uspsCodes.put("CT", "Connecticut"); 551 uspsCodes.put("DC", "District of Columbia"); 552 uspsCodes.put("DE", "Delaware"); 553 uspsCodes.put("FL", "Florida"); 554 uspsCodes.put("FM", "Federated States of Micronesia"); 555 uspsCodes.put("GA", "Georgia"); 556 uspsCodes.put("GU", "Guam"); 557 uspsCodes.put("HI", "Hawaii"); 558 uspsCodes.put("IA", "Iowa"); 559 uspsCodes.put("ID", "Idaho"); 560 uspsCodes.put("IL", "Illinois"); 561 uspsCodes.put("IN", "Indiana"); 562 uspsCodes.put("KS", "Kansas"); 563 uspsCodes.put("KY", "Kentucky"); 564 uspsCodes.put("LA", "Louisiana"); 565 uspsCodes.put("MA", "Massachusetts"); 566 uspsCodes.put("MD", "Maryland"); 567 uspsCodes.put("ME", "Maine"); 568 uspsCodes.put("MH", "Marshall Islands"); 569 uspsCodes.put("MI", "Michigan"); 570 uspsCodes.put("MN", "Minnesota"); 571 uspsCodes.put("MO", "Missouri"); 572 uspsCodes.put("MP", "Northern Mariana Islands"); 573 uspsCodes.put("MS", "Mississippi"); 574 uspsCodes.put("MT", "Montana"); 575 uspsCodes.put("NC", "North Carolina"); 576 uspsCodes.put("ND", "North Dakota"); 577 uspsCodes.put("NE", "Nebraska"); 578 uspsCodes.put("NH", "New Hampshire"); 579 uspsCodes.put("NJ", "New Jersey"); 580 uspsCodes.put("NM", "New Mexico"); 581 uspsCodes.put("NV", "Nevada"); 582 uspsCodes.put("NY", "New York"); 583 uspsCodes.put("OH", "Ohio"); 584 uspsCodes.put("OK", "Oklahoma"); 585 uspsCodes.put("OR", "Oregon"); 586 uspsCodes.put("PA", "Pennsylvania"); 587 uspsCodes.put("PR", "Puerto Rico"); 588 uspsCodes.put("PW", "Palau"); 589 uspsCodes.put("RI", "Rhode Island"); 590 uspsCodes.put("SC", "South Carolina"); 591 uspsCodes.put("SD", "South Dakota"); 592 uspsCodes.put("TN", "Tennessee"); 593 uspsCodes.put("TX", "Texas"); 594 uspsCodes.put("UM", "U.S. Minor Outlying Islands"); 595 uspsCodes.put("UT", "Utah"); 596 uspsCodes.put("VA", "Virginia"); 597 uspsCodes.put("VI", "Virgin Islands of the U.S."); 598 uspsCodes.put("VT", "Vermont"); 599 uspsCodes.put("WA", "Washington"); 600 uspsCodes.put("WI", "Wisconsin"); 601 uspsCodes.put("WV", "West Virginia"); 602 uspsCodes.put("WY", "Wyoming"); 603 return uspsCodes; 604 } 605 606 private static HashMap<String, String> buildIso4217Codes() { 607 HashMap<String, String> iso4217Codes = new HashMap<>(); 608 iso4217Codes.put("AED", "United Arab Emirates dirham"); 609 iso4217Codes.put("AFN", "Afghan afghani"); 610 iso4217Codes.put("ALL", "Albanian lek"); 611 iso4217Codes.put("AMD", "Armenian dram"); 612 iso4217Codes.put("ANG", "Netherlands Antillean guilder"); 613 iso4217Codes.put("AOA", "Angolan kwanza"); 614 iso4217Codes.put("ARS", "Argentine peso"); 615 iso4217Codes.put("AUD", "Australian dollar"); 616 iso4217Codes.put("AWG", "Aruban florin"); 617 iso4217Codes.put("AZN", "Azerbaijani manat"); 618 iso4217Codes.put("BAM", "Bosnia and Herzegovina convertible mark"); 619 iso4217Codes.put("BBD", "Barbados dollar"); 620 iso4217Codes.put("BDT", "Bangladeshi taka"); 621 iso4217Codes.put("BGN", "Bulgarian lev"); 622 iso4217Codes.put("BHD", "Bahraini dinar"); 623 iso4217Codes.put("BIF", "Burundian franc"); 624 iso4217Codes.put("BMD", "Bermudian dollar"); 625 iso4217Codes.put("BND", "Brunei dollar"); 626 iso4217Codes.put("BOB", "Boliviano"); 627 iso4217Codes.put("BOV", "Bolivian Mvdol (funds code)"); 628 iso4217Codes.put("BRL", "Brazilian real"); 629 iso4217Codes.put("BSD", "Bahamian dollar"); 630 iso4217Codes.put("BTN", "Bhutanese ngultrum"); 631 iso4217Codes.put("BWP", "Botswana pula"); 632 iso4217Codes.put("BYN", "Belarusian ruble"); 633 iso4217Codes.put("BZD", "Belize dollar"); 634 iso4217Codes.put("CAD", "Canadian dollar"); 635 iso4217Codes.put("CDF", "Congolese franc"); 636 iso4217Codes.put("CHE", "WIR Euro (complementary currency)"); 637 iso4217Codes.put("CHF", "Swiss franc"); 638 iso4217Codes.put("CHW", "WIR Franc (complementary currency)"); 639 iso4217Codes.put("CLF", "Unidad de Fomento (funds code)"); 640 iso4217Codes.put("CLP", "Chilean peso"); 641 iso4217Codes.put("CNY", "Renminbi (Chinese) yuan[8]"); 642 iso4217Codes.put("COP", "Colombian peso"); 643 iso4217Codes.put("COU", "Unidad de Valor Real (UVR) (funds code)[9]"); 644 iso4217Codes.put("CRC", "Costa Rican colon"); 645 iso4217Codes.put("CUC", "Cuban convertible peso"); 646 iso4217Codes.put("CUP", "Cuban peso"); 647 iso4217Codes.put("CVE", "Cape Verde escudo"); 648 iso4217Codes.put("CZK", "Czech koruna"); 649 iso4217Codes.put("DJF", "Djiboutian franc"); 650 iso4217Codes.put("DKK", "Danish krone"); 651 iso4217Codes.put("DOP", "Dominican peso"); 652 iso4217Codes.put("DZD", "Algerian dinar"); 653 iso4217Codes.put("EGP", "Egyptian pound"); 654 iso4217Codes.put("ERN", "Eritrean nakfa"); 655 iso4217Codes.put("ETB", "Ethiopian birr"); 656 iso4217Codes.put("EUR", "Euro"); 657 iso4217Codes.put("FJD", "Fiji dollar"); 658 iso4217Codes.put("FKP", "Falkland Islands pound"); 659 iso4217Codes.put("GBP", "Pound sterling"); 660 iso4217Codes.put("GEL", "Georgian lari"); 661 iso4217Codes.put("GGP", "Guernsey Pound"); 662 iso4217Codes.put("GHS", "Ghanaian cedi"); 663 iso4217Codes.put("GIP", "Gibraltar pound"); 664 iso4217Codes.put("GMD", "Gambian dalasi"); 665 iso4217Codes.put("GNF", "Guinean franc"); 666 iso4217Codes.put("GTQ", "Guatemalan quetzal"); 667 iso4217Codes.put("GYD", "Guyanese dollar"); 668 iso4217Codes.put("HKD", "Hong Kong dollar"); 669 iso4217Codes.put("HNL", "Honduran lempira"); 670 iso4217Codes.put("HRK", "Croatian kuna"); 671 iso4217Codes.put("HTG", "Haitian gourde"); 672 iso4217Codes.put("HUF", "Hungarian forint"); 673 iso4217Codes.put("IDR", "Indonesian rupiah"); 674 iso4217Codes.put("ILS", "Israeli new shekel"); 675 iso4217Codes.put("IMP", "Isle of Man Pound"); 676 iso4217Codes.put("INR", "Indian rupee"); 677 iso4217Codes.put("IQD", "Iraqi dinar"); 678 iso4217Codes.put("IRR", "Iranian rial"); 679 iso4217Codes.put("ISK", "Icelandic króna"); 680 iso4217Codes.put("JEP", "Jersey Pound"); 681 iso4217Codes.put("JMD", "Jamaican dollar"); 682 iso4217Codes.put("JOD", "Jordanian dinar"); 683 iso4217Codes.put("JPY", "Japanese yen"); 684 iso4217Codes.put("KES", "Kenyan shilling"); 685 iso4217Codes.put("KGS", "Kyrgyzstani som"); 686 iso4217Codes.put("KHR", "Cambodian riel"); 687 iso4217Codes.put("KMF", "Comoro franc"); 688 iso4217Codes.put("KPW", "North Korean won"); 689 iso4217Codes.put("KRW", "South Korean won"); 690 iso4217Codes.put("KWD", "Kuwaiti dinar"); 691 iso4217Codes.put("KYD", "Cayman Islands dollar"); 692 iso4217Codes.put("KZT", "Kazakhstani tenge"); 693 iso4217Codes.put("LAK", "Lao kip"); 694 iso4217Codes.put("LBP", "Lebanese pound"); 695 iso4217Codes.put("LKR", "Sri Lankan rupee"); 696 iso4217Codes.put("LRD", "Liberian dollar"); 697 iso4217Codes.put("LSL", "Lesotho loti"); 698 iso4217Codes.put("LYD", "Libyan dinar"); 699 iso4217Codes.put("MAD", "Moroccan dirham"); 700 iso4217Codes.put("MDL", "Moldovan leu"); 701 iso4217Codes.put("MGA", "Malagasy ariary"); 702 iso4217Codes.put("MKD", "Macedonian denar"); 703 iso4217Codes.put("MMK", "Myanmar kyat"); 704 iso4217Codes.put("MNT", "Mongolian tögrög"); 705 iso4217Codes.put("MOP", "Macanese pataca"); 706 iso4217Codes.put("MRU", "Mauritanian ouguiya"); 707 iso4217Codes.put("MUR", "Mauritian rupee"); 708 iso4217Codes.put("MVR", "Maldivian rufiyaa"); 709 iso4217Codes.put("MWK", "Malawian kwacha"); 710 iso4217Codes.put("MXN", "Mexican peso"); 711 iso4217Codes.put("MXV", "Mexican Unidad de Inversion (UDI) (funds code)"); 712 iso4217Codes.put("MYR", "Malaysian ringgit"); 713 iso4217Codes.put("MZN", "Mozambican metical"); 714 iso4217Codes.put("NAD", "Namibian dollar"); 715 iso4217Codes.put("NGN", "Nigerian naira"); 716 iso4217Codes.put("NIO", "Nicaraguan córdoba"); 717 iso4217Codes.put("NOK", "Norwegian krone"); 718 iso4217Codes.put("NPR", "Nepalese rupee"); 719 iso4217Codes.put("NZD", "New Zealand dollar"); 720 iso4217Codes.put("OMR", "Omani rial"); 721 iso4217Codes.put("PAB", "Panamanian balboa"); 722 iso4217Codes.put("PEN", "Peruvian Sol"); 723 iso4217Codes.put("PGK", "Papua New Guinean kina"); 724 iso4217Codes.put("PHP", "Philippine piso[13]"); 725 iso4217Codes.put("PKR", "Pakistani rupee"); 726 iso4217Codes.put("PLN", "Polish złoty"); 727 iso4217Codes.put("PYG", "Paraguayan guaraní"); 728 iso4217Codes.put("QAR", "Qatari riyal"); 729 iso4217Codes.put("RON", "Romanian leu"); 730 iso4217Codes.put("RSD", "Serbian dinar"); 731 iso4217Codes.put("RUB", "Russian ruble"); 732 iso4217Codes.put("RWF", "Rwandan franc"); 733 iso4217Codes.put("SAR", "Saudi riyal"); 734 iso4217Codes.put("SBD", "Solomon Islands dollar"); 735 iso4217Codes.put("SCR", "Seychelles rupee"); 736 iso4217Codes.put("SDG", "Sudanese pound"); 737 iso4217Codes.put("SEK", "Swedish krona/kronor"); 738 iso4217Codes.put("SGD", "Singapore dollar"); 739 iso4217Codes.put("SHP", "Saint Helena pound"); 740 iso4217Codes.put("SLL", "Sierra Leonean leone"); 741 iso4217Codes.put("SOS", "Somali shilling"); 742 iso4217Codes.put("SRD", "Surinamese dollar"); 743 iso4217Codes.put("SSP", "South Sudanese pound"); 744 iso4217Codes.put("STN", "São Tomé and Príncipe dobra"); 745 iso4217Codes.put("SVC", "Salvadoran colón"); 746 iso4217Codes.put("SYP", "Syrian pound"); 747 iso4217Codes.put("SZL", "Swazi lilangeni"); 748 iso4217Codes.put("THB", "Thai baht"); 749 iso4217Codes.put("TJS", "Tajikistani somoni"); 750 iso4217Codes.put("TMT", "Turkmenistan manat"); 751 iso4217Codes.put("TND", "Tunisian dinar"); 752 iso4217Codes.put("TOP", "Tongan paʻanga"); 753 iso4217Codes.put("TRY", "Turkish lira"); 754 iso4217Codes.put("TTD", "Trinidad and Tobago dollar"); 755 iso4217Codes.put("TVD", "Tuvalu Dollar"); 756 iso4217Codes.put("TWD", "New Taiwan dollar"); 757 iso4217Codes.put("TZS", "Tanzanian shilling"); 758 iso4217Codes.put("UAH", "Ukrainian hryvnia"); 759 iso4217Codes.put("UGX", "Ugandan shilling"); 760 iso4217Codes.put("USD", "United States dollar"); 761 iso4217Codes.put("USN", "United States dollar (next day) (funds code)"); 762 iso4217Codes.put("UYI", "Uruguay Peso en Unidades Indexadas (URUIURUI) (funds code)"); 763 iso4217Codes.put("UYU", "Uruguayan peso"); 764 iso4217Codes.put("UZS", "Uzbekistan som"); 765 iso4217Codes.put("VEF", "Venezuelan bolívar"); 766 iso4217Codes.put("VND", "Vietnamese đồng"); 767 iso4217Codes.put("VUV", "Vanuatu vatu"); 768 iso4217Codes.put("WST", "Samoan tala"); 769 iso4217Codes.put("XAF", "CFA franc BEAC"); 770 iso4217Codes.put("XAG", "Silver (one troy ounce)"); 771 iso4217Codes.put("XAU", "Gold (one troy ounce)"); 772 iso4217Codes.put("XBA", "European Composite Unit (EURCO) (bond market unit)"); 773 iso4217Codes.put("XBB", "European Monetary Unit (E.M.U.-6) (bond market unit)"); 774 iso4217Codes.put("XBC", "European Unit of Account 9 (E.U.A.-9) (bond market unit)"); 775 iso4217Codes.put("XBD", "European Unit of Account 17 (E.U.A.-17) (bond market unit)"); 776 iso4217Codes.put("XCD", "East Caribbean dollar"); 777 iso4217Codes.put("XDR", "Special drawing rights"); 778 iso4217Codes.put("XOF", "CFA franc BCEAO"); 779 iso4217Codes.put("XPD", "Palladium (one troy ounce)"); 780 iso4217Codes.put("XPF", "CFP franc (franc Pacifique)"); 781 iso4217Codes.put("XPT", "Platinum (one troy ounce)"); 782 iso4217Codes.put("XSU", "SUCRE"); 783 iso4217Codes.put("XTS", "Code reserved for testing purposes"); 784 iso4217Codes.put("XUA", "ADB Unit of Account"); 785 iso4217Codes.put("XXX", "No currency"); 786 iso4217Codes.put("YER", "Yemeni rial"); 787 iso4217Codes.put("ZAR", "South African rand"); 788 iso4217Codes.put("ZMW", "Zambian kwacha"); 789 iso4217Codes.put("ZWL", "Zimbabwean dollar A/10"); 790 return iso4217Codes; 791 } 792 793 794 private static HashMap<String, String> buildIso3166Codes() { 795 HashMap<String, String> codes = new HashMap<>(); 796 797 // 2 letter codes 798 codes.put("AF", "Afghanistan"); 799 codes.put("AX", "Åland Islands"); 800 codes.put("AL", "Albania"); 801 codes.put("DZ", "Algeria"); 802 codes.put("AS", "American Samoa"); 803 codes.put("AD", "Andorra"); 804 codes.put("AO", "Angola"); 805 codes.put("AI", "Anguilla"); 806 codes.put("AQ", "Antarctica"); 807 codes.put("AG", "Antigua & Barbuda"); 808 codes.put("AR", "Argentina"); 809 codes.put("AM", "Armenia"); 810 codes.put("AW", "Aruba"); 811 codes.put("AU", "Australia"); 812 codes.put("AT", "Austria"); 813 codes.put("AZ", "Azerbaijan"); 814 codes.put("BS", "Bahamas"); 815 codes.put("BH", "Bahrain"); 816 codes.put("BD", "Bangladesh"); 817 codes.put("BB", "Barbados"); 818 codes.put("BY", "Belarus"); 819 codes.put("BE", "Belgium"); 820 codes.put("BZ", "Belize"); 821 codes.put("BJ", "Benin"); 822 codes.put("BM", "Bermuda"); 823 codes.put("BT", "Bhutan"); 824 codes.put("BO", "Bolivia"); 825 codes.put("BA", "Bosnia & Herzegovina"); 826 codes.put("BW", "Botswana"); 827 codes.put("BV", "Bouvet Island"); 828 codes.put("BR", "Brazil"); 829 codes.put("IO", "British Indian Ocean Territory"); 830 codes.put("VG", "British Virgin Islands"); 831 codes.put("BN", "Brunei"); 832 codes.put("BG", "Bulgaria"); 833 codes.put("BF", "Burkina Faso"); 834 codes.put("BI", "Burundi"); 835 codes.put("KH", "Cambodia"); 836 codes.put("CM", "Cameroon"); 837 codes.put("CA", "Canada"); 838 codes.put("CV", "Cape Verde"); 839 codes.put("BQ", "Caribbean Netherlands"); 840 codes.put("KY", "Cayman Islands"); 841 codes.put("CF", "Central African Republic"); 842 codes.put("TD", "Chad"); 843 codes.put("CL", "Chile"); 844 codes.put("CN", "China"); 845 codes.put("CX", "Christmas Island"); 846 codes.put("CC", "Cocos (Keeling) Islands"); 847 codes.put("CO", "Colombia"); 848 codes.put("KM", "Comoros"); 849 codes.put("CG", "Congo - Brazzaville"); 850 codes.put("CD", "Congo - Kinshasa"); 851 codes.put("CK", "Cook Islands"); 852 codes.put("CR", "Costa Rica"); 853 codes.put("CI", "Côte d’Ivoire"); 854 codes.put("HR", "Croatia"); 855 codes.put("CU", "Cuba"); 856 codes.put("CW", "Curaçao"); 857 codes.put("CY", "Cyprus"); 858 codes.put("CZ", "Czechia"); 859 codes.put("DK", "Denmark"); 860 codes.put("DJ", "Djibouti"); 861 codes.put("DM", "Dominica"); 862 codes.put("DO", "Dominican Republic"); 863 codes.put("EC", "Ecuador"); 864 codes.put("EG", "Egypt"); 865 codes.put("SV", "El Salvador"); 866 codes.put("GQ", "Equatorial Guinea"); 867 codes.put("ER", "Eritrea"); 868 codes.put("EE", "Estonia"); 869 codes.put("SZ", "Eswatini"); 870 codes.put("ET", "Ethiopia"); 871 codes.put("FK", "Falkland Islands"); 872 codes.put("FO", "Faroe Islands"); 873 codes.put("FJ", "Fiji"); 874 codes.put("FI", "Finland"); 875 codes.put("FR", "France"); 876 codes.put("GF", "French Guiana"); 877 codes.put("PF", "French Polynesia"); 878 codes.put("TF", "French Southern Territories"); 879 codes.put("GA", "Gabon"); 880 codes.put("GM", "Gambia"); 881 codes.put("GE", "Georgia"); 882 codes.put("DE", "Germany"); 883 codes.put("GH", "Ghana"); 884 codes.put("GI", "Gibraltar"); 885 codes.put("GR", "Greece"); 886 codes.put("GL", "Greenland"); 887 codes.put("GD", "Grenada"); 888 codes.put("GP", "Guadeloupe"); 889 codes.put("GU", "Guam"); 890 codes.put("GT", "Guatemala"); 891 codes.put("GG", "Guernsey"); 892 codes.put("GN", "Guinea"); 893 codes.put("GW", "Guinea-Bissau"); 894 codes.put("GY", "Guyana"); 895 codes.put("HT", "Haiti"); 896 codes.put("HM", "Heard & McDonald Islands"); 897 codes.put("HN", "Honduras"); 898 codes.put("HK", "Hong Kong SAR China"); 899 codes.put("HU", "Hungary"); 900 codes.put("IS", "Iceland"); 901 codes.put("IN", "India"); 902 codes.put("ID", "Indonesia"); 903 codes.put("IR", "Iran"); 904 codes.put("IQ", "Iraq"); 905 codes.put("IE", "Ireland"); 906 codes.put("IM", "Isle of Man"); 907 codes.put("IL", "Israel"); 908 codes.put("IT", "Italy"); 909 codes.put("JM", "Jamaica"); 910 codes.put("JP", "Japan"); 911 codes.put("JE", "Jersey"); 912 codes.put("JO", "Jordan"); 913 codes.put("KZ", "Kazakhstan"); 914 codes.put("KE", "Kenya"); 915 codes.put("KI", "Kiribati"); 916 codes.put("KW", "Kuwait"); 917 codes.put("KG", "Kyrgyzstan"); 918 codes.put("LA", "Laos"); 919 codes.put("LV", "Latvia"); 920 codes.put("LB", "Lebanon"); 921 codes.put("LS", "Lesotho"); 922 codes.put("LR", "Liberia"); 923 codes.put("LY", "Libya"); 924 codes.put("LI", "Liechtenstein"); 925 codes.put("LT", "Lithuania"); 926 codes.put("LU", "Luxembourg"); 927 codes.put("MO", "Macao SAR China"); 928 codes.put("MG", "Madagascar"); 929 codes.put("MW", "Malawi"); 930 codes.put("MY", "Malaysia"); 931 codes.put("MV", "Maldives"); 932 codes.put("ML", "Mali"); 933 codes.put("MT", "Malta"); 934 codes.put("MH", "Marshall Islands"); 935 codes.put("MQ", "Martinique"); 936 codes.put("MR", "Mauritania"); 937 codes.put("MU", "Mauritius"); 938 codes.put("YT", "Mayotte"); 939 codes.put("MX", "Mexico"); 940 codes.put("FM", "Micronesia"); 941 codes.put("MD", "Moldova"); 942 codes.put("MC", "Monaco"); 943 codes.put("MN", "Mongolia"); 944 codes.put("ME", "Montenegro"); 945 codes.put("MS", "Montserrat"); 946 codes.put("MA", "Morocco"); 947 codes.put("MZ", "Mozambique"); 948 codes.put("MM", "Myanmar (Burma)"); 949 codes.put("NA", "Namibia"); 950 codes.put("NR", "Nauru"); 951 codes.put("NP", "Nepal"); 952 codes.put("NL", "Netherlands"); 953 codes.put("NC", "New Caledonia"); 954 codes.put("NZ", "New Zealand"); 955 codes.put("NI", "Nicaragua"); 956 codes.put("NE", "Niger"); 957 codes.put("NG", "Nigeria"); 958 codes.put("NU", "Niue"); 959 codes.put("NF", "Norfolk Island"); 960 codes.put("KP", "North Korea"); 961 codes.put("MK", "North Macedonia"); 962 codes.put("MP", "Northern Mariana Islands"); 963 codes.put("NO", "Norway"); 964 codes.put("OM", "Oman"); 965 codes.put("PK", "Pakistan"); 966 codes.put("PW", "Palau"); 967 codes.put("PS", "Palestinian Territories"); 968 codes.put("PA", "Panama"); 969 codes.put("PG", "Papua New Guinea"); 970 codes.put("PY", "Paraguay"); 971 codes.put("PE", "Peru"); 972 codes.put("PH", "Philippines"); 973 codes.put("PN", "Pitcairn Islands"); 974 codes.put("PL", "Poland"); 975 codes.put("PT", "Portugal"); 976 codes.put("PR", "Puerto Rico"); 977 codes.put("QA", "Qatar"); 978 codes.put("RE", "Réunion"); 979 codes.put("RO", "Romania"); 980 codes.put("RU", "Russia"); 981 codes.put("RW", "Rwanda"); 982 codes.put("WS", "Samoa"); 983 codes.put("SM", "San Marino"); 984 codes.put("ST", "São Tomé & Príncipe"); 985 codes.put("SA", "Saudi Arabia"); 986 codes.put("SN", "Senegal"); 987 codes.put("RS", "Serbia"); 988 codes.put("SC", "Seychelles"); 989 codes.put("SL", "Sierra Leone"); 990 codes.put("SG", "Singapore"); 991 codes.put("SX", "Sint Maarten"); 992 codes.put("SK", "Slovakia"); 993 codes.put("SI", "Slovenia"); 994 codes.put("SB", "Solomon Islands"); 995 codes.put("SO", "Somalia"); 996 codes.put("ZA", "South Africa"); 997 codes.put("GS", "South Georgia & South Sandwich Islands"); 998 codes.put("KR", "South Korea"); 999 codes.put("SS", "South Sudan"); 1000 codes.put("ES", "Spain"); 1001 codes.put("LK", "Sri Lanka"); 1002 codes.put("BL", "St. Barthélemy"); 1003 codes.put("SH", "St. Helena"); 1004 codes.put("KN", "St. Kitts & Nevis"); 1005 codes.put("LC", "St. Lucia"); 1006 codes.put("MF", "St. Martin"); 1007 codes.put("PM", "St. Pierre & Miquelon"); 1008 codes.put("VC", "St. Vincent & Grenadines"); 1009 codes.put("SD", "Sudan"); 1010 codes.put("SR", "Suriname"); 1011 codes.put("SJ", "Svalbard & Jan Mayen"); 1012 codes.put("SE", "Sweden"); 1013 codes.put("CH", "Switzerland"); 1014 codes.put("SY", "Syria"); 1015 codes.put("TW", "Taiwan"); 1016 codes.put("TJ", "Tajikistan"); 1017 codes.put("TZ", "Tanzania"); 1018 codes.put("TH", "Thailand"); 1019 codes.put("TL", "Timor-Leste"); 1020 codes.put("TG", "Togo"); 1021 codes.put("TK", "Tokelau"); 1022 codes.put("TO", "Tonga"); 1023 codes.put("TT", "Trinidad & Tobago"); 1024 codes.put("TN", "Tunisia"); 1025 codes.put("TR", "Turkey"); 1026 codes.put("TM", "Turkmenistan"); 1027 codes.put("TC", "Turks & Caicos Islands"); 1028 codes.put("TV", "Tuvalu"); 1029 codes.put("UM", "U.S. Outlying Islands"); 1030 codes.put("VI", "U.S. Virgin Islands"); 1031 codes.put("UG", "Uganda"); 1032 codes.put("UA", "Ukraine"); 1033 codes.put("AE", "United Arab Emirates"); 1034 codes.put("GB", "United Kingdom"); 1035 codes.put("US", "United States"); 1036 codes.put("UY", "Uruguay"); 1037 codes.put("UZ", "Uzbekistan"); 1038 codes.put("VU", "Vanuatu"); 1039 codes.put("VA", "Vatican City"); 1040 codes.put("VE", "Venezuela"); 1041 codes.put("VN", "Vietnam"); 1042 codes.put("WF", "Wallis & Futuna"); 1043 codes.put("EH", "Western Sahara"); 1044 codes.put("YE", "Yemen"); 1045 codes.put("ZM", "Zambia"); 1046 codes.put("ZW", "Zimbabwe"); 1047 1048 // 3 letter codes 1049 codes.put("ABW", "Aruba"); 1050 codes.put("AFG", "Afghanistan"); 1051 codes.put("AGO", "Angola"); 1052 codes.put("AIA", "Anguilla"); 1053 codes.put("ALA", "Åland Islands"); 1054 codes.put("ALB", "Albania"); 1055 codes.put("AND", "Andorra"); 1056 codes.put("ARE", "United Arab Emirates"); 1057 codes.put("ARG", "Argentina"); 1058 codes.put("ARM", "Armenia"); 1059 codes.put("ASM", "American Samoa"); 1060 codes.put("ATA", "Antarctica"); 1061 codes.put("ATF", "French Southern Territories"); 1062 codes.put("ATG", "Antigua and Barbuda"); 1063 codes.put("AUS", "Australia"); 1064 codes.put("AUT", "Austria"); 1065 codes.put("AZE", "Azerbaijan"); 1066 codes.put("BDI", "Burundi"); 1067 codes.put("BEL", "Belgium"); 1068 codes.put("BEN", "Benin"); 1069 codes.put("BES", "Bonaire, Sint Eustatius and Saba"); 1070 codes.put("BFA", "Burkina Faso"); 1071 codes.put("BGD", "Bangladesh"); 1072 codes.put("BGR", "Bulgaria"); 1073 codes.put("BHR", "Bahrain"); 1074 codes.put("BHS", "Bahamas"); 1075 codes.put("BIH", "Bosnia and Herzegovina"); 1076 codes.put("BLM", "Saint Barthélemy"); 1077 codes.put("BLR", "Belarus"); 1078 codes.put("BLZ", "Belize"); 1079 codes.put("BMU", "Bermuda"); 1080 codes.put("BOL", "Bolivia, Plurinational State of"); 1081 codes.put("BRA", "Brazil"); 1082 codes.put("BRB", "Barbados"); 1083 codes.put("BRN", "Brunei Darussalam"); 1084 codes.put("BTN", "Bhutan"); 1085 codes.put("BVT", "Bouvet Island"); 1086 codes.put("BWA", "Botswana"); 1087 codes.put("CAF", "Central African Republic"); 1088 codes.put("CAN", "Canada"); 1089 codes.put("CCK", "Cocos (Keeling) Islands"); 1090 codes.put("CHE", "Switzerland"); 1091 codes.put("CHL", "Chile"); 1092 codes.put("CHN", "China"); 1093 codes.put("CIV", "Côte d'Ivoire"); 1094 codes.put("CMR", "Cameroon"); 1095 codes.put("COD", "Congo, the Democratic Republic of the"); 1096 codes.put("COG", "Congo"); 1097 codes.put("COK", "Cook Islands"); 1098 codes.put("COL", "Colombia"); 1099 codes.put("COM", "Comoros"); 1100 codes.put("CPV", "Cabo Verde"); 1101 codes.put("CRI", "Costa Rica"); 1102 codes.put("CUB", "Cuba"); 1103 codes.put("CUW", "Curaçao"); 1104 codes.put("CXR", "Christmas Island"); 1105 codes.put("CYM", "Cayman Islands"); 1106 codes.put("CYP", "Cyprus"); 1107 codes.put("CZE", "Czechia"); 1108 codes.put("DEU", "Germany"); 1109 codes.put("DJI", "Djibouti"); 1110 codes.put("DMA", "Dominica"); 1111 codes.put("DNK", "Denmark"); 1112 codes.put("DOM", "Dominican Republic"); 1113 codes.put("DZA", "Algeria"); 1114 codes.put("ECU", "Ecuador"); 1115 codes.put("EGY", "Egypt"); 1116 codes.put("ERI", "Eritrea"); 1117 codes.put("ESH", "Western Sahara"); 1118 codes.put("ESP", "Spain"); 1119 codes.put("EST", "Estonia"); 1120 codes.put("ETH", "Ethiopia"); 1121 codes.put("FIN", "Finland"); 1122 codes.put("FJI", "Fiji"); 1123 codes.put("FLK", "Falkland Islands (Malvinas)"); 1124 codes.put("FRA", "France"); 1125 codes.put("FRO", "Faroe Islands"); 1126 codes.put("FSM", "Micronesia, Federated States of"); 1127 codes.put("GAB", "Gabon"); 1128 codes.put("GBR", "United Kingdom"); 1129 codes.put("GEO", "Georgia"); 1130 codes.put("GGY", "Guernsey"); 1131 codes.put("GHA", "Ghana"); 1132 codes.put("GIB", "Gibraltar"); 1133 codes.put("GIN", "Guinea"); 1134 codes.put("GLP", "Guadeloupe"); 1135 codes.put("GMB", "Gambia"); 1136 codes.put("GNB", "Guinea-Bissau"); 1137 codes.put("GNQ", "Equatorial Guinea"); 1138 codes.put("GRC", "Greece"); 1139 codes.put("GRD", "Grenada"); 1140 codes.put("GRL", "Greenland"); 1141 codes.put("GTM", "Guatemala"); 1142 codes.put("GUF", "French Guiana"); 1143 codes.put("GUM", "Guam"); 1144 codes.put("GUY", "Guyana"); 1145 codes.put("HKG", "Hong Kong"); 1146 codes.put("HMD", "Heard Island and McDonald Islands"); 1147 codes.put("HND", "Honduras"); 1148 codes.put("HRV", "Croatia"); 1149 codes.put("HTI", "Haiti"); 1150 codes.put("HUN", "Hungary"); 1151 codes.put("IDN", "Indonesia"); 1152 codes.put("IMN", "Isle of Man"); 1153 codes.put("IND", "India"); 1154 codes.put("IOT", "British Indian Ocean Territory"); 1155 codes.put("IRL", "Ireland"); 1156 codes.put("IRN", "Iran, Islamic Republic of"); 1157 codes.put("IRQ", "Iraq"); 1158 codes.put("ISL", "Iceland"); 1159 codes.put("ISR", "Israel"); 1160 codes.put("ITA", "Italy"); 1161 codes.put("JAM", "Jamaica"); 1162 codes.put("JEY", "Jersey"); 1163 codes.put("JOR", "Jordan"); 1164 codes.put("JPN", "Japan"); 1165 codes.put("KAZ", "Kazakhstan"); 1166 codes.put("KEN", "Kenya"); 1167 codes.put("KGZ", "Kyrgyzstan"); 1168 codes.put("KHM", "Cambodia"); 1169 codes.put("KIR", "Kiribati"); 1170 codes.put("KNA", "Saint Kitts and Nevis"); 1171 codes.put("KOR", "Korea, Republic of"); 1172 codes.put("KWT", "Kuwait"); 1173 codes.put("LAO", "Lao People's Democratic Republic"); 1174 codes.put("LBN", "Lebanon"); 1175 codes.put("LBR", "Liberia"); 1176 codes.put("LBY", "Libya"); 1177 codes.put("LCA", "Saint Lucia"); 1178 codes.put("LIE", "Liechtenstein"); 1179 codes.put("LKA", "Sri Lanka"); 1180 codes.put("LSO", "Lesotho"); 1181 codes.put("LTU", "Lithuania"); 1182 codes.put("LUX", "Luxembourg"); 1183 codes.put("LVA", "Latvia"); 1184 codes.put("MAC", "Macao"); 1185 codes.put("MAF", "Saint Martin (French part)"); 1186 codes.put("MAR", "Morocco"); 1187 codes.put("MCO", "Monaco"); 1188 codes.put("MDA", "Moldova, Republic of"); 1189 codes.put("MDG", "Madagascar"); 1190 codes.put("MDV", "Maldives"); 1191 codes.put("MEX", "Mexico"); 1192 codes.put("MHL", "Marshall Islands"); 1193 codes.put("MKD", "Macedonia, the former Yugoslav Republic of"); 1194 codes.put("MLI", "Mali"); 1195 codes.put("MLT", "Malta"); 1196 codes.put("MMR", "Myanmar"); 1197 codes.put("MNE", "Montenegro"); 1198 codes.put("MNG", "Mongolia"); 1199 codes.put("MNP", "Northern Mariana Islands"); 1200 codes.put("MOZ", "Mozambique"); 1201 codes.put("MRT", "Mauritania"); 1202 codes.put("MSR", "Montserrat"); 1203 codes.put("MTQ", "Martinique"); 1204 codes.put("MUS", "Mauritius"); 1205 codes.put("MWI", "Malawi"); 1206 codes.put("MYS", "Malaysia"); 1207 codes.put("MYT", "Mayotte"); 1208 codes.put("NAM", "Namibia"); 1209 codes.put("NCL", "New Caledonia"); 1210 codes.put("NER", "Niger"); 1211 codes.put("NFK", "Norfolk Island"); 1212 codes.put("NGA", "Nigeria"); 1213 codes.put("NIC", "Nicaragua"); 1214 codes.put("NIU", "Niue"); 1215 codes.put("NLD", "Netherlands"); 1216 codes.put("NOR", "Norway"); 1217 codes.put("NPL", "Nepal"); 1218 codes.put("NRU", "Nauru"); 1219 codes.put("NZL", "New Zealand"); 1220 codes.put("OMN", "Oman"); 1221 codes.put("PAK", "Pakistan"); 1222 codes.put("PAN", "Panama"); 1223 codes.put("PCN", "Pitcairn"); 1224 codes.put("PER", "Peru"); 1225 codes.put("PHL", "Philippines"); 1226 codes.put("PLW", "Palau"); 1227 codes.put("PNG", "Papua New Guinea"); 1228 codes.put("POL", "Poland"); 1229 codes.put("PRI", "Puerto Rico"); 1230 codes.put("PRK", "Korea, Democratic People's Republic of"); 1231 codes.put("PRT", "Portugal"); 1232 codes.put("PRY", "Paraguay"); 1233 codes.put("PSE", "Palestine, State of"); 1234 codes.put("PYF", "French Polynesia"); 1235 codes.put("QAT", "Qatar"); 1236 codes.put("REU", "Réunion"); 1237 codes.put("ROU", "Romania"); 1238 codes.put("RUS", "Russian Federation"); 1239 codes.put("RWA", "Rwanda"); 1240 codes.put("SAU", "Saudi Arabia"); 1241 codes.put("SDN", "Sudan"); 1242 codes.put("SEN", "Senegal"); 1243 codes.put("SGP", "Singapore"); 1244 codes.put("SGS", "South Georgia and the South Sandwich Islands"); 1245 codes.put("SHN", "Saint Helena, Ascension and Tristan da Cunha"); 1246 codes.put("SJM", "Svalbard and Jan Mayen"); 1247 codes.put("SLB", "Solomon Islands"); 1248 codes.put("SLE", "Sierra Leone"); 1249 codes.put("SLV", "El Salvador"); 1250 codes.put("SMR", "San Marino"); 1251 codes.put("SOM", "Somalia"); 1252 codes.put("SPM", "Saint Pierre and Miquelon"); 1253 codes.put("SRB", "Serbia"); 1254 codes.put("SSD", "South Sudan"); 1255 codes.put("STP", "Sao Tome and Principe"); 1256 codes.put("SUR", "Suriname"); 1257 codes.put("SVK", "Slovakia"); 1258 codes.put("SVN", "Slovenia"); 1259 codes.put("SWE", "Sweden"); 1260 codes.put("SWZ", "Swaziland"); 1261 codes.put("SXM", "Sint Maarten (Dutch part)"); 1262 codes.put("SYC", "Seychelles"); 1263 codes.put("SYR", "Syrian Arab Republic"); 1264 codes.put("TCA", "Turks and Caicos Islands"); 1265 codes.put("TCD", "Chad"); 1266 codes.put("TGO", "Togo"); 1267 codes.put("THA", "Thailand"); 1268 codes.put("TJK", "Tajikistan"); 1269 codes.put("TKL", "Tokelau"); 1270 codes.put("TKM", "Turkmenistan"); 1271 codes.put("TLS", "Timor-Leste"); 1272 codes.put("TON", "Tonga"); 1273 codes.put("TTO", "Trinidad and Tobago"); 1274 codes.put("TUN", "Tunisia"); 1275 codes.put("TUR", "Turkey"); 1276 codes.put("TUV", "Tuvalu"); 1277 codes.put("TWN", "Taiwan, Province of China"); 1278 codes.put("TZA", "Tanzania, United Republic of"); 1279 codes.put("UGA", "Uganda"); 1280 codes.put("UKR", "Ukraine"); 1281 codes.put("UMI", "United States Minor Outlying Islands"); 1282 codes.put("URY", "Uruguay"); 1283 codes.put("USA", "United States of America"); 1284 codes.put("UZB", "Uzbekistan"); 1285 codes.put("VAT", "Holy See"); 1286 codes.put("VCT", "Saint Vincent and the Grenadines"); 1287 codes.put("VEN", "Venezuela, Bolivarian Republic of"); 1288 codes.put("VGB", "Virgin Islands, British"); 1289 codes.put("VIR", "Virgin Islands, U.S."); 1290 codes.put("VNM", "Viet Nam"); 1291 codes.put("VUT", "Vanuatu"); 1292 codes.put("WLF", "Wallis and Futuna"); 1293 codes.put("WSM", "Samoa"); 1294 codes.put("YEM", "Yemen"); 1295 codes.put("ZAF", "South Africa"); 1296 codes.put("ZMB", "Zambia"); 1297 codes.put("ZWE", "Zimbabwe"); 1298 return codes; 1299 } 1300 1301}