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