diff options
author | Fredrik Roubert <roubert@google.com> | 2018-07-09 12:38:00 +0200 |
---|---|---|
committer | Fredrik Roubert <roubert@google.com> | 2018-07-09 12:38:00 +0200 |
commit | 916131948aa91e4ad53c3f359daa1037518595b9 (patch) | |
tree | dfb69acf5fe0e20b1d79313ff3916d5092334a2f /tools/java/org | |
parent | 178614513228a6e8143bc010170f4f3a087f1e39 (diff) | |
parent | 1cc09cde2a712b3e802585d933d14fd5f7bd4860 (diff) | |
download | android_external_cldr-916131948aa91e4ad53c3f359daa1037518595b9.tar.gz android_external_cldr-916131948aa91e4ad53c3f359daa1037518595b9.tar.bz2 android_external_cldr-916131948aa91e4ad53c3f359daa1037518595b9.zip |
Merge remote-tracking branch 'aosp/cldr-release-33-1' into aosp/master.
This updates AOSP to CLDR 33.1 in preparation for the ICU 62.1 upgrade.
Bug: 111246576
Change-Id: I391323aa1215dd9cc021987e9f98251da9760381
Diffstat (limited to 'tools/java/org')
21 files changed, 1619 insertions, 695 deletions
diff --git a/tools/java/org/unicode/cldr/draft/ScriptMetadata.java b/tools/java/org/unicode/cldr/draft/ScriptMetadata.java index 44d6ba0..6921faf 100644 --- a/tools/java/org/unicode/cldr/draft/ScriptMetadata.java +++ b/tools/java/org/unicode/cldr/draft/ScriptMetadata.java @@ -305,13 +305,21 @@ public class ScriptMetadata { } public enum Groupings { - EUROPEAN("150"), MIDDLE_EASTERN("145"), SOUTH_ASIAN("034"), SOUTHEAST_ASIAN("035"), EAST_ASIAN("030"), AFRICAN("002"), AMERICAN("019"),; + EUROPEAN("150"), + MIDDLE_EASTERN("145"), + CENTRAL_ASIAN("143"), + SOUTH_ASIAN("034"), + SOUTHEAST_ASIAN("035"), + EAST_ASIAN("030"), + AFRICAN("002"), + AMERICAN("019"),; public final Set<String> scripts; private Groupings(String... regions) { scripts = With .in(getScripts()) - .toUnmodifiableCollection(new ScriptMetadata.RegionFilter(regions), new TreeSet()); + .toUnmodifiableCollection( + new ScriptMetadata.RegionFilter(regions), new TreeSet<String>()); } } diff --git a/tools/java/org/unicode/cldr/test/CheckCLDR.java b/tools/java/org/unicode/cldr/test/CheckCLDR.java index 831ed93..78a4c8b 100644 --- a/tools/java/org/unicode/cldr/test/CheckCLDR.java +++ b/tools/java/org/unicode/cldr/test/CheckCLDR.java @@ -696,7 +696,7 @@ abstract public class CheckCLDR { charactersNotInCurrencyExemplars, asciiCharactersNotInCurrencyExemplars, charactersNotInMainOrAuxiliaryExemplars, asciiCharactersNotInMainOrAuxiliaryExemplars, - narrowDateFieldTooWide, illegalCharactersInExemplars, orientationDisagreesWithExemplars, inconsistentDatePattern, inconsistentTimePattern, missingDatePattern, illegalDatePattern, missingMainExemplars, mustNotStartOrEndWithSpace, illegalCharactersInNumberPattern, numberPatternNotCanonical, currencyPatternMissingCurrencySymbol, missingMinusSign, badNumericType, percentPatternMissingPercentSymbol, illegalNumberFormat, unexpectedAttributeValue, metazoneContainsDigit, tooManyGroupingSeparators, inconsistentPluralFormat, sameAsEnglishOrCode, dateSymbolCollision, incompleteLogicalGroup, extraMetazoneString, inconsistentDraftStatus, errorOrWarningInLogicalGroup, valueTooWide, valueTooNarrow, nameContainsYear, patternCannotContainDigits, patternContainsInvalidCharacters, parenthesesNotAllowed, illegalNumberingSystem, unexpectedOrderOfEraYear, invalidPlaceHolder, asciiQuotesNotAllowed, badMinimumGroupingDigits, inconsistentPeriods, inheritanceMarkerNotAllowed, invalidDurationUnitPattern, invalidDelimiter, illegalCharactersInPattern, badParseLenient; + narrowDateFieldTooWide, illegalCharactersInExemplars, orientationDisagreesWithExemplars, inconsistentDatePattern, inconsistentTimePattern, missingDatePattern, illegalDatePattern, missingMainExemplars, mustNotStartOrEndWithSpace, illegalCharactersInNumberPattern, numberPatternNotCanonical, currencyPatternMissingCurrencySymbol, missingMinusSign, badNumericType, percentPatternMissingPercentSymbol, illegalNumberFormat, unexpectedAttributeValue, metazoneContainsDigit, tooManyGroupingSeparators, inconsistentPluralFormat, sameAsEnglishOrCode, dateSymbolCollision, incompleteLogicalGroup, extraMetazoneString, inconsistentDraftStatus, errorOrWarningInLogicalGroup, valueTooWide, valueTooNarrow, nameContainsYear, patternCannotContainDigits, patternContainsInvalidCharacters, parenthesesNotAllowed, illegalNumberingSystem, unexpectedOrderOfEraYear, invalidPlaceHolder, asciiQuotesNotAllowed, badMinimumGroupingDigits, inconsistentPeriods, inheritanceMarkerNotAllowed, invalidDurationUnitPattern, invalidDelimiter, illegalCharactersInPattern, badParseLenient, tooManyValues; public String toString() { return TO_STRING.matcher(name()).replaceAll(" $1").toLowerCase(); diff --git a/tools/java/org/unicode/cldr/test/CheckWidths.java b/tools/java/org/unicode/cldr/test/CheckWidths.java index fd3687c..d8366b5 100644 --- a/tools/java/org/unicode/cldr/test/CheckWidths.java +++ b/tools/java/org/unicode/cldr/test/CheckWidths.java @@ -19,6 +19,8 @@ public class CheckWidths extends CheckCLDR { private static CoverageLevel2 coverageLevel; private Level requiredLevel; + public static final int MAX_COMPONENTS_PER_ANNOTATION = 16; + SupplementalDataInfo supplementalData; private static final double EM = ApproximateWidth.getWidth("ๆ"); @@ -26,7 +28,7 @@ public class CheckWidths extends CheckCLDR { private static final boolean DEBUG = true; private enum Measure { - CODE_POINTS, DISPLAY_WIDTH + CODE_POINTS, DISPLAY_WIDTH, SET_ELEMENTS } private enum LimitType { @@ -34,7 +36,7 @@ public class CheckWidths extends CheckCLDR { } private enum Special { - NONE, QUOTES, PLACEHOLDERS, NUMBERSYMBOLS, NUMBERFORMAT + NONE, QUOTES, PLACEHOLDERS, NUMBERSYMBOLS, NUMBERFORMAT, BARS } private static final Pattern PLACEHOLDER_PATTERN = PatternCache.get("\\{\\d\\}"); @@ -58,16 +60,35 @@ public class CheckWidths extends CheckCLDR { this.special = special; switch (limit) { case MINIMUM: - this.message = measure == Measure.CODE_POINTS - ? "Expected no fewer than {0} character(s), but was {1}." - : "Too narrow by about {2}% (with common fonts)."; this.subtype = Subtype.valueTooNarrow; + switch (measure) { + case CODE_POINTS: + this.message = "Expected no fewer than {0} character(s), but was {1}."; + break; + case DISPLAY_WIDTH: + this.message = "Too narrow by about {2}% (with common fonts)."; + break; + default: + throw new IllegalArgumentException(); + } break; case MAXIMUM: - this.message = measure == Measure.CODE_POINTS - ? "Expected no more than {0} character(s), but was {1}." - : "Too wide by about {2}% (with common fonts)."; - this.subtype = Subtype.valueTooWide; + switch (measure) { + case CODE_POINTS: + this.message = "Expected no more than {0} character(s), but was {1}."; + this.subtype = Subtype.valueTooWide; + break; + case DISPLAY_WIDTH: + this.message = "Too wide by about {2}% (with common fonts)."; + this.subtype = Subtype.valueTooWide; + break; + case SET_ELEMENTS: + this.message = "Expected no more than {0} items(s), but was {1}."; + this.subtype = Subtype.tooManyValues; + break; + default: + throw new IllegalArgumentException(); + } break; default: throw new IllegalArgumentException(); @@ -95,9 +116,13 @@ public class CheckWidths extends CheckCLDR { case NUMBERSYMBOLS: value = value.replaceAll("[\u200E\u200F\u061C]", ""); // don't include LRM/RLM/ALM when checking length of number symbols break; + case BARS: + value = value.replaceAll("[^|]", "")+"|"; // Check the number of items by counting separators. Bit of a hack... + break; default: } - double valueMeasure = measure == Measure.CODE_POINTS ? value.codePointCount(0, value.length()) : ApproximateWidth.getWidth(value); + double valueMeasure = measure == Measure.DISPLAY_WIDTH ? ApproximateWidth.getWidth(value) + : value.codePointCount(0, value.length()) ; CheckStatus.Type errorType = CheckStatus.warningType; switch (limit) { case MINIMUM: @@ -113,7 +138,13 @@ public class CheckWidths extends CheckCLDR { return false; } if (valueMeasure > errorReference && cause.getPhase() != Phase.BUILD && !aliasedAndComprenehsive) { - errorType = CheckStatus.errorType; + // Workaround for ST submission phase only per TC discussion 2018-05-30 + // Make too many keywords be only a warning until we decide policy (JCE) + if (cause.getPhase() == Phase.SUBMISSION && measure.equals(Measure.SET_ELEMENTS)) { + errorType = CheckStatus.warningType; + } else { + errorType = CheckStatus.errorType; + } } break; } @@ -240,7 +271,7 @@ public class CheckWidths extends CheckCLDR { .add("//ldml/numbers/decimalFormats[@numberSystem=%A]/decimalFormatLength[@type=\"short\"]/decimalFormat[@type=%A]/pattern[@type=\"1", new Limit[] { new Limit(4 * EM, 5 * EM, Measure.DISPLAY_WIDTH, LimitType.MAXIMUM, Special.NUMBERFORMAT) - }) + }) // Catch -future/past Narrow units and allow much wider values .add("//ldml/units/unitLength[@type=\"narrow\"]/unit[@type=\"[^\"]+-(future|past)\"]/unitPattern", new Limit[] { new Limit(10 * EM, 15 * EM, Measure.DISPLAY_WIDTH, LimitType.MAXIMUM, Special.PLACEHOLDERS) @@ -270,8 +301,12 @@ public class CheckWidths extends CheckCLDR { // "grinning cat face with smiling eyes" should be normal max ~= 160 em // emoji names (not keywords) .add("//ldml/annotations/annotation[@cp=%A][@type=%A]", new Limit[] { - new Limit(20 * EM, 100 * EM, Measure.DISPLAY_WIDTH, LimitType.MAXIMUM, Special.NONE) - }); + new Limit(20 * EM, 100 * EM, Measure.DISPLAY_WIDTH, LimitType.MAXIMUM, Special.NONE), + }) + .add("//ldml/annotations/annotation[@cp=%A]", new Limit[] { + new Limit(5, MAX_COMPONENTS_PER_ANNOTATION, Measure.SET_ELEMENTS, LimitType.MAXIMUM, Special.BARS) // Allow up to 5 with no warning, up to 7 with no error. + }) + ; static { System.out.println("EMs: " + ApproximateWidth.getWidth("grinning cat face with smiling eyes")); diff --git a/tools/java/org/unicode/cldr/test/EmojiSubdivisionNames.java b/tools/java/org/unicode/cldr/test/EmojiSubdivisionNames.java new file mode 100644 index 0000000..b678c85 --- /dev/null +++ b/tools/java/org/unicode/cldr/test/EmojiSubdivisionNames.java @@ -0,0 +1,146 @@ +package org.unicode.cldr.test; + +import java.io.File; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.unicode.cldr.draft.FileUtilities; +import org.unicode.cldr.util.CLDRConfig; +import org.unicode.cldr.util.CLDRFile; +import org.unicode.cldr.util.CLDRPaths; +import org.unicode.cldr.util.EmojiConstants; +import org.unicode.cldr.util.LanguageGroup; +import org.unicode.cldr.util.LocaleIDParser; +import org.unicode.cldr.util.Organization; +import org.unicode.cldr.util.StandardCodes; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSortedSet; +import com.ibm.icu.util.ULocale; + +public class EmojiSubdivisionNames { + private static final String subdivisionPathPrefix = "//ldml/localeDisplayNames/subdivisions/subdivision[@type=\""; + private static final String subdivisionPathSuffix = "\"]"; + private static final Map<String,Map<String,String>> localeToNameToSubdivisionId = new ConcurrentHashMap<>(); + private static final Map<String,Map<String,String>> localeToSubdivisionIdToName = new ConcurrentHashMap<>(); + + private static final Pattern SUBDIVISION_PATTERN = Pattern.compile("\\s*<subdivision\\s+type=\"(gb(?:eng|sct|wls))\">([^<]+)</subdivision>"); + private static final SortedSet<String> SUBDIVISION_FILE_NAMES = ImmutableSortedSet.copyOf( + new File(CLDRPaths.SUBDIVISIONS_DIRECTORY).list() + ); + + static { + localeToNameToSubdivisionId.put("root", Collections.emptyMap()); + } + + public static Map<String, String> getSubdivisionIdToName(String localeID) { + Map<String,String> result = localeToSubdivisionIdToName.get(localeID); + if (result == null) { + load(localeID); + result = localeToSubdivisionIdToName.get(localeID); + if (result == null) { + result = Collections.emptyMap(); + } + } + return result; + } + + public static Map<String, String> getNameToSubdivisionPath(String localeID) { + Map<String,String> result = localeToNameToSubdivisionId.get(localeID); + if (result == null) { + load(localeID); + result = localeToNameToSubdivisionId.get(localeID); + if (result == null) { + result = Collections.emptyMap(); + } + } + return result; + } + + private static void load(String localeID) { + try { + Map<String,String> _subdivisionIdToName; + Map<String, String> _nameToSubdivisionId; + + String fileName = localeID + ".xml"; + if (SUBDIVISION_FILE_NAMES.contains(fileName)) { + _nameToSubdivisionId = new TreeMap<>(); + _subdivisionIdToName = new TreeMap<>(); + Matcher m = SUBDIVISION_PATTERN.matcher(""); + for (String line : FileUtilities.in(new File(CLDRPaths.SUBDIVISIONS_DIRECTORY, fileName))) { + if (m.reset(line).matches()) { + String xpath = subdivisionPathPrefix + EmojiConstants.toTagSeq(m.group(1)) + subdivisionPathSuffix; + _nameToSubdivisionId.put(m.group(2), xpath); + _subdivisionIdToName.put(m.group(1), m.group(2)); + } + } + _nameToSubdivisionId = _nameToSubdivisionId.isEmpty() ? Collections.emptyMap() + : ImmutableMap.copyOf(_nameToSubdivisionId); + _subdivisionIdToName = _subdivisionIdToName.isEmpty() ? Collections.emptyMap() + : ImmutableMap.copyOf(_subdivisionIdToName); + } else { + String parentLocaleId = LocaleIDParser.getParent(localeID); + _nameToSubdivisionId = getNameToSubdivisionPath(parentLocaleId); + _subdivisionIdToName = localeToSubdivisionIdToName.get(parentLocaleId); + } + localeToNameToSubdivisionId.put(localeID, _nameToSubdivisionId); + localeToSubdivisionIdToName.put(localeID, _subdivisionIdToName); + } catch (Exception e) {} + } + + static Set<String> SUBDIVISIONS = ImmutableSet.of("gbeng", "gbsct", "gbwls"); + + public static void main(String[] args) { + System.out.print("Group\tOrd.\tLocale\tCode"); + for (String sd : SUBDIVISIONS) { + System.out.print('\t'); + System.out.print(sd); + + } + System.out.println(); + CLDRFile english = CLDRConfig.getInstance().getEnglish(); + Set<String> locales = new HashSet<>(); + for (String filename : SUBDIVISION_FILE_NAMES) { + if (filename.endsWith(".xml")) { + String locale = filename.substring(0, filename.length()-4); + Map<String, String> map = getSubdivisionIdToName(locale); + if (!map.isEmpty()) { + locales.add(locale); + ULocale ulocale = new ULocale(locale); + LanguageGroup group = LanguageGroup.get(ulocale); + int rank = LanguageGroup.rankInGroup(ulocale); + System.out.print(group + "\t" + rank + "\t" + english.getName(locale) + "\t" + locale); + for (String sd : SUBDIVISIONS) { + System.out.print('\t'); + System.out.print(map.get(sd)); + } + System.out.println(); + } + } + } + for (String locale : StandardCodes.make().getLocaleCoverageLocales(Organization.cldr)) { + if (locales.contains(locale)) { + continue; + } + ULocale ulocale = new ULocale(locale); + String region = ulocale.getCountry(); + if (!region.isEmpty() && !region.equals("PT") && !region.equals("GB")) { + continue; + } + LanguageGroup group = LanguageGroup.get(ulocale); + int rank = LanguageGroup.rankInGroup(ulocale); + System.out.println(group + "\t" + rank + "\t" + english.getName(locale) + "\t" + locale); + } + +// System.out.println(getSubdivisionIdToName("fr")); +// System.out.println(getNameToSubdivisionPath("fr")); + } +}
\ No newline at end of file diff --git a/tools/java/org/unicode/cldr/test/ExampleGenerator.java b/tools/java/org/unicode/cldr/test/ExampleGenerator.java index 8c07a3a..85add0a 100644 --- a/tools/java/org/unicode/cldr/test/ExampleGenerator.java +++ b/tools/java/org/unicode/cldr/test/ExampleGenerator.java @@ -28,6 +28,7 @@ import org.unicode.cldr.util.CLDRPaths; import org.unicode.cldr.util.CldrUtility; import org.unicode.cldr.util.DayPeriodInfo; import org.unicode.cldr.util.DayPeriodInfo.DayPeriod; +import org.unicode.cldr.util.EmojiConstants; import org.unicode.cldr.util.Factory; import org.unicode.cldr.util.ICUServiceBuilder; import org.unicode.cldr.util.LanguageTagParser; @@ -41,6 +42,7 @@ import org.unicode.cldr.util.SupplementalDataInfo.PluralInfo.Count; import org.unicode.cldr.util.SupplementalDataInfo.PluralType; import org.unicode.cldr.util.TimezoneFormatter; import org.unicode.cldr.util.TransliteratorUtilities; +import org.unicode.cldr.util.XListFormatter.ListTypeLength; import org.unicode.cldr.util.XPathParts; import com.ibm.icu.impl.Row.R3; @@ -51,6 +53,7 @@ import com.ibm.icu.text.DateFormatSymbols; import com.ibm.icu.text.DateTimePatternGenerator; import com.ibm.icu.text.DecimalFormat; import com.ibm.icu.text.DecimalFormatSymbols; +import com.ibm.icu.text.ListFormatter; import com.ibm.icu.text.MessageFormat; import com.ibm.icu.text.NumberFormat; import com.ibm.icu.text.PluralRules; @@ -59,7 +62,9 @@ import com.ibm.icu.text.PluralRules.FixedDecimalRange; import com.ibm.icu.text.PluralRules.FixedDecimalSamples; import com.ibm.icu.text.PluralRules.SampleType; import com.ibm.icu.text.SimpleDateFormat; +import com.ibm.icu.text.SimpleFormatter; import com.ibm.icu.text.Transliterator; +import com.ibm.icu.text.UTF16; import com.ibm.icu.util.Calendar; import com.ibm.icu.util.TimeZone; import com.ibm.icu.util.ULocale; @@ -126,14 +131,14 @@ public class ExampleGenerator { static { Calendar calendar = Calendar.getInstance(ZONE_SAMPLE, ULocale.ENGLISH); - calendar.set(1999, 8, 14, 13, 25, 59); // 1999-08-14 13:25:59 + calendar.set(1999, 8, 5, 13, 25, 59); // 1999-08-14 13:25:59 DATE_SAMPLE = calendar.getTime(); calendar.set(1999, 9, 27, 13, 25, 59); // 1999-09-27 13:25:59 DATE_SAMPLE2 = calendar.getTime(); - calendar.set(1999, 8, 14, 7, 0, 0); // 1999-08-14 07:00:00 + calendar.set(1999, 8, 5, 7, 0, 0); // 1999-08-14 07:00:00 DATE_SAMPLE3 = calendar.getTime(); - calendar.set(1999, 8, 14, 23, 0, 0); // 1999-08-14 23:00:00 + calendar.set(1999, 8, 5, 23, 0, 0); // 1999-08-14 23:00:00 DATE_SAMPLE4 = calendar.getTime(); } @@ -161,6 +166,8 @@ public class ExampleGenerator { private PluralSamples patternExamples; + private Map<String, String> subdivisionIdToName; + /** * For getting the end of the "background" style. Default is "</span>". It is * used in composing patterns, so it can show the part that corresponds to the @@ -224,6 +231,7 @@ public class ExampleGenerator { if (!resolvedCldrFile.isResolved()) throw new IllegalArgumentException("CLDRFile must be resolved"); if (!englishFile.isResolved()) throw new IllegalArgumentException("English CLDRFile must be resolved"); cldrFile = resolvedCldrFile; + subdivisionIdToName = EmojiSubdivisionNames.getSubdivisionIdToName(cldrFile.getLocaleID()); this.englishFile = englishFile; synchronized (ExampleGenerator.class) { if (supplementalDataInfo == null) { @@ -343,6 +351,12 @@ public class ExampleGenerator { result = handleMonthPatterns(parts, value); } else if (parts.getElement(-1).equals("appendItem")) { result = handleAppendItems(parts, value); + } else if (parts.getElement(-1).equals("annotation")) { + result = handleAnnotationName(parts, value); + } else if (parts.getElement(-1).equals("characterLabel")) { + result = handleLabel(parts, value); + } else if (parts.getElement(-1).equals("characterLabelPattern")) { + result = handleLabelPattern(parts, value); } else { // didn't detect anything, return empty-handed return null; @@ -377,6 +391,155 @@ public class ExampleGenerator { return result; } + private String handleLabelPattern(XPathParts parts2, String value) { + switch (parts.getAttributeValue(-1, "type")) { + case "category-list": + List<String> examples = new ArrayList<>(); + CLDRFile cfile = getCldrFile(); + SimpleFormatter initialPattern = SimpleFormatter.compile(setBackground(value)); + String path = CLDRFile.getKey(CLDRFile.TERRITORY_NAME, "FR"); + String regionName = cfile.getStringValue(path); + String flagName = cfile.getStringValue("//ldml/characterLabels/characterLabel[@type=\"flag\"]"); + examples.add(invertBackground(EmojiConstants.getEmojiFromRegionCodes("FR") + + " โ " + initialPattern.format(flagName, regionName))); + return formatExampleList(examples); + default: return null; + } + } + + private String handleLabel(XPathParts parts2, String value) { + // "//ldml/characterLabels/characterLabel[@type=\"" + typeAttributeValue + "\"]" + switch (parts.getAttributeValue(-1, "type")) { + case "flag": { + String value2 = backgroundStartSymbol + value + backgroundEndSymbol; + CLDRFile cfile = getCldrFile(); + List<String> examples = new ArrayList<>(); + SimpleFormatter initialPattern = SimpleFormatter.compile(cfile.getStringValue("//ldml/characterLabels/characterLabelPattern[@type=\"category-list\"]")); + addFlag(value2, "FR", cfile, initialPattern, examples); + addFlag(value2, "CN", cfile, initialPattern, examples); + addSubdivisionFlag(value2, "gbeng", cfile, initialPattern, examples); + addSubdivisionFlag(value2, "gbsct", cfile, initialPattern, examples); + addSubdivisionFlag(value2, "gbwls", cfile, initialPattern, examples); + return formatExampleList(examples); + } + case "keycap": { + String value2 = backgroundStartSymbol + value + backgroundEndSymbol; + List<String> examples = new ArrayList<>(); + CLDRFile cfile = getCldrFile(); + SimpleFormatter initialPattern = SimpleFormatter.compile(cfile.getStringValue("//ldml/characterLabels/characterLabelPattern[@type=\"category-list\"]")); + examples.add(invertBackground(initialPattern.format(value2, "1"))); + examples.add(invertBackground(initialPattern.format(value2, "10"))); + examples.add(invertBackground(initialPattern.format(value2, "#"))); + return formatExampleList(examples); + } + default: + return null; + } + } + + private void addFlag(String value2, String isoRegionCode, CLDRFile cfile, SimpleFormatter initialPattern, List<String> examples) { + String path = CLDRFile.getKey(CLDRFile.TERRITORY_NAME, isoRegionCode); + String regionName = cfile.getStringValue(path); + examples.add(invertBackground(EmojiConstants.getEmojiFromRegionCodes(isoRegionCode) + + " โ " + initialPattern.format(value2, regionName))); + } + + private void addSubdivisionFlag(String value2, String isoSubdivisionCode, CLDRFile cfile, SimpleFormatter initialPattern, List<String> examples) { + String subdivisionName = subdivisionIdToName.get(isoSubdivisionCode); + if (subdivisionName == null) { + subdivisionName = isoSubdivisionCode; + } + examples.add(invertBackground(EmojiConstants.getEmojiFromSubdivisionCodes(isoSubdivisionCode) + + " โ " + initialPattern.format(value2, subdivisionName))); + } + + private String handleAnnotationName(XPathParts parts, String value) { + //ldml/annotations/annotation[@cp="๐ฆฐ"][@type="tts"] + // skip anything but the name + if (!"tts".equals(parts.getAttributeValue(-1, "type"))) { + return null; + } + String cp = parts.getAttributeValue(-1, "cp"); + if (cp == null || cp.isEmpty()) { + return null; + } + Set<String> examples = new LinkedHashSet<>(); + int first = cp.codePointAt(0); + switch(first) { + case 0x1F46A: // ๐ช U+1F46A FAMILY + examples.add(formatGroup(parts, value, "๐จโ๐ฉโ๐งโ๐ฆ", "๐จ", "๐ฉ", "๐ง", "๐ฆ")); + examples.add(formatGroup(parts, value, "๐ฉโ๐ฉโ๐ฆ", "๐ฉ", "๐ฉ", "๐ฆ")); + break; + case 0x1F48F: // ๐ U+1F48F KISS ๐ฉ๐จ + examples.add(formatGroup(parts, value, "๐ฉโโค๏ธโ๐โ๐จ", "๐ฉ", "๐จ")); + examples.add(formatGroup(parts, value, "๐ฉโโค๏ธโ๐โ๐ฉ", "๐ฉ", "๐ฉ")); + break; + case 0x1F491: // ๐ U+1F491 COUPLE WITH HEART + examples.add(formatGroup(parts, value, "๐ฉโโค๏ธโ๐จ", "๐ฉ", "๐จ")); + examples.add(formatGroup(parts, value, "๐ฉโโค๏ธโ๐ฉ", "๐ฉ", "๐ฉ")); + break; + default: + boolean isSkin = EmojiConstants.MODIFIERS.contains(first); + if (isSkin || EmojiConstants.HAIR.contains(first)) { + String value2 = backgroundStartSymbol + value + backgroundEndSymbol; + CLDRFile cfile = getCldrFile(); + String skin = "๐ฝ"; + String hair = "๐ฆฐ"; + String skinName = getEmojiName(cfile, skin); + String hairName = getEmojiName(cfile, hair); + if (hairName == null) { + hair = "[missing]"; + } + SimpleFormatter initialPattern = SimpleFormatter.compile(cfile.getStringValue("//ldml/characterLabels/characterLabelPattern[@type=\"category-list\"]")); + SimpleFormatter listPattern = SimpleFormatter.compile(cfile.getStringValue("//ldml/listPatterns/listPattern[@type=\"unit-short\"]/listPatternPart[@type=\"2\"]")); + + hair = EmojiConstants.JOINER_STRING + hair; + formatPeople(cfile, first, isSkin, value2, "๐ฉ", skin, skinName, hair, hairName, initialPattern, listPattern, examples); + formatPeople(cfile, first, isSkin, value2, "๐จ", skin, skinName, hair, hairName, initialPattern, listPattern, examples); + } + break; + } + return formatExampleList(examples); + } + + private String getEmojiName(CLDRFile cfile, String skin) { + return cfile.getStringValue("//ldml/annotations/annotation[@cp=\"" + skin + "\"][@type=\"tts\"]"); + } + + //ldml/listPatterns/listPattern[@type="standard-short"]/listPatternPart[@type="2"] + private String formatGroup(XPathParts parts, String value, String sourceEmoji, String... components) { + CLDRFile cfile = getCldrFile(); + SimpleFormatter initialPattern = SimpleFormatter.compile(cfile.getStringValue("//ldml/characterLabels/characterLabelPattern[@type=\"category-list\"]")); + String value2 = backgroundEndSymbol + value + backgroundStartSymbol; + String[] names = new String[components.length]; + int i = 0; + for (String component : components) { + names[i++] = getEmojiName(cfile, component); + } + return backgroundStartSymbol + sourceEmoji + " โ " + initialPattern.format(value2, + longListPatternExample(EmojiConstants.COMPOSED_NAME_LIST.getPath(), "n/a", "n/a2", names)); + } + + private void formatPeople(CLDRFile cfile, int first, boolean isSkin, String value2, String person, String skin, String skinName, + String hair, String hairName, SimpleFormatter initialPattern, SimpleFormatter listPattern, Collection<String> examples) { + String cp; + String personName = getEmojiName(cfile, person); + StringBuilder emoji = new StringBuilder(person).appendCodePoint(first); + cp = UTF16.valueOf(first); + cp = isSkin ? cp : EmojiConstants.JOINER_STRING + cp; + examples.add(person + cp + " โ " + invertBackground(initialPattern.format(personName,value2))); + emoji.setLength(0); + emoji.append(personName); + if (isSkin) { + skinName = value2; + skin = cp; + } else { + hairName = value2; + hair = cp; + } + examples.add(person + skin + hair + " โ " + invertBackground(listPattern.format(initialPattern.format(personName, skinName), hairName))); + } + private String handleDayPeriod(String xpath, String value, ExampleContext context, ExampleType type) { //ldml/dates/calendars/calendar[@type="gregorian"]/dayPeriods/dayPeriodContext[@type="format"]/dayPeriodWidth[@type="wide"]/dayPeriod[@type="morning1"] //ldml/dates/calendars/calendar[@type="gregorian"]/dayPeriods/dayPeriodContext[@type="stand-alone"]/dayPeriodWidth[@type="wide"]/dayPeriod[@type="morning1"] @@ -425,7 +588,7 @@ public class ExampleGenerator { <compoundUnit type="per"> <unitPattern count="other">{0}/{1}</unitPattern> </compoundUnit> - + * <compoundUnit type="per"> <unitPattern count="one">{0}/{1}</unitPattern> <unitPattern count="other">{0}/{1}</unitPattern> @@ -434,7 +597,7 @@ public class ExampleGenerator { <unitPattern count="one">{0} meter</unitPattern> <unitPattern count="other">{0} meters</unitPattern> </unit> - + */ // we want to get a number that works for the count passed in. @@ -542,16 +705,16 @@ public class ExampleGenerator { } private String handleListPatterns(XPathParts parts, String value) { - // listPatternType is either "duration" or null + // listPatternType is either "duration" or null/other list String listPatternType = parts.getAttributeValue(-2, "type"); if (listPatternType == null || !listPatternType.contains("unit")) { - return handleRegularListPatterns(parts, value); + return handleRegularListPatterns(parts, value, ListTypeLength.from(listPatternType)); } else { return handleDurationListPatterns(parts, value, UnitLength.from(listPatternType)); } } - private String handleRegularListPatterns(XPathParts parts, String value) { + private String handleRegularListPatterns(XPathParts parts, String value, ListTypeLength listTypeLength) { String patternType = parts.getAttributeValue(-1, "type"); String pathFormat = "//ldml/localeDisplayNames/territories/territory[@type=\"{0}\"]"; String territory1 = getValueFromFormat(pathFormat, "CH"); @@ -561,9 +724,8 @@ public class ExampleGenerator { } String territory3 = getValueFromFormat(pathFormat, "EG"); String territory4 = getValueFromFormat(pathFormat, "CA"); - String listPathFormat = "//ldml/listPatterns/listPattern/listPatternPart[@type=\"{0}\"]"; return longListPatternExample( - listPathFormat, patternType, value, territory1, territory2, territory3, territory4); + listTypeLength.getPath(), patternType, value, territory1, territory2, territory3, territory4); } private String handleDurationListPatterns(XPathParts parts, String value, UnitLength unitWidth) { @@ -575,20 +737,8 @@ public class ExampleGenerator { } String duration3 = getFormattedUnit("duration-minute", unitWidth, 37); String duration4 = getFormattedUnit("duration-second", unitWidth, 23); - String listPathFormat = "//ldml/listPatterns/listPattern" - + unitWidth.listTypeLength.typeString - + "/listPatternPart[@type=\"{0}\"]"; return longListPatternExample( - listPathFormat, patternType, value, duration1, duration2, duration3, duration4); - } - - public enum ListTypeLength { - NORMAL(""), UNIT_WIDE("[@type=\"unit\"]"), UNIT_SHORT("[@type=\"unit-short\"]"), UNIT_NARROW("[@type=\"unit-narrow\"]"); - final String typeString; - - ListTypeLength(String typeString) { - this.typeString = typeString; - } + unitWidth.listTypeLength.getPath(), patternType, value, duration1, duration2, duration3, duration4); } public enum UnitLength { @@ -630,17 +780,24 @@ public class ExampleGenerator { return format(getValueFromFormat(pathFormat, unitType, form), formattedUnitAmount); } - private String longListPatternExample(String listPathFormat, String patternType, String value, String territory1, String territory2, String territory3, - String territory4) { + //ldml/listPatterns/listPattern/listPatternPart[@type="2"] โ And + //ldml/listPatterns/listPattern[@type="standard-short"]/listPatternPart[@type="2"] Short And + //ldml/listPatterns/listPattern[@type="or"]/listPatternPart[@type="2"] or list + //ldml/listPatterns/listPattern[@type="unit"]/listPatternPart[@type="2"] + //ldml/listPatterns/listPattern[@type="unit-short"]/listPatternPart[@type="2"] + //ldml/listPatterns/listPattern[@type="unit-narrow"]/listPatternPart[@type="2"] + + private String longListPatternExample(String listPathFormat, String patternType, String value, String... items) { + String doublePattern = getPattern(listPathFormat, "2", patternType, value); String startPattern = getPattern(listPathFormat, "start", patternType, value); String middlePattern = getPattern(listPathFormat, "middle", patternType, value); String endPattern = getPattern(listPathFormat, "end", patternType, value); - - String example = format(startPattern, territory1, - format(middlePattern, territory2, format(endPattern, territory3, territory4))); + ListFormatter listFormatter = new ListFormatter(doublePattern, startPattern, middlePattern, endPattern); + String example = listFormatter.format(items); return invertBackground(example); } + /** * Helper method for handleListPatterns. Returns the pattern to be used for * a specified pattern type. @@ -651,8 +808,7 @@ public class ExampleGenerator { * @param value * @return */ - private String getPattern(String pathFormat, String pathPatternType, - String valuePatternType, String value) { + private String getPattern(String pathFormat, String pathPatternType, String valuePatternType, String value) { return valuePatternType.equals(pathPatternType) ? setBackground(value) : getValueFromFormat(pathFormat, pathPatternType); } @@ -837,54 +993,54 @@ public class ExampleGenerator { Set<FixedDecimal> examplesSeen = new HashSet<FixedDecimal>(); int maxCount = 2; main: - // If we are a currency, we will try to see if we can set the decimals to match. - // but if nothing works, we will just use a plain sample. - for (int phase = 0; phase < 2; ++phase) { - int check = 0; - for (FixedDecimal example : exampleCount) { - // we have to first see whether we have a currency. If so, we have to see if the count works. - - if (isCurrency && phase == 0) { - example = new FixedDecimal(example.getSource(), decimalCount); - } - // skip if we've done before (can happen because of the currency reset) - if (examplesSeen.contains(example)) { - continue; - } - examplesSeen.add(example); - // skip if the count isn't appropriate - if (!pluralRules.select(example).equals(count.toString())) { - continue; - } + // If we are a currency, we will try to see if we can set the decimals to match. + // but if nothing works, we will just use a plain sample. + for (int phase = 0; phase < 2; ++phase) { + int check = 0; + for (FixedDecimal example : exampleCount) { + // we have to first see whether we have a currency. If so, we have to see if the count works. + + if (isCurrency && phase == 0) { + example = new FixedDecimal(example.getSource(), decimalCount); + } + // skip if we've done before (can happen because of the currency reset) + if (examplesSeen.contains(example)) { + continue; + } + examplesSeen.add(example); + // skip if the count isn't appropriate + if (!pluralRules.select(example).equals(count.toString())) { + continue; + } - if (value == null) { - String fallbackPath = cldrFile.getCountPathWithFallback(xpath, count, true); - value = cldrFile.getStringValue(fallbackPath); - } - String resultItem; - - resultItem = formatCurrency(value, type, unitType, isPattern, isCurrency, count, example); - // now add to list - result = addExampleResult(resultItem, result); - if (isPattern) { - String territory = getDefaultTerritory(type); - String currency = supplementalDataInfo.getDefaultCurrency(territory); - if (currency.equals(unitType)) { - currency = "EUR"; - if (currency.equals(unitType)) { - currency = "JAY"; - } + if (value == null) { + String fallbackPath = cldrFile.getCountPathWithFallback(xpath, count, true); + value = cldrFile.getStringValue(fallbackPath); } - resultItem = formatCurrency(value, type, currency, isPattern, isCurrency, count, example); + String resultItem; + + resultItem = formatCurrency(value, type, unitType, isPattern, isCurrency, count, example); // now add to list result = addExampleResult(resultItem, result); + if (isPattern) { + String territory = getDefaultTerritory(type); + String currency = supplementalDataInfo.getDefaultCurrency(territory); + if (currency.equals(unitType)) { + currency = "EUR"; + if (currency.equals(unitType)) { + currency = "JAY"; + } + } + resultItem = formatCurrency(value, type, currency, isPattern, isCurrency, count, example); + // now add to list + result = addExampleResult(resultItem, result); - } - if (--maxCount < 1) { - break main; + } + if (--maxCount < 1) { + break main; + } } } - } return result.isEmpty() ? null : result; } @@ -953,8 +1109,8 @@ public class ExampleGenerator { String unitPattern; String unitPatternPath = cldrFile.getCountPathWithFallback(isCurrency ? "//ldml/numbers/currencyFormats/unitPattern" - : "//ldml/units/unit[@type=\"" + unitType + "\"]/unitPattern", - count, true); + : "//ldml/units/unit[@type=\"" + unitType + "\"]/unitPattern", + count, true); unitPattern = cldrFile.getWinningValue(unitPatternPath); return unitPattern; } @@ -962,8 +1118,8 @@ public class ExampleGenerator { private String getUnitName(String unitType, final boolean isCurrency, Count count) { String unitNamePath = cldrFile.getCountPathWithFallback(isCurrency ? "//ldml/numbers/currencies/currency[@type=\"" + unitType + "\"]/displayName" - : "//ldml/units/unit[@type=\"" + unitType + "\"]/unitPattern", - count, true); + : "//ldml/units/unit[@type=\"" + unitType + "\"]/unitPattern", + count, true); return unitNamePath == null ? unitType : cldrFile.getWinningValue(unitNamePath); } @@ -1506,6 +1662,28 @@ public class ExampleGenerator { return result; } + /** + * Return examples formatted as string, with null returned for null or empty examples. + * @param examples + * @return + */ + private String formatExampleList(Collection<String> examples) { + if (examples == null || examples.isEmpty()) { + return null; + } + String result = ""; + boolean first = true; + for (String example : examples) { + if (first) { + result = example; + first = false; + } else { + result = addExampleResult(example, result); + } + } + return result; + } + public String format(String format, Object... objects) { if (format == null) return null; return MessageFormat.format(format, objects); @@ -1525,19 +1703,17 @@ public class ExampleGenerator { /** * Put a background on an item, skipping enclosed patterns. - * * @param sampleTerritory * @return */ private String setBackground(String inputPattern) { Matcher m = PARAMETER.matcher(inputPattern); return backgroundStartSymbol + m.replaceAll(backgroundEndSymbol + "$1" + backgroundStartSymbol) - + backgroundEndSymbol; + + backgroundEndSymbol; } /** * Put a background on an item, skipping enclosed patterns, except for {0} - * * @param patternToEmbed * TODO * @param sampleTerritory @@ -1547,7 +1723,7 @@ public class ExampleGenerator { private String setBackgroundExceptMatch(String input, Pattern patternToEmbed) { Matcher m = patternToEmbed.matcher(input); return backgroundStartSymbol + m.replaceAll(backgroundEndSymbol + "$1" + backgroundStartSymbol) - + backgroundEndSymbol; + + backgroundEndSymbol; } /** @@ -1608,19 +1784,19 @@ public class ExampleGenerator { private String finalizeBackground(String input) { return input == null ? input - : exampleStart + + : exampleStart + TransliteratorUtilities.toHTML.transliterate(input) - .replace(backgroundStartSymbol + backgroundEndSymbol, "") - // remove null runs - .replace(backgroundEndSymbol + backgroundStartSymbol, "") - // remove null runs - .replace(backgroundStartSymbol, backgroundStart) - .replace(backgroundEndSymbol, backgroundEnd) - .replace(exampleSeparatorSymbol, exampleEnd + exampleStart) - .replace(startItalicSymbol, startItalic) - .replace(endItalicSymbol, endItalic) - .replace(startSupSymbol, startSup) - .replace(endSupSymbol, endSup) + .replace(backgroundStartSymbol + backgroundEndSymbol, "") + // remove null runs + .replace(backgroundEndSymbol + backgroundStartSymbol, "") + // remove null runs + .replace(backgroundStartSymbol, backgroundStart) + .replace(backgroundEndSymbol, backgroundEnd) + .replace(exampleSeparatorSymbol, exampleEnd + exampleStart) + .replace(startItalicSymbol, startItalic) + .replace(endItalicSymbol, endItalic) + .replace(startSupSymbol, startSup) + .replace(endSupSymbol, endSup) + exampleEnd; } @@ -1738,12 +1914,12 @@ public class ExampleGenerator { while (URLMatcher.reset(description).find(start)) { final String url = URLMatcher.group(); buffer - .append(TransliteratorUtilities.toHTML.transliterate(description.substring(start, URLMatcher.start()))) - .append("<a target='CLDR-ST-DOCS' href='") - .append(url) - .append("'>") - .append(url) - .append("</a>"); + .append(TransliteratorUtilities.toHTML.transliterate(description.substring(start, URLMatcher.start()))) + .append("<a target='CLDR-ST-DOCS' href='") + .append(url) + .append("'>") + .append(url) + .append("</a>"); start = URLMatcher.end(); } buffer.append(TransliteratorUtilities.toHTML.transliterate(description.substring(start))); @@ -1755,7 +1931,7 @@ public class ExampleGenerator { XPathParts emoji = XPathParts.getFrozenInstance(xpath); String cp = emoji.getAttributeValue(-1, "cp"); String minimal = Utility.hex(cp.replace("", "")).replace(',', '_').toLowerCase(Locale.ROOT); - buffer.append("<br><img height='64px' width='auto' src='images/android/android_" + minimal + ".png'>"); + buffer.append("<br><img height='64px' width='auto' src='images/emoji/emoji_" + minimal + ".png'>"); } return buffer.toString(); @@ -1780,12 +1956,12 @@ public class ExampleGenerator { return exampleHtml == null ? null : internal ? "ใ" + exampleHtml .replace("๎ด", "โฌ") - .replace("๎ต", "โญ") + "ใ" - : exampleHtml - .replace("<div class='cldr_example'>", "ใ") - .replace("</div>", "ใ") - .replace("<span class='cldr_substituted'>", "โฌ") - .replace("</span>", "โญ"); + .replace("๎ต", "โญ") + "ใ" + : exampleHtml + .replace("<div class='cldr_example'>", "ใ") + .replace("</div>", "ใ") + .replace("<span class='cldr_substituted'>", "โฌ") + .replace("</span>", "โญ"); } HelpMessages helpMessages; diff --git a/tools/java/org/unicode/cldr/tool/CLDRModify.java b/tools/java/org/unicode/cldr/tool/CLDRModify.java index be8a943..453e6ad 100644 --- a/tools/java/org/unicode/cldr/tool/CLDRModify.java +++ b/tools/java/org/unicode/cldr/tool/CLDRModify.java @@ -1331,10 +1331,10 @@ public class CLDRModify { fixList.add('c', "Fix transiton from an old currency code to a new one", new CLDRFilter() { public void handlePath(String xpath) { - String oldCurrencyCode = "MRO"; - String newCurrencyCode = "MRU"; - int fromDate = 1973; - int toDate = 2017; + String oldCurrencyCode = "VEF"; + String newCurrencyCode = "VES"; + int fromDate = 2008; + int toDate = 2018; String leadingParenString = " ("; String trailingParenString = ")"; String separator = "\u2013"; diff --git a/tools/java/org/unicode/cldr/tool/ChartAnnotations.java b/tools/java/org/unicode/cldr/tool/ChartAnnotations.java index e47c67e..ac6cfce 100644 --- a/tools/java/org/unicode/cldr/tool/ChartAnnotations.java +++ b/tools/java/org/unicode/cldr/tool/ChartAnnotations.java @@ -86,7 +86,17 @@ public class ChartAnnotations extends Chart { "๐ช๐บ", "๐", "#๏ธโฃ", "๐ถ๐ฝ", "๐ฉโโค๏ธโ๐โ๐ฉ", "๐ฉโโค๏ธโ๐ฉ", "๐ฉโ๐ฉโ๐ง", "๐จ๐ปโโ๏ธ", "๐ฎ๐ฟโโ๏ธ", "๐ฎ๐ฝโโ๏ธ", "๐ฉโโค๏ธโ๐โ๐ฉ", "๐ฎ๐ฝโโ๏ธ", "๐", "๐ฉโโค๏ธโ๐โ๐ฉ", "๐", "๐ฉโโค๏ธโ๐ฉ", "๐ช", "๐ฉโ๐ฉโ๐ง", "๐ฆ๐ป", "๐ฉ๐ฟ", "๐จโโ", "๐จ๐ฟโโ", "๐ฉโโ", "๐ฉ๐ผโโ", "๐ฎ", "๐ฎโโ๏ธ", "๐ฎ๐ผโโ๏ธ", "๐ฎโโ๏ธ", "๐ฎ๐ฟโโ๏ธ", - "๐ด", "๐ด๐ฟ", "๐ดโโ๏ธ", "๐ด๐ฟโโ๏ธ", "๐ดโโ๏ธ", "๐ด๐ฟโโ๏ธ")) + "๐ด", "๐ด๐ฟ", "๐ดโโ๏ธ", "๐ด๐ฟโโ๏ธ", "๐ดโโ๏ธ", "๐ด๐ฟโโ๏ธ", + "๐ด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ", + "#๏ธโฃ", + "๐ฆ๐จ", + "โน๏ธโโ๏ธ", + "๐จโโ๏ธ", + "๐ณ๏ธโ๐","๐ดโโ ๏ธ", + "๐จโ๐ฆฐ", + "๐จ๐ฟโ๐ฆฐ", + "๐ฟ","๐ฆฐ" + )) .freeze(); public void writeSubcharts(Anchors anchors) throws IOException { diff --git a/tools/java/org/unicode/cldr/tool/GenerateMaximalLocales.java b/tools/java/org/unicode/cldr/tool/GenerateMaximalLocales.java index 139f785..9f8e106 100644 --- a/tools/java/org/unicode/cldr/tool/GenerateMaximalLocales.java +++ b/tools/java/org/unicode/cldr/tool/GenerateMaximalLocales.java @@ -150,6 +150,8 @@ public class GenerateMaximalLocales { "bsq_Bass_LR", "ccp_Cakm_BD", "blt_Tavt_VN", + "rhg_Arab_MM", + "rhg_Rohg_MM", }; /** @@ -264,6 +266,7 @@ public class GenerateMaximalLocales { // {"bsq", "bsq_Bass_LR"}, // {"ccp", "ccp_Cakm_BD"}, // {"blt", "blt_Tavt_VN"}, + { "mis_Medf", "mis_Medf_NG" }, }); /** diff --git a/tools/java/org/unicode/cldr/tool/GetChanges.java b/tools/java/org/unicode/cldr/tool/GetChanges.java index bf8f87e..cbf8717 100644 --- a/tools/java/org/unicode/cldr/tool/GetChanges.java +++ b/tools/java/org/unicode/cldr/tool/GetChanges.java @@ -1,7 +1,10 @@ package org.unicode.cldr.tool; +import java.util.Collections; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -11,9 +14,15 @@ import org.unicode.cldr.util.CLDRFile; import org.unicode.cldr.util.CLDRPaths; import org.unicode.cldr.util.CldrUtility; import org.unicode.cldr.util.Factory; +import org.unicode.cldr.util.LanguageTagParser; +import org.unicode.cldr.util.Level; +import org.unicode.cldr.util.Organization; import org.unicode.cldr.util.PathHeader; import org.unicode.cldr.util.PatternCache; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; +import com.google.common.collect.TreeMultimap; import com.ibm.icu.util.Output; public class GetChanges { @@ -43,9 +52,17 @@ public class GetChanges { CLDRConfig testInfo = ToolConfig.getToolInstance(); CLDRFile english = testInfo.getEnglish(); - Factory lastReleaseFactory = Factory.make(CLDRPaths.LAST_DIRECTORY + "common/main/", ".*"); - Factory trunkFactory = testInfo.getCldrFactory(); - Factory snapshotFactory = Factory.make(CLDRPaths.TMP2_DIRECTORY + "vxml/common/main/", ".*"); + boolean onlyMissing = true; + String release = "33.1"; + + String subdir = "annotations"; // "main"; + Factory lastReleaseFactory = Factory.make(CLDRPaths.LAST_DIRECTORY + "common/" + + subdir, ".*"); + Factory trunkFactory = testInfo.getAnnotationsFactory(); // CldrFactory(); + Factory snapshotFactory = Factory.make(CLDRPaths.AUX_DIRECTORY + "voting/" + + release + + "/vxml/common/" + + subdir, ".*"); PathHeader.Factory phf = PathHeader.getFactory(english); int totalCount = 0; @@ -54,33 +71,84 @@ public class GetChanges { Output<String> localeWhereFound = new Output<String>(); Output<String> pathWhereFound = new Output<String>(); - for (String locale : lastReleaseFactory.getAvailable()) { + CLDRFile englishCldrFile = trunkFactory.make("en", false); + final Set<String> paths = ImmutableSet.copyOf(englishCldrFile.iterator()); + System.out.println("english paths: " + paths.size()); + + Multimap<String,PathHeader> missing = TreeMultimap.create(); + + Set<String> locales = testInfo.getStandardCodes().getLocaleCoverageLocales(Organization.cldr, Collections.singleton(Level.MODERN)); + + LanguageTagParser ltp = new LanguageTagParser(); + for (String locale : locales) { + if (!ltp.set(locale).getRegion().isEmpty() || locale.equals("sr_Latn")) { + continue; // skip region locales, they'll inherit + } +// if (!locale.equals("sr_Latn")) { +// continue; +// } + System.out.println(locale); + + CLDRFile snapshot; + try { + snapshot = snapshotFactory.make(locale, false); + } catch (Exception e) { + System.out.println("Skipping " + locale + ", no data in annotations/"); + continue; + } + + CLDRFile lastRelease = null; + try { + lastRelease = lastReleaseFactory.make(locale, false); + } catch (Exception e) { + } + + CLDRFile trunk = null; + try { + trunk = trunkFactory.make(locale, false); + } catch (Exception e) { + } + Map<PathHeader, Data> results = new TreeMap<PathHeader, Data>(); - CLDRFile lastRelease = lastReleaseFactory.make(locale, false); - CLDRFile trunk = trunkFactory.make(locale, false); - CLDRFile snapshot = snapshotFactory.make(locale, true); - for (String xpath : lastRelease) { - if (xpath.contains("fallbackRegionFormat") || xpath.contains("exemplar")) { + + for (String xpath : paths) { + if (xpath.contains("fallbackRegionFormat") + || xpath.contains("exemplar") + || xpath.contains("/identity")) { continue; } - String valueLastRelease = lastRelease.getStringValue(xpath); String newPath = fixOldPath(xpath); String valueSnapshot = snapshot.getStringValue(newPath); - if (valueLastRelease.equals(valueSnapshot)) { + PathHeader ph = null; + + if (valueSnapshot == null) { + ph = phf.fromPath(newPath); + missing.put(locale, ph); + } + String valueLastRelease = lastRelease == null ? null : lastRelease.getStringValue(xpath); + if (valueSnapshot == null) { + ph = phf.fromPath(newPath); + missing.put(locale, ph); + } + + if (onlyMissing) { continue; } - String valueTrunk = trunk.getStringValue(newPath); - if (valueSnapshot == null && valueTrunk == null) { // committee deletion + if (valueSnapshot != null && Objects.equals(valueLastRelease, valueSnapshot)) { continue; } + String valueTrunk = trunk == null ? null : trunk.getStringValue(newPath); +// if (valueSnapshot == null && valueTrunk == null) { // committee deletion +// continue; +// } // skip inherited String baileyValue = snapshot.getConstructedBaileyValue(xpath, pathWhereFound, localeWhereFound); - if (!localeWhereFound.value.equals("root") - && !localeWhereFound.value.equals("code-fallback") + if (!"root".equals(localeWhereFound.value) + && !"code-fallback".equals(localeWhereFound.value) && CldrUtility.equals(valueSnapshot, baileyValue)) { continue; } - PathHeader ph = phf.fromPath(newPath); + ph = ph != null ? ph : phf.fromPath(newPath); results.put(ph, new Data(valueLastRelease, valueSnapshot, valueTrunk)); } if (results.isEmpty()) { @@ -89,12 +157,22 @@ public class GetChanges { int itemCount = 0; localeCount++; for (Entry<PathHeader, Data> entry : results.entrySet()) { - System.out.println(localeCount + "\t" + ++itemCount + "\t" + locale + "\t" + english.getName(locale) + "\tยซ" + entry.getKey() + "\t" - + entry.getValue()); + PathHeader ph = entry.getKey(); + String englishValue = englishCldrFile.getStringValue(ph.getOriginalPath()); + System.out.println(localeCount + + "\t" + ++itemCount + + "\t" + locale + + "\t" + english.getName(locale) + + "\t" + ph + + "\tยซ" + englishValue + + "ยป\t" + entry.getValue()); } totalCount += itemCount; } System.out.println("Total:\t" + totalCount); + for ( Entry<String, PathHeader> entry : missing.entries()) { + System.out.println(entry.getKey() + "\t" + entry.getValue()); + } } static Pattern OLD_PATH = PatternCache.get("//ldml/units/unit\\[@type=\"([^\"]*)\"]/unitPattern\\[@count=\"([^\"]*)\"](\\[@alt=\"([^\"]*)\"])?"); diff --git a/tools/java/org/unicode/cldr/tool/ToolConstants.java b/tools/java/org/unicode/cldr/tool/ToolConstants.java index d00dd26..74c4a3e 100644 --- a/tools/java/org/unicode/cldr/tool/ToolConstants.java +++ b/tools/java/org/unicode/cldr/tool/ToolConstants.java @@ -63,7 +63,8 @@ public class ToolConstants { "29.0", "30.0", "31.0", - "32.0" + "32.0", + "33.0" // add to this once the release is final! ); public static final String PREVIOUS_CHART_VERSION; diff --git a/tools/java/org/unicode/cldr/util/Annotations.java b/tools/java/org/unicode/cldr/util/Annotations.java index 75f3f5c..126843e 100644 --- a/tools/java/org/unicode/cldr/util/Annotations.java +++ b/tools/java/org/unicode/cldr/util/Annotations.java @@ -2,9 +2,11 @@ package org.unicode.cldr.util; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashSet; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -12,6 +14,7 @@ import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; +import org.unicode.cldr.test.EmojiSubdivisionNames; import org.unicode.cldr.tool.ChartAnnotations; import org.unicode.cldr.util.XMLFileReader.SimpleHandler; @@ -27,6 +30,8 @@ import com.ibm.icu.text.SimpleFormatter; import com.ibm.icu.text.Transform; import com.ibm.icu.text.UTF16; import com.ibm.icu.text.UnicodeSet; +import com.ibm.icu.text.UnicodeSet.SpanCondition; +import com.ibm.icu.text.UnicodeSetSpanner; import com.ibm.icu.util.ICUUncheckedIOException; public class Annotations { @@ -43,6 +48,7 @@ public class Annotations { static final Map<String, Map<String, AnnotationSet>> cache = new ConcurrentHashMap<>(); static final Set<String> LOCALES; static final String DIR; + private static final AnnotationSet ENGLISH_DATA; private final Set<String> annotations; private final String tts; @@ -71,10 +77,11 @@ public class Annotations { shortName.startsWith("#") || // skip other junk files shortName.startsWith(".") // || shortName.contains("001") // skip world english for now - ) continue; // skip dot files (backups, etc) + ) continue; // skip dot files (backups, etc) temp.add(dotSplitter.split(shortName).iterator().next()); } LOCALES = temp.build(); + ENGLISH_DATA = getDataSet("en"); } static class MyHandler extends SimpleHandler { @@ -191,95 +198,48 @@ public class Annotations { return LOCALES; } - static class EmojiConstants { - public static final String EMOJI_VARIANT_STRING = "\uFE0F"; - static final int FIRST_REGIONAL = 0x1F1E6; - static final int LAST_REGIONAL = 0x1F1FF; - public static final UnicodeSet REGIONAL_INDICATORS = new UnicodeSet(FIRST_REGIONAL, LAST_REGIONAL).freeze(); - public static final String KEYCAP_MARK_STRING = "\u20E3"; - public static final UnicodeSet MODIFIERS = new UnicodeSet(0x1F3FB, 0x1F3FF).freeze(); - public static final String JOINER_STRING = "\u200D"; - public static final String KISS = "๐"; - public static final String HEART = "โค"; - public static final String MALE_SIGN = "โ"; - public static final String FEMALE_SIGN = "โ"; - public static final String MAN = "๐จ"; - public static final String WOMAN = "๐ฉ"; - public static final String JOINER_MALE_SIGN = JOINER_STRING + MALE_SIGN; - public static final String JOINER_FEMALE_SIGN = JOINER_STRING + FEMALE_SIGN; - - //public static final UnicodeSet MODIFIERS_GENDER_SIGNS = new UnicodeSet(0x1F3FB, 0x1F3FF).add(MALE_SIGN).add(FEMALE_SIGN).freeze(); - public static String getFlagCode(String s) { - return String.valueOf((char) (s.codePointAt(0) - FIRST_REGIONAL + 'A')) + (char) (s.codePointAt(2) - FIRST_REGIONAL + 'A'); - } - - public static final UnicodeSet FAMILY_MARKERS = new UnicodeSet() - .add(0x1F466, 0x1F469).add(0x1F476) - .add(JOINER_STRING) - .freeze(); // boy, girl, man, woman, baby - public static final UnicodeSet REM_SKIP_SET = new UnicodeSet() - .add(JOINER_STRING) - .freeze(); - public static final UnicodeSet REM_GROUP_SKIP_SET = new UnicodeSet(REM_SKIP_SET) - .add(EmojiConstants.HEART).add(EmojiConstants.KISS) - .add(MALE_SIGN).add(FEMALE_SIGN) - .freeze(); - public static final String TAG_TERM = UTF16.valueOf(0xE007F); - public static final String BLACK_FLAG = UTF16.valueOf(0x1F3F4); - - public static String getTagSpec(String code) { - StringBuilder b = new StringBuilder(); - for (int codePoint : CharSequences.codePoints(code)) { - if (codePoint >= 0xE0020 && codePoint <= 0xE007E) { - b.appendCodePoint(codePoint - 0xE0000); - } - } - return b.toString(); - } - } - public static final class AnnotationSet { private static final CLDRConfig CONFIG = CLDRConfig.getInstance(); static final Factory factory = CONFIG.getCldrFactory(); static final CLDRFile ENGLISH = CONFIG.getEnglish(); - static final Factory SUBDIVISION_FACTORY = Factory.make(CLDRPaths.COMMON_DIRECTORY + "subdivisions/", ".*"); - static final CLDRFile ENGLISH_SUBDIVISIONS = SUBDIVISION_FACTORY.make("en", true); + static final CLDRFile ENGLISH_ANNOTATIONS = null; + static final Map<String,String> englishSubdivisionIdToName = EmojiSubdivisionNames.getSubdivisionIdToName("en"); + //CLDRConfig.getInstance().getAnnotationsFactory().make("en", false); private final String locale; private final UnicodeMap<Annotations> baseData; private final UnicodeMap<Annotations> unresolvedData; private final CLDRFile cldrFile; - private final CLDRFile cldrFileSubdivisions; + private final Map<String, String> subdivisionIdToName; private final SimpleFormatter initialPattern; private final Pattern initialRegexPattern; - private final SimpleFormatter listPattern; + private final XListFormatter listPattern; private final Set<String> flagLabelSet; private final Set<String> keycapLabelSet; private final String keycapLabel; + private final String flagLabel; // private final String maleLabel; // private final String femaleLabel; private final Map<String, Annotations> localeCache = new ConcurrentHashMap<>(); - public AnnotationSet(String locale, UnicodeMap<Annotations> source, UnicodeMap<Annotations> resolvedSource) { + static UnicodeSetSpanner uss = new UnicodeSetSpanner(EmojiConstants.COMPONENTS); // must be sync'ed + + private AnnotationSet(String locale, UnicodeMap<Annotations> source, UnicodeMap<Annotations> resolvedSource) { this.locale = locale; unresolvedData = source.freeze(); this.baseData = resolvedSource == null ? unresolvedData : resolvedSource.freeze(); cldrFile = factory.make(locale, true); - CLDRFile _cldrFileSubdivisions = null; - try { - _cldrFileSubdivisions = SUBDIVISION_FACTORY.make(locale, true); - } catch (Exception e) { - } - cldrFileSubdivisions = _cldrFileSubdivisions; - listPattern = SimpleFormatter.compile(getStringValue("//ldml/listPatterns/listPattern[@type=\"unit-short\"]/listPatternPart[@type=\"2\"]")); + subdivisionIdToName = EmojiSubdivisionNames.getSubdivisionIdToName(locale); + listPattern = new XListFormatter(cldrFile, EmojiConstants.COMPOSED_NAME_LIST); final String initialPatternString = getStringValue("//ldml/characterLabels/characterLabelPattern[@type=\"category-list\"]"); initialPattern = SimpleFormatter.compile(initialPatternString); final String regexPattern = ("\\Q" + initialPatternString.replace("{0}", "\\E.*\\Q").replace("{1}", "\\E.*\\Q") + "\\E") .replace("\\Q\\E", ""); // HACK to detect use of prefix pattern initialRegexPattern = Pattern.compile(regexPattern); flagLabelSet = getLabelSet("flag"); + flagLabel = flagLabelSet.isEmpty() ? null : flagLabelSet.iterator().next(); keycapLabelSet = getLabelSet("keycap"); keycapLabel = keycapLabelSet.isEmpty() ? null : keycapLabelSet.iterator().next(); // maleLabel = getStringValue("//ldml/characterLabels/characterLabel[@type=\"male\"]"); @@ -309,7 +269,7 @@ public class Annotations { } String sourceLocale = cldrFile2.getSourceLocaleID(xpath, null); if (sourceLocale.equals(XMLSource.CODE_FALLBACK_ID) || sourceLocale.equals(XMLSource.ROOT_ID)) { - return BAD_MARKER + result; + return MISSING_MARKER + result; } return result; } @@ -365,6 +325,9 @@ public class Annotations { } private Annotations synthesize(String code, Transform<String, String> otherSource) { + if (code.equals("๐ฑ๐ปโโ")) { + int debug = 0; + } String shortName = null; int len = code.codePointCount(0, code.length()); boolean isKeycap10 = code.equals("๐"); @@ -388,12 +351,26 @@ public class Annotations { } else if (EmojiConstants.REGIONAL_INDICATORS.containsAll(code)) { String countryCode = EmojiConstants.getFlagCode(code); String path = CLDRFile.getKey(CLDRFile.TERRITORY_NAME, countryCode); - return new Annotations(flagLabelSet, getStringValue(path)); + String regionName = getStringValue(path); + if (regionName == null) { + regionName = ENGLISH_MARKER + ENGLISH.getStringValue(path); + } + String flagName = flagLabel == null ? regionName : initialPattern.format(flagLabel, regionName); + return new Annotations(flagLabelSet, flagName); } else if (code.startsWith(EmojiConstants.BLACK_FLAG) && code.endsWith(EmojiConstants.TAG_TERM)) { String subdivisionCode = EmojiConstants.getTagSpec(code); - String path = CLDRFile.getKey(CLDRFile.SUBDIVISION_NAME, subdivisionCode); - return new Annotations(flagLabelSet, getStringValue(path, cldrFileSubdivisions, ENGLISH_SUBDIVISIONS)); + String subdivisionName = subdivisionIdToName.get(subdivisionCode); + if (subdivisionName == null) { + subdivisionName = englishSubdivisionIdToName.get(subdivisionCode); + if (subdivisionName != null) { + subdivisionName = ENGLISH_MARKER + subdivisionCode; + } else { + subdivisionName = MISSING_MARKER + subdivisionCode; + } + } + String flagName = flagLabel == null ? subdivisionName : initialPattern.format(flagLabel, subdivisionName); + return new Annotations(flagLabelSet, flagName); } else if (isKeycap10 || code.contains(EmojiConstants.KEYCAP_MARK_STRING)) { final String rem = code.equals("๐") ? "10" : UTF16.valueOf(code.charAt(0)); shortName = initialPattern.format(keycapLabel, rem); @@ -402,10 +379,11 @@ public class Annotations { UnicodeSet skipSet = EmojiConstants.REM_SKIP_SET; String rem = ""; SimpleFormatter startPattern = initialPattern; - - if (EmojiConstants.MODIFIERS.containsSome(code)) { - rem = EmojiConstants.MODIFIERS.stripFrom(code, false); - code = EmojiConstants.MODIFIERS.stripFrom(code, true); + if (EmojiConstants.COMPONENTS.containsSome(code)) { + synchronized (uss) { + rem = uss.deleteFrom(code, SpanCondition.NOT_CONTAINED); + code = uss.deleteFrom(code, SpanCondition.CONTAINED); + } } if (code.contains(EmojiConstants.JOINER_STRING)) { // if (code.endsWith(EmojiConstants.JOINER_MALE_SIGN)){ @@ -466,6 +444,10 @@ public class Annotations { return null; } } + + boolean hackBlond = EmojiConstants.HAIR_EXPLICIT.contains(base.codePointAt(0)); + List<String> arguments = new ArrayList<>(); + for (int mod : CharSequences.codePoints(rem)) { if (ignore.contains(mod)) { continue; @@ -479,13 +461,40 @@ public class Annotations { } if (modName == null) { needMarker = true; - continue; + if (ENGLISH_DATA != null) { + Annotations engName = ENGLISH_DATA.baseData.get(mod); + if (engName != null) { + modName = engName.getShortName(); + } + } + if (modName == null) { + modName = Utility.hex(mod); // ultimate fallback + } + } + if (hackBlond && shortName != null) { + // HACK: make the blond names look like the other hair names + // Split the short name into pieces, if possible, and insert the modName first + String sep = initialPattern.format("", ""); + int splitPoint = shortName.indexOf(sep); + if (splitPoint >= 0) { + String modName0 = shortName.substring(splitPoint+sep.length()); + shortName = shortName.substring(0, splitPoint); + if (modName != null) { + arguments.add(modName); + annotations.add(modName); + } + modName = modName0; + } + hackBlond = false; + } + + if (modName != null) { + arguments.add(modName); + annotations.add(modName); } - shortName = shortName == null ? modName : pattern.format(shortName, modName); - if (modName != null) annotations.add(modName); - pattern = listPattern; } - Annotations result = new Annotations(annotations, (needMarker ? BAD_MARKER : "") + shortName); + shortName = pattern.format(shortName, listPattern.format(arguments)); + Annotations result = new Annotations(annotations, (needMarker ? ENGLISH_MARKER : "") + shortName); return result; } diff --git a/tools/java/org/unicode/cldr/util/CLDRConfig.java b/tools/java/org/unicode/cldr/util/CLDRConfig.java index 23ec5e7..8d386bf 100644 --- a/tools/java/org/unicode/cldr/util/CLDRConfig.java +++ b/tools/java/org/unicode/cldr/util/CLDRConfig.java @@ -62,6 +62,11 @@ public class CLDRConfig extends Properties { * Object to use for synchronization when interacting with Factory */ private static final Object ANNOTATIONS_FACTORY_SYNC = new Object(); + + /** + * Object to use for synchronization when interacting with Factory + */ + private static final Object SUBDIVISION_FACTORY_SYNC = new Object(); /** * Object used for synchronization when interacting with SupplementalData @@ -74,6 +79,11 @@ public class CLDRConfig extends Properties { private static final Object GET_COLLATOR_SYNC = new Object(); /** + * Object used for synchronization in getCollator() + */ + private static final Object GET_COLLATOR_SYNC_ROOT = new Object(); + + /** * Object used for synchronization in getStandardCodes() */ private static final Object GET_STANDARD_CODES_SYNC = new Object(); @@ -152,7 +162,9 @@ public class CLDRConfig extends Properties { private Factory collationFactory; private Factory rbnfFactory; private Factory annotationsFactory; + private Factory subdivisionFactory; private Factory supplementalFactory; + private RuleBasedCollator colRoot; private RuleBasedCollator col; private Phase phase = null; // default @@ -269,6 +281,15 @@ public class CLDRConfig extends Properties { return annotationsFactory; } + public Factory getSubdivisionFactory() { + synchronized (SUBDIVISION_FACTORY_SYNC) { + if (subdivisionFactory == null) { + subdivisionFactory = Factory.make(CLDRPaths.SUBDIVISIONS_DIRECTORY, ".*"); + } + } + return subdivisionFactory; + } + public Factory getMainAndAnnotationsFactory() { synchronized (FULL_FACTORY_SYNC) { if (mainAndAnnotationsFactory == null) { @@ -339,6 +360,25 @@ public class CLDRConfig extends Properties { return getCLDRFile("root", true); } + public Collator getCollatorRoot() { + synchronized (GET_COLLATOR_SYNC_ROOT) { + if (colRoot == null) { + CLDRFile root = getCollationFactory().make("root", false); + String rules = root.getStringValue("//ldml/collations/collation[@type=\"emoji\"][@visibility=\"external\"]/cr"); + try { + colRoot = new RuleBasedCollator(rules); + } catch (Exception e) { + colRoot = (RuleBasedCollator) getCollator(); + return colRoot; + } + colRoot.setStrength(Collator.IDENTICAL); + colRoot.setNumericCollation(true); + colRoot.freeze(); + } + } + return colRoot; + } + public Collator getCollator() { synchronized (GET_COLLATOR_SYNC) { if (col == null) { diff --git a/tools/java/org/unicode/cldr/util/CLDRFile.java b/tools/java/org/unicode/cldr/util/CLDRFile.java index 58b8182..e6c9e66 100644 --- a/tools/java/org/unicode/cldr/util/CLDRFile.java +++ b/tools/java/org/unicode/cldr/util/CLDRFile.java @@ -116,7 +116,7 @@ public class CLDRFile implements Freezable<CLDRFile>, Iterable<String> { public static final String SUPPLEMENTAL_NAME = "supplementalData"; public static final String SUPPLEMENTAL_METADATA = "supplementalMetadata"; public static final String SUPPLEMENTAL_PREFIX = "supplemental"; - public static final String GEN_VERSION = "33"; + public static final String GEN_VERSION = "33.1"; public static final List<String> SUPPLEMENTAL_NAMES = Arrays.asList("characters", "coverageLevels", "dayPeriods", "genderList", "languageInfo", "languageGroup", "likelySubtags", "metaZones", "numberingSystems", "ordinals", "plurals", "postalCodeData", "rgScope", "supplementalData", "supplementalMetadata", diff --git a/tools/java/org/unicode/cldr/util/Emoji.java b/tools/java/org/unicode/cldr/util/Emoji.java index 7592105..c7e4cce 100644 --- a/tools/java/org/unicode/cldr/util/Emoji.java +++ b/tools/java/org/unicode/cldr/util/Emoji.java @@ -23,7 +23,7 @@ public class Emoji { public static final UnicodeSet TAGS = new UnicodeSet(0xE0000, 0xE007F).freeze(); public static final UnicodeSet FAMILY = new UnicodeSet("[\u200D ๐ฆ-๐ฉ ๐ โค]").freeze(); public static final UnicodeSet GENDER = new UnicodeSet().add(0x2640).add(0x2642).freeze(); - public static final UnicodeSet SPECIALS = new UnicodeSet("[{๐ณโ๐}{๐โ๐จ}]").freeze(); + public static final UnicodeSet SPECIALS = new UnicodeSet("[{๐ณโ๐}{๐โ๐จ}{๐ดโโ }]").freeze(); public static final UnicodeSet MAN_WOMAN = new UnicodeSet("[๐จ ๐ฉ]").freeze(); public static final UnicodeSet OBJECT = new UnicodeSet("[๐ฉ ๐ ๐พ ๐ณ ๐ซ ๐ญ ๐จ ๐ โ ๐ ๐ค ๐ป ๐ฌ ๐ผ ๐ง โ โ]").freeze(); @@ -31,6 +31,7 @@ public class Emoji { static final UnicodeMap<String> emojiToMinorCategory = new UnicodeMap<>(); static final Map<String, Integer> minorToOrder = new HashMap<>(); static final UnicodeSet nonConstructed = new UnicodeSet(); + static final UnicodeSet allRgi = new UnicodeSet(); static { /* @@ -60,11 +61,11 @@ public class Emoji { } Iterator<String> it = semi.split(line).iterator(); String emojiHex = it.next(); -// String type = it.next(); -// if (!type.startsWith("fully-qualified")) { -// continue; -// } String original = Utility.fromHex(emojiHex, 4, " "); + String type = it.next(); + if (type.startsWith("fully-qualified")) { + allRgi.add(original); + } emojiToMajorCategory.put(original, majorCategory); emojiToMinorCategory.put(original, minorCategory); @@ -95,10 +96,20 @@ public class Emoji { emojiToMinorCategory.freeze(); nonConstructed.add(MODIFIERS); // needed for names nonConstructed.freeze(); + allRgi.freeze(); + } + + public static UnicodeSet getAllRgi() { + return allRgi; } public static String getMinorCategory(String emoji) { - return CldrUtility.ifNull(emojiToMinorCategory.get(emoji), "Component"); + String minorCat = emojiToMinorCategory.get(emoji); + if (minorCat == null) { + throw new InternalCldrException("No minor category (aka subgroup) found for " + emoji + + ". Update emoji-test.txt to latest, and adjust PathHeader.. functionMap.put(\"minor\", ..."); + } + return minorCat; } public static int getMinorToOrder(String minor) { @@ -107,7 +118,12 @@ public class Emoji { } public static String getMajorCategory(String emoji) { - return CldrUtility.ifNull(emojiToMajorCategory.get(emoji), "Component"); + String majorCat = emojiToMajorCategory.get(emoji); + if (majorCat == null) { + throw new InternalCldrException("No minor category (aka subgroup) found for " + emoji + + ". Update emoji-test.txt to latest, and adjust PathHeader.. functionMap.put(\"major\", ..."); + } + return majorCat; } public static Set<String> getMajorCategories() { diff --git a/tools/java/org/unicode/cldr/util/EmojiConstants.java b/tools/java/org/unicode/cldr/util/EmojiConstants.java new file mode 100644 index 0000000..ba24679 --- /dev/null +++ b/tools/java/org/unicode/cldr/util/EmojiConstants.java @@ -0,0 +1,107 @@ +package org.unicode.cldr.util; + +import java.util.Locale; + +import org.unicode.cldr.util.XListFormatter.ListTypeLength; + +import com.ibm.icu.lang.CharSequences; +import com.ibm.icu.text.UTF16; +import com.ibm.icu.text.UnicodeSet; + +public class EmojiConstants { + public static final String EMOJI_VARIANT_STRING = "\uFE0F"; + static final int FIRST_REGIONAL = 0x1F1E6; + static final int LAST_REGIONAL = 0x1F1FF; + public static final UnicodeSet REGIONAL_INDICATORS = new UnicodeSet(FIRST_REGIONAL, LAST_REGIONAL).freeze(); + public static final String KEYCAP_MARK_STRING = "\u20E3"; + public static final UnicodeSet MODIFIERS = new UnicodeSet(0x1F3FB, 0x1F3FF).freeze(); + public static final UnicodeSet HAIR = new UnicodeSet(0x1F9B0, 0x1F9B3).freeze(); + public static final char JOINER = '\u200D'; + public static final String JOINER_STRING = String.valueOf(JOINER); + public static final UnicodeSet COMPONENTS = new UnicodeSet(EmojiConstants.MODIFIERS) + .add(EmojiConstants.fromCodePoints(JOINER,0x1F9B0)) + .add(EmojiConstants.fromCodePoints(JOINER,0x1F9B1)) + .add(EmojiConstants.fromCodePoints(JOINER,0x1F9B2)) + .add(EmojiConstants.fromCodePoints(JOINER,0x1F9B3)) + .freeze(); + + public static final String KISS = "๐"; + public static final String HEART = "โค"; + public static final String MALE_SIGN = "โ"; + public static final String FEMALE_SIGN = "โ"; + public static final String MAN = "๐จ"; + public static final String WOMAN = "๐ฉ"; + public static final String JOINER_MALE_SIGN = JOINER_STRING + MALE_SIGN; + public static final String JOINER_FEMALE_SIGN = JOINER_STRING + FEMALE_SIGN; + public static final UnicodeSet HAIR_EXPLICIT = new UnicodeSet("[๐ง ๐ฑ]").freeze(); + + public static final ListTypeLength COMPOSED_NAME_LIST = ListTypeLength.UNIT_SHORT; + + //public static final UnicodeSet MODIFIERS_GENDER_SIGNS = new UnicodeSet(0x1F3FB, 0x1F3FF).add(MALE_SIGN).add(FEMALE_SIGN).freeze(); + public static String getFlagCode(String s) { + return String.valueOf((char) (s.codePointAt(0) - FIRST_REGIONAL + 'A')) + (char) (s.codePointAt(2) - FIRST_REGIONAL + 'A'); + } + + public static String getEmojiFromRegionCodes(String chars) { + return new StringBuilder() + .appendCodePoint(chars.codePointAt(0) + FIRST_REGIONAL - 'A') + .appendCodePoint(chars.codePointAt(1) + FIRST_REGIONAL - 'A') + .toString(); + } + + public static final int TAG_BASE = 0xE0000; + public static final int TAG_TERM_CHAR = 0xE007F; + + public static String getEmojiFromSubdivisionCodes(String string) { + string = string.toLowerCase(Locale.ROOT).replace("-",""); + StringBuilder result = new StringBuilder().appendCodePoint(0x1F3F4); + for (int cp : CharSequences.codePoints(string)) { + result.appendCodePoint(TAG_BASE + cp); + } + return result.appendCodePoint(TAG_TERM_CHAR).toString(); + } + + public static final UnicodeSet FAMILY_MARKERS = new UnicodeSet() + .add(0x1F466, 0x1F469).add(0x1F476) + .add(JOINER_STRING) + .freeze(); // boy, girl, man, woman, baby + public static final UnicodeSet REM_SKIP_SET = new UnicodeSet() + .add(JOINER_STRING) + .freeze(); + public static final UnicodeSet REM_GROUP_SKIP_SET = new UnicodeSet(REM_SKIP_SET) + .add(EmojiConstants.HEART).add(EmojiConstants.KISS) + .add(MALE_SIGN).add(FEMALE_SIGN) + .freeze(); + public static final String TAG_TERM = UTF16.valueOf(0xE007F); + public static final String BLACK_FLAG = UTF16.valueOf(0x1F3F4); + + public static String getTagSpec(String code) { + StringBuilder b = new StringBuilder(); + for (int codePoint : CharSequences.codePoints(code)) { + if (codePoint >= 0xE0020 && codePoint <= 0xE007E) { + b.appendCodePoint(codePoint - 0xE0000); + } + } + return b.toString(); + } + + // U+1F3F4 U+E0067 U+E0062 U+E0065 U+E006E U+E0067 U+E007F + public static String toTagSeq(String subdivisionCode) { + StringBuilder b = new StringBuilder().appendCodePoint(0x1F3F4); + for (int i = 0; i < subdivisionCode.length(); ++i) { + b.appendCodePoint(subdivisionCode.charAt(i) + 0xE0000); + } + return b.appendCodePoint(0xE007F).toString(); + } + + public static CharSequence fromCodePoints(int... codePoints) { + return EmojiConstants.appendCodePoints(new StringBuilder(), codePoints).toString(); + } + + public static StringBuilder appendCodePoints(StringBuilder b, int... codePoints) { + for (int i = 0; i < codePoints.length; ++i) { + b.appendCodePoint(codePoints[i]); + } + return b; + } +}
\ No newline at end of file diff --git a/tools/java/org/unicode/cldr/util/LanguageGroup.java b/tools/java/org/unicode/cldr/util/LanguageGroup.java index 7c4780a..aa10e8a 100644 --- a/tools/java/org/unicode/cldr/util/LanguageGroup.java +++ b/tools/java/org/unicode/cldr/util/LanguageGroup.java @@ -50,7 +50,7 @@ public enum LanguageGroup { add(temp, romance, "fr", "pt", "gl", "es", "ca", "ast", "it", "rm", "ro"); add(temp, slavic, "pl", "cs", "sk", "sl", "hr", "bs", "mk", "sr", "bg", "ru", "be", "uk"); add(temp, baltic, "lt", "lv"); - add(temp, other_indo, "el", "sq", "hy", "fa", "ps", "os"); + add(temp, other_indo, "el", "hy", "sq", "fa", "ps", "os"); add(temp, indic, "ur", "hi", "gu", "sd", "bn", "as", "ccp", "or", "mr", "ne", "pa", "si"); add(temp, dravidian, "ta", "te", "ml", "kn"); add(temp, cjk, "zh", "yue", "ja", "ko"); @@ -58,7 +58,7 @@ public enum LanguageGroup { add(temp, uralic, "hu", "fi", "et", "se", "smn"); add(temp, afroasiatic, "ar", "mt", "he", "om", "so", "ha", "am", "tzm", "zgh"); add(temp, tai, "th", "lo"); - add(temp, austronesian, "id", "ms", "fil", "haw"); + add(temp, austronesian, "id", "ms", "jv", "fil", "haw"); add(temp, austroasiatic, "vi", "km"); add(temp, niger_congo, "sw", "swc", "yo", "ig", "ff", "sn", "zu"); add(temp, other, "ka", "eu", "mn", "naq"); @@ -81,7 +81,7 @@ public enum LanguageGroup { } public static LanguageGroup get(ULocale locale) { - return CldrUtility.ifNull(LANGUAGE_GROUP.get(locale), LanguageGroup.other); + return CldrUtility.ifNull(LANGUAGE_GROUP.get(new ULocale(locale.getLanguage())), LanguageGroup.other); } public static Set<ULocale> getExplicit() { @@ -98,6 +98,7 @@ public enum LanguageGroup { * @return */ public static int rankInGroup(ULocale locale) { + locale = new ULocale(locale.getLanguage()); LanguageGroup group = LANGUAGE_GROUP.get(locale); if (group == null) { return Integer.MAX_VALUE; diff --git a/tools/java/org/unicode/cldr/util/PathHeader.java b/tools/java/org/unicode/cldr/util/PathHeader.java index 9615fe2..e0e6637 100644 --- a/tools/java/org/unicode/cldr/util/PathHeader.java +++ b/tools/java/org/unicode/cldr/util/PathHeader.java @@ -116,8 +116,8 @@ public class PathHeader implements Comparable<PathHeader> { // account for digits, and "some" future proofing. order = ordering < 0 ? source.charAt(pos) - : 0x10000 + ordering; - mainOrder = source.substring(0, pos); + : 0x10000 + ordering; + mainOrder = source.substring(0, pos); } @Override @@ -296,7 +296,7 @@ public class PathHeader implements Comparable<PathHeader> { "\\[@alt=\"([^\"]*+)\"]") .matcher(""); - static final Collator alphabetic = CLDRConfig.getInstance().getCollator();// (RuleBasedCollator) Collator.getInstance(ULocale.ENGLISH); + static final Collator alphabetic = CLDRConfig.getInstance().getCollatorRoot(); // static final RuleBasedCollator alphabetic = (RuleBasedCollator) Collator // .getInstance(ULocale.ENGLISH); @@ -436,7 +436,7 @@ public class PathHeader implements Comparable<PathHeader> { + "\t" + pageId + "\t" + header // + "\t" + headerOrder + "\t" + code // + "\t" + codeOrder - ; + ; } @Override @@ -976,7 +976,7 @@ public class PathHeader implements Comparable<PathHeader> { "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - "Und" }; + "Und" }; static List<String> days = Arrays.asList("sun", "mon", "tue", "wed", "thu", "fri", "sat"); @@ -1198,7 +1198,7 @@ public class PathHeader implements Comparable<PathHeader> { for (int i = 0; i < languageRangeStartPoints.length; i++) { if (firstLetter >= languageRangeStartPoints[i] && firstLetter <= languageRangeEndPoints[i]) { return "Languages (" + Character.toUpperCase(languageRangeStartPoints[i]) + "-" + Character.toUpperCase(languageRangeEndPoints[i]) - + ")"; + + ")"; } } return "Languages"; @@ -1237,13 +1237,13 @@ public class PathHeader implements Comparable<PathHeader> { }); functionMap.put("categoryFromTerritory", catFromTerritory = new Transform<String, String>() { - public String transform(String source) { - String territory = getSubdivisionsTerritory(source, null); - String container = Containment.getContainer(territory); - order = Containment.getOrder(territory); - return englishFile.getName(CLDRFile.TERRITORY_NAME, container); - } - }); + public String transform(String source) { + String territory = getSubdivisionsTerritory(source, null); + String container = Containment.getContainer(territory); + order = Containment.getOrder(territory); + return englishFile.getName(CLDRFile.TERRITORY_NAME, container); + } + }); functionMap.put("territorySection", new Transform<String, String>() { final Set<String> specialRegions = new HashSet<String>(Arrays.asList("EZ", "EU", "QO", "UN", "ZZ")); @@ -1274,14 +1274,14 @@ public class PathHeader implements Comparable<PathHeader> { }); functionMap.put("categoryFromTimezone", catFromTimezone = new Transform<String, String>() { - public String transform(String source0) { - String territory = Containment.getRegionFromZone(source0); - if (territory == null) { - territory = "ZZ"; - } - return catFromTerritory.transform(territory); + public String transform(String source0) { + String territory = Containment.getRegionFromZone(source0); + if (territory == null) { + territory = "ZZ"; } - }); + return catFromTerritory.transform(territory); + } + }); functionMap.put("timeZonePage", new Transform<String, String>() { Set<String> singlePageTerritories = new HashSet<String>(Arrays.asList("AQ", "RU", "ZZ")); @@ -1676,7 +1676,8 @@ public class PathHeader implements Comparable<PathHeader> { public String transform(String source) { String major = Emoji.getMajorCategory(source); // check that result is reasonable by running through PageId. - if (!major.equals("Smileys & People")) { + switch(major) { + default: PageId pageId2 = PageId.forString(major); if (pageId2.getSectionId() != SectionId.Characters) { if (pageId2 == PageId.Symbols) { @@ -1684,12 +1685,15 @@ public class PathHeader implements Comparable<PathHeader> { } } return pageId2.toString(); - } - String minorCat = Emoji.getMinorCategory(source); - if (minorCat.startsWith("person")) { - return PageId.People.toString(); - } else { - return PageId.Smileys.toString(); + case "Smileys & People": + String minorCat = Emoji.getMinorCategory(source); + if (minorCat.equals("skin-tone") || minorCat.equals("hair-style")) { + return PageId.Component.toString(); + } else if (!minorCat.contains("face")) { + return PageId.People.toString(); + } else { + return PageId.Smileys.toString(); + } } } }); @@ -1749,6 +1753,9 @@ public class PathHeader implements Comparable<PathHeader> { * @return */ private static String fix(String input, int orderIn) { + if (input.contains("๐ฑ")) { + int debug = 0; + } String oldInput = input; input = RegexLookup.replace(input, args.value); order = orderIn; diff --git a/tools/java/org/unicode/cldr/util/XListFormatter.java b/tools/java/org/unicode/cldr/util/XListFormatter.java new file mode 100644 index 0000000..6d0b150 --- /dev/null +++ b/tools/java/org/unicode/cldr/util/XListFormatter.java @@ -0,0 +1,82 @@ +package org.unicode.cldr.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import com.ibm.icu.lang.CharSequences; +import com.ibm.icu.text.ListFormatter; +import com.ibm.icu.text.SimpleFormatter; +import com.ibm.icu.text.UTF16; + +public class XListFormatter { + + public enum ListTypeLength { + AND_WIDE(""), + AND_SHORT("[@type=\"standard-short\"]"), + OR_WIDE("[@type=\"or\"]"), + UNIT_WIDE("[@type=\"unit\"]"), + UNIT_SHORT("[@type=\"unit-short\"]"), + UNIT_NARROW("[@type=\"unit-narrow\"]") + ; + + public static final ListTypeLength NORMAL = AND_WIDE; + + final String typeString; + + static final Map<String, ListTypeLength> stringToEnum; + static { + Map<String, ListTypeLength> _stringToEnum = new LinkedHashMap<>(); + for (ListTypeLength value : values()) { + if (value != NORMAL) { + _stringToEnum.put(value.typeString.substring(value.typeString.indexOf('"')+1, value.typeString.lastIndexOf('"')), value); + } + } + stringToEnum = ImmutableMap.copyOf(_stringToEnum); + } + private ListTypeLength(String typeString) { + this.typeString = typeString; + } + public static ListTypeLength from(String listPatternType) { + if (listPatternType == null) { + return NORMAL; + } + return stringToEnum.get(listPatternType); + } + public String getPath() { + return "//ldml/listPatterns/listPattern" + + typeString + + "/listPatternPart[@type=\"{0}\"]"; + } + } + + private ListFormatter listFormatter; + + public XListFormatter(CLDRFile cldrFile, ListTypeLength listTypeLength) { + SimpleFormatter listPathFormat = SimpleFormatter.compile(listTypeLength.getPath()); + String doublePattern = cldrFile.getWinningValue(listPathFormat.format("2")); + String startPattern = cldrFile.getWinningValue(listPathFormat.format("start")); + String middlePattern = cldrFile.getWinningValue(listPathFormat.format("middle")); + String endPattern = cldrFile.getWinningValue(listPathFormat.format("end")); + listFormatter = new ListFormatter(doublePattern, startPattern, middlePattern, endPattern); + } + + public String format(Object... items) { + return listFormatter.format(items); + } + + public String format(Collection<?> items) { + return listFormatter.format(items); + } + + public String formatCodePoints(String items) { + List<String> source = new ArrayList<>(); + for (int sourceInt : CharSequences.codePoints(items)) { // TODO add utility in CharSequences + source.add(UTF16.valueOf(sourceInt)); + } + return listFormatter.format(source); + } +}
\ No newline at end of file diff --git a/tools/java/org/unicode/cldr/util/XMLSource.java b/tools/java/org/unicode/cldr/util/XMLSource.java index bb626ee..b752301 100644 --- a/tools/java/org/unicode/cldr/util/XMLSource.java +++ b/tools/java/org/unicode/cldr/util/XMLSource.java @@ -1233,6 +1233,7 @@ public abstract class XMLSource implements Freezable<XMLSource>, Iterable<String { "fullwide", "numbers" }, { "gb2312han", "collation" }, { "geor", "numbers" }, + { "gong", "numbers" }, { "gonm", "numbers" }, { "gregorian", "calendar" }, { "grek", "numbers" }, @@ -1296,6 +1297,7 @@ public abstract class XMLSource implements Freezable<XMLSource>, Iterable<String { "pinyin", "collation" }, { "reformed", "collation" }, { "roc", "calendar" }, + { "rohg", "numbers" }, { "roman", "numbers" }, { "romanlow", "numbers" }, { "saur", "numbers" }, diff --git a/tools/java/org/unicode/cldr/util/data/Script_Metadata.csv b/tools/java/org/unicode/cldr/util/data/Script_Metadata.csv index fe1ee59..ffea0df 100644 --- a/tools/java/org/unicode/cldr/util/data/Script_Metadata.csv +++ b/tools/java/org/unicode/cldr/util/data/Script_Metadata.csv @@ -39,7 +39,7 @@ WR,Name,Script_Code,Age,Size,Sample,Sample_Code,Origin Country,~Density,Likely L 38,Yi,Yiii,3,"1,220",๊,A288,China,3,Sichuan Yi,ii,Limited_Use,no,Yes,no,Yes,no
39,Samaritan,Samr,5.2,61,เ ,800,Israel,1,Samaritan Hebrew,smp,Exclusion,Yes,no,min,no,no
40,Coptic,Copt,1.1,165,ฯข,3E2,Egypt,1,Coptic,cop,Exclusion,no,no,min,no,Yes
-41,Mongolian,Mong,3,153,แ ฆ,1826,Mongolia,1,Mongolian,mn,Limited_Use,no,no,Yes,no,no
+41,Mongolian,Mong,3,153,แ ฆ,1826,Mongolia,1,Mongolian,mn,Exclusion,no,no,Yes,no,no
42,Glagolitic,Glag,4.1,94,โฐ,2C00,Bulgaria,1,Church Slavic,cu,Exclusion,no,no,no,no,Yes
43,Vai,Vaii,5.1,300,๊,A549,Liberia,2,Vai,vai,Limited_Use,no,no,no,Yes,no
44,Balinese,Bali,5,121,แฌ
,1B05,Indonesia,1,Balinese,ban,Limited_Use,no,no,Yes,no,no
@@ -138,7 +138,7 @@ WR,Name,Script_Code,Age,Size,Sample,Sample_Code,Origin Country,~Density,Likely L 137,Osage,Osge,9,0,๐ต,104B5,USA,1,Osage,osa,Limited_Use,no,no,no,no,Yes
138,Tangut,Tang,9,0,๐ฉ,18229,China,3,Tangut,txg,Exclusion,no,Yes,no,Yes,no
139,Newa,Newa,9,0,๐,11412,Nepal,1,Newari,new,Limited_Use,no,no,Yes,no,no
-140,Masaram Gondi,Gonm,10,75,๐ด,11D10,India,1,Gondi,gon,Exclusion,no,no,Yes,no,no
+140,Masaram Gondi,Gonm,10,75,๐ด,11D10,India,1,Aheri Gondi,esg,Exclusion,no,no,Yes,no,no
141,Nushu,Nshu,10,397,๐,1B1C4,China,2,Chinese language family,zhx,Exclusion,no,Yes,no,Yes,no
142,Soyombo,Soyo,10,81,๐ฉ,11A5C,Mongolia,1,Classical Mongolian,cmg,Exclusion,no,no,Yes,no,no
143,Zanabazar Square,Zanb,10,69,๐จ,11A0B,Mongolia,1,Classical Mongolian,cmg,Exclusion,no,no,Yes,no,no
diff --git a/tools/java/org/unicode/cldr/util/data/emoji/emoji-test.txt b/tools/java/org/unicode/cldr/util/data/emoji/emoji-test.txt index c2d334f..bc34cc5 100644 --- a/tools/java/org/unicode/cldr/util/data/emoji/emoji-test.txt +++ b/tools/java/org/unicode/cldr/util/data/emoji/emoji-test.txt @@ -1,11 +1,11 @@ # emoji-test.txt -# Date: 2017-03-21, 12:10:30 GMT -# ยฉ 2017 Unicodeยฎ, Inc. +# Date: 2018-05-22, 17:07:43 GMT +# ยฉ 2018 Unicodeยฎ, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use, see http://www.unicode.org/terms_of_use.html # -# Emoji Keyboard/Display Test Data for UTR #51 -# Version: 5.0 +# Emoji Keyboard/Display Test Data for UTS #51 +# Version: 11.0 # # For documentation and usage, see http://www.unicode.org/reports/tr51 # @@ -13,8 +13,8 @@ # Format # Code points; status # emoji name # Status -# fully-qualified โ see โEmoji Implementation Notesโ in UTR#51 -# non-fully-qualified โ see โEmoji Implementation Notesโ in UTR#51 +# fully-qualified โ see โEmoji Implementation Notesโ in UTS #51 +# non-fully-qualified โ see โEmoji Implementation Notesโ in UTS #51 # Notes: # โข This currently omits the 12 keycap bases, the 5 modifier characters, and 26 singleton Regional Indicator characters # โข The file is in CLDR order, not codepoint order. This is recommended (but not required!) for keyboard palettes. @@ -24,19 +24,20 @@ # subgroup: face-positive 1F600 ; fully-qualified # ๐ grinning face -1F601 ; fully-qualified # ๐ grinning face with smiling eyes +1F601 ; fully-qualified # ๐ beaming face with smiling eyes 1F602 ; fully-qualified # ๐ face with tears of joy 1F923 ; fully-qualified # ๐คฃ rolling on the floor laughing -1F603 ; fully-qualified # ๐ smiling face with open mouth -1F604 ; fully-qualified # ๐ smiling face with open mouth & smiling eyes -1F605 ; fully-qualified # ๐
smiling face with open mouth & cold sweat -1F606 ; fully-qualified # ๐ smiling face with open mouth & closed eyes +1F603 ; fully-qualified # ๐ grinning face with big eyes +1F604 ; fully-qualified # ๐ grinning face with smiling eyes +1F605 ; fully-qualified # ๐
grinning face with sweat +1F606 ; fully-qualified # ๐ grinning squinting face 1F609 ; fully-qualified # ๐ winking face 1F60A ; fully-qualified # ๐ smiling face with smiling eyes -1F60B ; fully-qualified # ๐ face savouring delicious food +1F60B ; fully-qualified # ๐ face savoring food 1F60E ; fully-qualified # ๐ smiling face with sunglasses 1F60D ; fully-qualified # ๐ smiling face with heart-eyes 1F618 ; fully-qualified # ๐ face blowing a kiss +1F970 ; fully-qualified # ๐ฅฐ smiling face with 3 hearts 1F617 ; fully-qualified # ๐ kissing face 1F619 ; fully-qualified # ๐ kissing face with smiling eyes 1F61A ; fully-qualified # ๐ kissing face with closed eyes @@ -55,7 +56,7 @@ 1F644 ; fully-qualified # ๐ face with rolling eyes 1F60F ; fully-qualified # ๐ smirking face 1F623 ; fully-qualified # ๐ฃ persevering face -1F625 ; fully-qualified # ๐ฅ disappointed but relieved face +1F625 ; fully-qualified # ๐ฅ sad but relieved face 1F62E ; fully-qualified # ๐ฎ face with open mouth 1F910 ; fully-qualified # ๐ค zipper-mouth face 1F62F ; fully-qualified # ๐ฏ hushed face @@ -63,12 +64,12 @@ 1F62B ; fully-qualified # ๐ซ tired face 1F634 ; fully-qualified # ๐ด sleeping face 1F60C ; fully-qualified # ๐ relieved face -1F61B ; fully-qualified # ๐ face with stuck-out tongue -1F61C ; fully-qualified # ๐ face with stuck-out tongue & winking eye -1F61D ; fully-qualified # ๐ face with stuck-out tongue & closed eyes +1F61B ; fully-qualified # ๐ face with tongue +1F61C ; fully-qualified # ๐ winking face with tongue +1F61D ; fully-qualified # ๐ squinting face with tongue 1F924 ; fully-qualified # ๐คค drooling face 1F612 ; fully-qualified # ๐ unamused face -1F613 ; fully-qualified # ๐ face with cold sweat +1F613 ; fully-qualified # ๐ downcast face with sweat 1F614 ; fully-qualified # ๐ pensive face 1F615 ; fully-qualified # ๐ confused face 1F643 ; fully-qualified # ๐ upside-down face @@ -91,14 +92,16 @@ 1F629 ; fully-qualified # ๐ฉ weary face 1F92F ; fully-qualified # ๐คฏ exploding head 1F62C ; fully-qualified # ๐ฌ grimacing face -1F630 ; fully-qualified # ๐ฐ face with open mouth & cold sweat +1F630 ; fully-qualified # ๐ฐ anxious face with sweat 1F631 ; fully-qualified # ๐ฑ face screaming in fear +1F975 ; fully-qualified # ๐ฅต hot face +1F976 ; fully-qualified # ๐ฅถ cold face 1F633 ; fully-qualified # ๐ณ flushed face -1F92A ; fully-qualified # ๐คช crazy face +1F92A ; fully-qualified # ๐คช zany face 1F635 ; fully-qualified # ๐ต dizzy face 1F621 ; fully-qualified # ๐ก pouting face 1F620 ; fully-qualified # ๐ angry face -1F92C ; fully-qualified # ๐คฌ face with symbols over mouth +1F92C ; fully-qualified # ๐คฌ face with symbols on mouth # subgroup: face-sick 1F637 ; fully-qualified # ๐ท face with medical mask @@ -111,7 +114,9 @@ # subgroup: face-role 1F607 ; fully-qualified # ๐ smiling face with halo 1F920 ; fully-qualified # ๐ค cowboy hat face -1F921 ; fully-qualified # ๐คก clown face +1F973 ; fully-qualified # ๐ฅณ partying face +1F974 ; fully-qualified # ๐ฅด woozy face +1F97A ; fully-qualified # ๐ฅบ pleading face 1F925 ; fully-qualified # ๐คฅ lying face 1F92B ; fully-qualified # ๐คซ shushing face 1F92D ; fully-qualified # ๐คญ face with hand over mouth @@ -121,6 +126,7 @@ # subgroup: face-fantasy 1F608 ; fully-qualified # ๐ smiling face with horns 1F47F ; fully-qualified # ๐ฟ angry face with horns +1F921 ; fully-qualified # ๐คก clown face 1F479 ; fully-qualified # ๐น ogre 1F47A ; fully-qualified # ๐บ goblin 1F480 ; fully-qualified # ๐ skull @@ -133,12 +139,12 @@ 1F4A9 ; fully-qualified # ๐ฉ pile of poo # subgroup: cat-face -1F63A ; fully-qualified # ๐บ smiling cat face with open mouth +1F63A ; fully-qualified # ๐บ grinning cat face 1F638 ; fully-qualified # ๐ธ grinning cat face with smiling eyes 1F639 ; fully-qualified # ๐น cat face with tears of joy 1F63B ; fully-qualified # ๐ป smiling cat face with heart-eyes 1F63C ; fully-qualified # ๐ผ cat face with wry smile -1F63D ; fully-qualified # ๐ฝ kissing cat face with closed eyes +1F63D ; fully-qualified # ๐ฝ kissing cat face 1F640 ; fully-qualified # ๐ weary cat face 1F63F ; fully-qualified # ๐ฟ crying cat face 1F63E ; fully-qualified # ๐พ pouting cat face @@ -173,30 +179,114 @@ 1F467 1F3FD ; fully-qualified # ๐ง๐ฝ girl: medium skin tone 1F467 1F3FE ; fully-qualified # ๐ง๐พ girl: medium-dark skin tone 1F467 1F3FF ; fully-qualified # ๐ง๐ฟ girl: dark skin tone -1F9D1 ; fully-qualified # ๐ง adult -1F9D1 1F3FB ; fully-qualified # ๐ง๐ป adult: light skin tone -1F9D1 1F3FC ; fully-qualified # ๐ง๐ผ adult: medium-light skin tone -1F9D1 1F3FD ; fully-qualified # ๐ง๐ฝ adult: medium skin tone -1F9D1 1F3FE ; fully-qualified # ๐ง๐พ adult: medium-dark skin tone -1F9D1 1F3FF ; fully-qualified # ๐ง๐ฟ adult: dark skin tone +1F9D1 ; fully-qualified # ๐ง person +1F9D1 1F3FB ; fully-qualified # ๐ง๐ป person: light skin tone +1F9D1 1F3FC ; fully-qualified # ๐ง๐ผ person: medium-light skin tone +1F9D1 1F3FD ; fully-qualified # ๐ง๐ฝ person: medium skin tone +1F9D1 1F3FE ; fully-qualified # ๐ง๐พ person: medium-dark skin tone +1F9D1 1F3FF ; fully-qualified # ๐ง๐ฟ person: dark skin tone +1F471 ; fully-qualified # ๐ฑ person: blond hair +1F471 1F3FB ; fully-qualified # ๐ฑ๐ป person: light skin tone, blond hair +1F471 1F3FC ; fully-qualified # ๐ฑ๐ผ person: medium-light skin tone, blond hair +1F471 1F3FD ; fully-qualified # ๐ฑ๐ฝ person: medium skin tone, blond hair +1F471 1F3FE ; fully-qualified # ๐ฑ๐พ person: medium-dark skin tone, blond hair +1F471 1F3FF ; fully-qualified # ๐ฑ๐ฟ person: dark skin tone, blond hair 1F468 ; fully-qualified # ๐จ man 1F468 1F3FB ; fully-qualified # ๐จ๐ป man: light skin tone 1F468 1F3FC ; fully-qualified # ๐จ๐ผ man: medium-light skin tone 1F468 1F3FD ; fully-qualified # ๐จ๐ฝ man: medium skin tone 1F468 1F3FE ; fully-qualified # ๐จ๐พ man: medium-dark skin tone 1F468 1F3FF ; fully-qualified # ๐จ๐ฟ man: dark skin tone +1F471 200D 2642 FE0F ; fully-qualified # ๐ฑโโ๏ธ man: blond hair +1F471 200D 2642 ; non-fully-qualified # ๐ฑโโ man: blond hair +1F471 1F3FB 200D 2642 FE0F ; fully-qualified # ๐ฑ๐ปโโ๏ธ man: light skin tone, blond hair +1F471 1F3FB 200D 2642 ; non-fully-qualified # ๐ฑ๐ปโโ man: light skin tone, blond hair +1F471 1F3FC 200D 2642 FE0F ; fully-qualified # ๐ฑ๐ผโโ๏ธ man: medium-light skin tone, blond hair +1F471 1F3FC 200D 2642 ; non-fully-qualified # ๐ฑ๐ผโโ man: medium-light skin tone, blond hair +1F471 1F3FD 200D 2642 FE0F ; fully-qualified # ๐ฑ๐ฝโโ๏ธ man: medium skin tone, blond hair +1F471 1F3FD 200D 2642 ; non-fully-qualified # ๐ฑ๐ฝโโ man: medium skin tone, blond hair +1F471 1F3FE 200D 2642 FE0F ; fully-qualified # ๐ฑ๐พโโ๏ธ man: medium-dark skin tone, blond hair +1F471 1F3FE 200D 2642 ; non-fully-qualified # ๐ฑ๐พโโ man: medium-dark skin tone, blond hair +1F471 1F3FF 200D 2642 FE0F ; fully-qualified # ๐ฑ๐ฟโโ๏ธ man: dark skin tone, blond hair +1F471 1F3FF 200D 2642 ; non-fully-qualified # ๐ฑ๐ฟโโ man: dark skin tone, blond hair +1F468 200D 1F9B0 ; fully-qualified # ๐จโ๐ฆฐ man: red hair +1F468 1F3FB 200D 1F9B0 ; fully-qualified # ๐จ๐ปโ๐ฆฐ man: light skin tone, red hair +1F468 1F3FC 200D 1F9B0 ; fully-qualified # ๐จ๐ผโ๐ฆฐ man: medium-light skin tone, red hair +1F468 1F3FD 200D 1F9B0 ; fully-qualified # ๐จ๐ฝโ๐ฆฐ man: medium skin tone, red hair +1F468 1F3FE 200D 1F9B0 ; fully-qualified # ๐จ๐พโ๐ฆฐ man: medium-dark skin tone, red hair +1F468 1F3FF 200D 1F9B0 ; fully-qualified # ๐จ๐ฟโ๐ฆฐ man: dark skin tone, red hair +1F468 200D 1F9B1 ; fully-qualified # ๐จโ๐ฆฑ man: curly hair +1F468 1F3FB 200D 1F9B1 ; fully-qualified # ๐จ๐ปโ๐ฆฑ man: light skin tone, curly hair +1F468 1F3FC 200D 1F9B1 ; fully-qualified # ๐จ๐ผโ๐ฆฑ man: medium-light skin tone, curly hair +1F468 1F3FD 200D 1F9B1 ; fully-qualified # ๐จ๐ฝโ๐ฆฑ man: medium skin tone, curly hair +1F468 1F3FE 200D 1F9B1 ; fully-qualified # ๐จ๐พโ๐ฆฑ man: medium-dark skin tone, curly hair +1F468 1F3FF 200D 1F9B1 ; fully-qualified # ๐จ๐ฟโ๐ฆฑ man: dark skin tone, curly hair +1F468 200D 1F9B3 ; fully-qualified # ๐จโ๐ฆณ man: white hair +1F468 1F3FB 200D 1F9B3 ; fully-qualified # ๐จ๐ปโ๐ฆณ man: light skin tone, white hair +1F468 1F3FC 200D 1F9B3 ; fully-qualified # ๐จ๐ผโ๐ฆณ man: medium-light skin tone, white hair +1F468 1F3FD 200D 1F9B3 ; fully-qualified # ๐จ๐ฝโ๐ฆณ man: medium skin tone, white hair +1F468 1F3FE 200D 1F9B3 ; fully-qualified # ๐จ๐พโ๐ฆณ man: medium-dark skin tone, white hair +1F468 1F3FF 200D 1F9B3 ; fully-qualified # ๐จ๐ฟโ๐ฆณ man: dark skin tone, white hair +1F468 200D 1F9B2 ; fully-qualified # ๐จโ๐ฆฒ man: bald +1F468 1F3FB 200D 1F9B2 ; fully-qualified # ๐จ๐ปโ๐ฆฒ man: light skin tone, bald +1F468 1F3FC 200D 1F9B2 ; fully-qualified # ๐จ๐ผโ๐ฆฒ man: medium-light skin tone, bald +1F468 1F3FD 200D 1F9B2 ; fully-qualified # ๐จ๐ฝโ๐ฆฒ man: medium skin tone, bald +1F468 1F3FE 200D 1F9B2 ; fully-qualified # ๐จ๐พโ๐ฆฒ man: medium-dark skin tone, bald +1F468 1F3FF 200D 1F9B2 ; fully-qualified # ๐จ๐ฟโ๐ฆฒ man: dark skin tone, bald +1F9D4 ; fully-qualified # ๐ง man: beard +1F9D4 1F3FB ; fully-qualified # ๐ง๐ป man: light skin tone, beard +1F9D4 1F3FC ; fully-qualified # ๐ง๐ผ man: medium-light skin tone, beard +1F9D4 1F3FD ; fully-qualified # ๐ง๐ฝ man: medium skin tone, beard +1F9D4 1F3FE ; fully-qualified # ๐ง๐พ man: medium-dark skin tone, beard +1F9D4 1F3FF ; fully-qualified # ๐ง๐ฟ man: dark skin tone, beard 1F469 ; fully-qualified # ๐ฉ woman 1F469 1F3FB ; fully-qualified # ๐ฉ๐ป woman: light skin tone 1F469 1F3FC ; fully-qualified # ๐ฉ๐ผ woman: medium-light skin tone 1F469 1F3FD ; fully-qualified # ๐ฉ๐ฝ woman: medium skin tone 1F469 1F3FE ; fully-qualified # ๐ฉ๐พ woman: medium-dark skin tone 1F469 1F3FF ; fully-qualified # ๐ฉ๐ฟ woman: dark skin tone -1F9D3 ; fully-qualified # ๐ง older adult -1F9D3 1F3FB ; fully-qualified # ๐ง๐ป older adult: light skin tone -1F9D3 1F3FC ; fully-qualified # ๐ง๐ผ older adult: medium-light skin tone -1F9D3 1F3FD ; fully-qualified # ๐ง๐ฝ older adult: medium skin tone -1F9D3 1F3FE ; fully-qualified # ๐ง๐พ older adult: medium-dark skin tone -1F9D3 1F3FF ; fully-qualified # ๐ง๐ฟ older adult: dark skin tone +1F471 200D 2640 FE0F ; fully-qualified # ๐ฑโโ๏ธ woman: blond hair +1F471 200D 2640 ; non-fully-qualified # ๐ฑโโ woman: blond hair +1F471 1F3FB 200D 2640 FE0F ; fully-qualified # ๐ฑ๐ปโโ๏ธ woman: light skin tone, blond hair +1F471 1F3FB 200D 2640 ; non-fully-qualified # ๐ฑ๐ปโโ woman: light skin tone, blond hair +1F471 1F3FC 200D 2640 FE0F ; fully-qualified # ๐ฑ๐ผโโ๏ธ woman: medium-light skin tone, blond hair +1F471 1F3FC 200D 2640 ; non-fully-qualified # ๐ฑ๐ผโโ woman: medium-light skin tone, blond hair +1F471 1F3FD 200D 2640 FE0F ; fully-qualified # ๐ฑ๐ฝโโ๏ธ woman: medium skin tone, blond hair +1F471 1F3FD 200D 2640 ; non-fully-qualified # ๐ฑ๐ฝโโ woman: medium skin tone, blond hair +1F471 1F3FE 200D 2640 FE0F ; fully-qualified # ๐ฑ๐พโโ๏ธ woman: medium-dark skin tone, blond hair +1F471 1F3FE 200D 2640 ; non-fully-qualified # ๐ฑ๐พโโ woman: medium-dark skin tone, blond hair +1F471 1F3FF 200D 2640 FE0F ; fully-qualified # ๐ฑ๐ฟโโ๏ธ woman: dark skin tone, blond hair +1F471 1F3FF 200D 2640 ; non-fully-qualified # ๐ฑ๐ฟโโ woman: dark skin tone, blond hair +1F469 200D 1F9B0 ; fully-qualified # ๐ฉโ๐ฆฐ woman: red hair +1F469 1F3FB 200D 1F9B0 ; fully-qualified # ๐ฉ๐ปโ๐ฆฐ woman: light skin tone, red hair +1F469 1F3FC 200D 1F9B0 ; fully-qualified # ๐ฉ๐ผโ๐ฆฐ woman: medium-light skin tone, red hair +1F469 1F3FD 200D 1F9B0 ; fully-qualified # ๐ฉ๐ฝโ๐ฆฐ woman: medium skin tone, red hair +1F469 1F3FE 200D 1F9B0 ; fully-qualified # ๐ฉ๐พโ๐ฆฐ woman: medium-dark skin tone, red hair +1F469 1F3FF 200D 1F9B0 ; fully-qualified # ๐ฉ๐ฟโ๐ฆฐ woman: dark skin tone, red hair +1F469 200D 1F9B1 ; fully-qualified # ๐ฉโ๐ฆฑ woman: curly hair +1F469 1F3FB 200D 1F9B1 ; fully-qualified # ๐ฉ๐ปโ๐ฆฑ woman: light skin tone, curly hair +1F469 1F3FC 200D 1F9B1 ; fully-qualified # ๐ฉ๐ผโ๐ฆฑ woman: medium-light skin tone, curly hair +1F469 1F3FD 200D 1F9B1 ; fully-qualified # ๐ฉ๐ฝโ๐ฆฑ woman: medium skin tone, curly hair +1F469 1F3FE 200D 1F9B1 ; fully-qualified # ๐ฉ๐พโ๐ฆฑ woman: medium-dark skin tone, curly hair +1F469 1F3FF 200D 1F9B1 ; fully-qualified # ๐ฉ๐ฟโ๐ฆฑ woman: dark skin tone, curly hair +1F469 200D 1F9B3 ; fully-qualified # ๐ฉโ๐ฆณ woman: white hair +1F469 1F3FB 200D 1F9B3 ; fully-qualified # ๐ฉ๐ปโ๐ฆณ woman: light skin tone, white hair +1F469 1F3FC 200D 1F9B3 ; fully-qualified # ๐ฉ๐ผโ๐ฆณ woman: medium-light skin tone, white hair +1F469 1F3FD 200D 1F9B3 ; fully-qualified # ๐ฉ๐ฝโ๐ฆณ woman: medium skin tone, white hair +1F469 1F3FE 200D 1F9B3 ; fully-qualified # ๐ฉ๐พโ๐ฆณ woman: medium-dark skin tone, white hair +1F469 1F3FF 200D 1F9B3 ; fully-qualified # ๐ฉ๐ฟโ๐ฆณ woman: dark skin tone, white hair +1F469 200D 1F9B2 ; fully-qualified # ๐ฉโ๐ฆฒ woman: bald +1F469 1F3FB 200D 1F9B2 ; fully-qualified # ๐ฉ๐ปโ๐ฆฒ woman: light skin tone, bald +1F469 1F3FC 200D 1F9B2 ; fully-qualified # ๐ฉ๐ผโ๐ฆฒ woman: medium-light skin tone, bald +1F469 1F3FD 200D 1F9B2 ; fully-qualified # ๐ฉ๐ฝโ๐ฆฒ woman: medium skin tone, bald +1F469 1F3FE 200D 1F9B2 ; fully-qualified # ๐ฉ๐พโ๐ฆฒ woman: medium-dark skin tone, bald +1F469 1F3FF 200D 1F9B2 ; fully-qualified # ๐ฉ๐ฟโ๐ฆฒ woman: dark skin tone, bald +1F9D3 ; fully-qualified # ๐ง older person +1F9D3 1F3FB ; fully-qualified # ๐ง๐ป older person: light skin tone +1F9D3 1F3FC ; fully-qualified # ๐ง๐ผ older person: medium-light skin tone +1F9D3 1F3FD ; fully-qualified # ๐ง๐ฝ older person: medium skin tone +1F9D3 1F3FE ; fully-qualified # ๐ง๐พ older person: medium-dark skin tone +1F9D3 1F3FF ; fully-qualified # ๐ง๐ฟ older person: dark skin tone 1F474 ; fully-qualified # ๐ด old man 1F474 1F3FB ; fully-qualified # ๐ด๐ป old man: light skin tone 1F474 1F3FC ; fully-qualified # ๐ด๐ผ old man: medium-light skin tone @@ -618,42 +708,6 @@ 1F9D5 1F3FD ; fully-qualified # ๐ง๐ฝ woman with headscarf: medium skin tone 1F9D5 1F3FE ; fully-qualified # ๐ง๐พ woman with headscarf: medium-dark skin tone 1F9D5 1F3FF ; fully-qualified # ๐ง๐ฟ woman with headscarf: dark skin tone -1F9D4 ; fully-qualified # ๐ง bearded person -1F9D4 1F3FB ; fully-qualified # ๐ง๐ป bearded person: light skin tone -1F9D4 1F3FC ; fully-qualified # ๐ง๐ผ bearded person: medium-light skin tone -1F9D4 1F3FD ; fully-qualified # ๐ง๐ฝ bearded person: medium skin tone -1F9D4 1F3FE ; fully-qualified # ๐ง๐พ bearded person: medium-dark skin tone -1F9D4 1F3FF ; fully-qualified # ๐ง๐ฟ bearded person: dark skin tone -1F471 ; fully-qualified # ๐ฑ blond-haired person -1F471 1F3FB ; fully-qualified # ๐ฑ๐ป blond-haired person: light skin tone -1F471 1F3FC ; fully-qualified # ๐ฑ๐ผ blond-haired person: medium-light skin tone -1F471 1F3FD ; fully-qualified # ๐ฑ๐ฝ blond-haired person: medium skin tone -1F471 1F3FE ; fully-qualified # ๐ฑ๐พ blond-haired person: medium-dark skin tone -1F471 1F3FF ; fully-qualified # ๐ฑ๐ฟ blond-haired person: dark skin tone -1F471 200D 2642 FE0F ; fully-qualified # ๐ฑโโ๏ธ blond-haired man -1F471 200D 2642 ; non-fully-qualified # ๐ฑโโ blond-haired man -1F471 1F3FB 200D 2642 FE0F ; fully-qualified # ๐ฑ๐ปโโ๏ธ blond-haired man: light skin tone -1F471 1F3FB 200D 2642 ; non-fully-qualified # ๐ฑ๐ปโโ blond-haired man: light skin tone -1F471 1F3FC 200D 2642 FE0F ; fully-qualified # ๐ฑ๐ผโโ๏ธ blond-haired man: medium-light skin tone -1F471 1F3FC 200D 2642 ; non-fully-qualified # ๐ฑ๐ผโโ blond-haired man: medium-light skin tone -1F471 1F3FD 200D 2642 FE0F ; fully-qualified # ๐ฑ๐ฝโโ๏ธ blond-haired man: medium skin tone -1F471 1F3FD 200D 2642 ; non-fully-qualified # ๐ฑ๐ฝโโ blond-haired man: medium skin tone -1F471 1F3FE 200D 2642 FE0F ; fully-qualified # ๐ฑ๐พโโ๏ธ blond-haired man: medium-dark skin tone -1F471 1F3FE 200D 2642 ; non-fully-qualified # ๐ฑ๐พโโ blond-haired man: medium-dark skin tone -1F471 1F3FF 200D 2642 FE0F ; fully-qualified # ๐ฑ๐ฟโโ๏ธ blond-haired man: dark skin tone -1F471 1F3FF 200D 2642 ; non-fully-qualified # ๐ฑ๐ฟโโ blond-haired man: dark skin tone -1F471 200D 2640 FE0F ; fully-qualified # ๐ฑโโ๏ธ blond-haired woman -1F471 200D 2640 ; non-fully-qualified # ๐ฑโโ blond-haired woman -1F471 1F3FB 200D 2640 FE0F ; fully-qualified # ๐ฑ๐ปโโ๏ธ blond-haired woman: light skin tone -1F471 1F3FB 200D 2640 ; non-fully-qualified # ๐ฑ๐ปโโ blond-haired woman: light skin tone -1F471 1F3FC 200D 2640 FE0F ; fully-qualified # ๐ฑ๐ผโโ๏ธ blond-haired woman: medium-light skin tone -1F471 1F3FC 200D 2640 ; non-fully-qualified # ๐ฑ๐ผโโ blond-haired woman: medium-light skin tone -1F471 1F3FD 200D 2640 FE0F ; fully-qualified # ๐ฑ๐ฝโโ๏ธ blond-haired woman: medium skin tone -1F471 1F3FD 200D 2640 ; non-fully-qualified # ๐ฑ๐ฝโโ blond-haired woman: medium skin tone -1F471 1F3FE 200D 2640 FE0F ; fully-qualified # ๐ฑ๐พโโ๏ธ blond-haired woman: medium-dark skin tone -1F471 1F3FE 200D 2640 ; non-fully-qualified # ๐ฑ๐พโโ blond-haired woman: medium-dark skin tone -1F471 1F3FF 200D 2640 FE0F ; fully-qualified # ๐ฑ๐ฟโโ๏ธ blond-haired woman: dark skin tone -1F471 1F3FF 200D 2640 ; non-fully-qualified # ๐ฑ๐ฟโโ blond-haired woman: dark skin tone 1F935 ; fully-qualified # ๐คต man in tuxedo 1F935 1F3FB ; fully-qualified # ๐คต๐ป man in tuxedo: light skin tone 1F935 1F3FC ; fully-qualified # ๐คต๐ผ man in tuxedo: medium-light skin tone @@ -698,6 +752,66 @@ 1F936 1F3FD ; fully-qualified # ๐คถ๐ฝ Mrs. Claus: medium skin tone 1F936 1F3FE ; fully-qualified # ๐คถ๐พ Mrs. Claus: medium-dark skin tone 1F936 1F3FF ; fully-qualified # ๐คถ๐ฟ Mrs. Claus: dark skin tone +1F9B8 ; fully-qualified # ๐ฆธ superhero +1F9B8 1F3FB ; fully-qualified # ๐ฆธ๐ป superhero: light skin tone +1F9B8 1F3FC ; fully-qualified # ๐ฆธ๐ผ superhero: medium-light skin tone +1F9B8 1F3FD ; fully-qualified # ๐ฆธ๐ฝ superhero: medium skin tone +1F9B8 1F3FE ; fully-qualified # ๐ฆธ๐พ superhero: medium-dark skin tone +1F9B8 1F3FF ; fully-qualified # ๐ฆธ๐ฟ superhero: dark skin tone +1F9B8 200D 2640 FE0F ; fully-qualified # ๐ฆธโโ๏ธ woman superhero +1F9B8 200D 2640 ; non-fully-qualified # ๐ฆธโโ woman superhero +1F9B8 1F3FB 200D 2640 FE0F ; fully-qualified # ๐ฆธ๐ปโโ๏ธ woman superhero: light skin tone +1F9B8 1F3FB 200D 2640 ; non-fully-qualified # ๐ฆธ๐ปโโ woman superhero: light skin tone +1F9B8 1F3FC 200D 2640 FE0F ; fully-qualified # ๐ฆธ๐ผโโ๏ธ woman superhero: medium-light skin tone +1F9B8 1F3FC 200D 2640 ; non-fully-qualified # ๐ฆธ๐ผโโ woman superhero: medium-light skin tone +1F9B8 1F3FD 200D 2640 FE0F ; fully-qualified # ๐ฆธ๐ฝโโ๏ธ woman superhero: medium skin tone +1F9B8 1F3FD 200D 2640 ; non-fully-qualified # ๐ฆธ๐ฝโโ woman superhero: medium skin tone +1F9B8 1F3FE 200D 2640 FE0F ; fully-qualified # ๐ฆธ๐พโโ๏ธ woman superhero: medium-dark skin tone +1F9B8 1F3FE 200D 2640 ; non-fully-qualified # ๐ฆธ๐พโโ woman superhero: medium-dark skin tone +1F9B8 1F3FF 200D 2640 FE0F ; fully-qualified # ๐ฆธ๐ฟโโ๏ธ woman superhero: dark skin tone +1F9B8 1F3FF 200D 2640 ; non-fully-qualified # ๐ฆธ๐ฟโโ woman superhero: dark skin tone +1F9B8 200D 2642 FE0F ; fully-qualified # ๐ฆธโโ๏ธ man superhero +1F9B8 200D 2642 ; non-fully-qualified # ๐ฆธโโ man superhero +1F9B8 1F3FB 200D 2642 FE0F ; fully-qualified # ๐ฆธ๐ปโโ๏ธ man superhero: light skin tone +1F9B8 1F3FB 200D 2642 ; non-fully-qualified # ๐ฆธ๐ปโโ man superhero: light skin tone +1F9B8 1F3FC 200D 2642 FE0F ; fully-qualified # ๐ฆธ๐ผโโ๏ธ man superhero: medium-light skin tone +1F9B8 1F3FC 200D 2642 ; non-fully-qualified # ๐ฆธ๐ผโโ man superhero: medium-light skin tone +1F9B8 1F3FD 200D 2642 FE0F ; fully-qualified # ๐ฆธ๐ฝโโ๏ธ man superhero: medium skin tone +1F9B8 1F3FD 200D 2642 ; non-fully-qualified # ๐ฆธ๐ฝโโ man superhero: medium skin tone +1F9B8 1F3FE 200D 2642 FE0F ; fully-qualified # ๐ฆธ๐พโโ๏ธ man superhero: medium-dark skin tone +1F9B8 1F3FE 200D 2642 ; non-fully-qualified # ๐ฆธ๐พโโ man superhero: medium-dark skin tone +1F9B8 1F3FF 200D 2642 FE0F ; fully-qualified # ๐ฆธ๐ฟโโ๏ธ man superhero: dark skin tone +1F9B8 1F3FF 200D 2642 ; non-fully-qualified # ๐ฆธ๐ฟโโ man superhero: dark skin tone +1F9B9 ; fully-qualified # ๐ฆน supervillain +1F9B9 1F3FB ; fully-qualified # ๐ฆน๐ป supervillain: light skin tone +1F9B9 1F3FC ; fully-qualified # ๐ฆน๐ผ supervillain: medium-light skin tone +1F9B9 1F3FD ; fully-qualified # ๐ฆน๐ฝ supervillain: medium skin tone +1F9B9 1F3FE ; fully-qualified # ๐ฆน๐พ supervillain: medium-dark skin tone +1F9B9 1F3FF ; fully-qualified # ๐ฆน๐ฟ supervillain: dark skin tone +1F9B9 200D 2640 FE0F ; fully-qualified # ๐ฆนโโ๏ธ woman supervillain +1F9B9 200D 2640 ; non-fully-qualified # ๐ฆนโโ woman supervillain +1F9B9 1F3FB 200D 2640 FE0F ; fully-qualified # ๐ฆน๐ปโโ๏ธ woman supervillain: light skin tone +1F9B9 1F3FB 200D 2640 ; non-fully-qualified # ๐ฆน๐ปโโ woman supervillain: light skin tone +1F9B9 1F3FC 200D 2640 FE0F ; fully-qualified # ๐ฆน๐ผโโ๏ธ woman supervillain: medium-light skin tone +1F9B9 1F3FC 200D 2640 ; non-fully-qualified # ๐ฆน๐ผโโ woman supervillain: medium-light skin tone +1F9B9 1F3FD 200D 2640 FE0F ; fully-qualified # ๐ฆน๐ฝโโ๏ธ woman supervillain: medium skin tone +1F9B9 1F3FD 200D 2640 ; non-fully-qualified # ๐ฆน๐ฝโโ woman supervillain: medium skin tone +1F9B9 1F3FE 200D 2640 FE0F ; fully-qualified # ๐ฆน๐พโโ๏ธ woman supervillain: medium-dark skin tone +1F9B9 1F3FE 200D 2640 ; non-fully-qualified # ๐ฆน๐พโโ woman supervillain: medium-dark skin tone +1F9B9 1F3FF 200D 2640 FE0F ; fully-qualified # ๐ฆน๐ฟโโ๏ธ woman supervillain: dark skin tone +1F9B9 1F3FF 200D 2640 ; non-fully-qualified # ๐ฆน๐ฟโโ woman supervillain: dark skin tone +1F9B9 200D 2642 FE0F ; fully-qualified # ๐ฆนโโ๏ธ man supervillain +1F9B9 200D 2642 ; non-fully-qualified # ๐ฆนโโ man supervillain +1F9B9 1F3FB 200D 2642 FE0F ; fully-qualified # ๐ฆน๐ปโโ๏ธ man supervillain: light skin tone +1F9B9 1F3FB 200D 2642 ; non-fully-qualified # ๐ฆน๐ปโโ man supervillain: light skin tone +1F9B9 1F3FC 200D 2642 FE0F ; fully-qualified # ๐ฆน๐ผโโ๏ธ man supervillain: medium-light skin tone +1F9B9 1F3FC 200D 2642 ; non-fully-qualified # ๐ฆน๐ผโโ man supervillain: medium-light skin tone +1F9B9 1F3FD 200D 2642 FE0F ; fully-qualified # ๐ฆน๐ฝโโ๏ธ man supervillain: medium skin tone +1F9B9 1F3FD 200D 2642 ; non-fully-qualified # ๐ฆน๐ฝโโ man supervillain: medium skin tone +1F9B9 1F3FE 200D 2642 FE0F ; fully-qualified # ๐ฆน๐พโโ๏ธ man supervillain: medium-dark skin tone +1F9B9 1F3FE 200D 2642 ; non-fully-qualified # ๐ฆน๐พโโ man supervillain: medium-dark skin tone +1F9B9 1F3FF 200D 2642 FE0F ; fully-qualified # ๐ฆน๐ฟโโ๏ธ man supervillain: dark skin tone +1F9B9 1F3FF 200D 2642 ; non-fully-qualified # ๐ฆน๐ฟโโ man supervillain: dark skin tone 1F9D9 ; fully-qualified # ๐ง mage 1F9D9 1F3FB ; fully-qualified # ๐ง๐ป mage: light skin tone 1F9D9 1F3FC ; fully-qualified # ๐ง๐ผ mage: medium-light skin tone @@ -1264,11 +1378,11 @@ 1F57A 1F3FD ; fully-qualified # ๐บ๐ฝ man dancing: medium skin tone 1F57A 1F3FE ; fully-qualified # ๐บ๐พ man dancing: medium-dark skin tone 1F57A 1F3FF ; fully-qualified # ๐บ๐ฟ man dancing: dark skin tone -1F46F ; fully-qualified # ๐ฏ people with bunny ears partying -1F46F 200D 2642 FE0F ; fully-qualified # ๐ฏโโ๏ธ men with bunny ears partying -1F46F 200D 2642 ; non-fully-qualified # ๐ฏโโ men with bunny ears partying -1F46F 200D 2640 FE0F ; fully-qualified # ๐ฏโโ๏ธ women with bunny ears partying -1F46F 200D 2640 ; non-fully-qualified # ๐ฏโโ women with bunny ears partying +1F46F ; fully-qualified # ๐ฏ people with bunny ears +1F46F 200D 2642 FE0F ; fully-qualified # ๐ฏโโ๏ธ men with bunny ears +1F46F 200D 2642 ; non-fully-qualified # ๐ฏโโ men with bunny ears +1F46F 200D 2640 FE0F ; fully-qualified # ๐ฏโโ๏ธ women with bunny ears +1F46F 200D 2640 ; non-fully-qualified # ๐ฏโโ women with bunny ears 1F9D6 ; fully-qualified # ๐ง person in steamy room 1F9D6 1F3FB ; fully-qualified # ๐ง๐ป person in steamy room: light skin tone 1F9D6 1F3FC ; fully-qualified # ๐ง๐ผ person in steamy room: medium-light skin tone @@ -1371,13 +1485,13 @@ 1F6CC 1F3FD ; fully-qualified # ๐๐ฝ person in bed: medium skin tone 1F6CC 1F3FE ; fully-qualified # ๐๐พ person in bed: medium-dark skin tone 1F6CC 1F3FF ; fully-qualified # ๐๐ฟ person in bed: dark skin tone -1F574 FE0F ; fully-qualified # ๐ด๏ธ man in business suit levitating -1F574 ; non-fully-qualified # ๐ด man in business suit levitating -1F574 1F3FB ; fully-qualified # ๐ด๐ป man in business suit levitating: light skin tone -1F574 1F3FC ; fully-qualified # ๐ด๐ผ man in business suit levitating: medium-light skin tone -1F574 1F3FD ; fully-qualified # ๐ด๐ฝ man in business suit levitating: medium skin tone -1F574 1F3FE ; fully-qualified # ๐ด๐พ man in business suit levitating: medium-dark skin tone -1F574 1F3FF ; fully-qualified # ๐ด๐ฟ man in business suit levitating: dark skin tone +1F574 FE0F ; fully-qualified # ๐ด๏ธ man in suit levitating +1F574 ; non-fully-qualified # ๐ด man in suit levitating +1F574 1F3FB ; fully-qualified # ๐ด๐ป man in suit levitating: light skin tone +1F574 1F3FC ; fully-qualified # ๐ด๐ผ man in suit levitating: medium-light skin tone +1F574 1F3FD ; fully-qualified # ๐ด๐ฝ man in suit levitating: medium skin tone +1F574 1F3FE ; fully-qualified # ๐ด๐พ man in suit levitating: medium-dark skin tone +1F574 1F3FF ; fully-qualified # ๐ด๐ฟ man in suit levitating: dark skin tone 1F5E3 FE0F ; fully-qualified # ๐ฃ๏ธ speaking head 1F5E3 ; non-fully-qualified # ๐ฃ speaking head 1F464 ; fully-qualified # ๐ค bust in silhouette @@ -1842,6 +1956,18 @@ 1F4AA 1F3FD ; fully-qualified # ๐ช๐ฝ flexed biceps: medium skin tone 1F4AA 1F3FE ; fully-qualified # ๐ช๐พ flexed biceps: medium-dark skin tone 1F4AA 1F3FF ; fully-qualified # ๐ช๐ฟ flexed biceps: dark skin tone +1F9B5 ; fully-qualified # ๐ฆต leg +1F9B5 1F3FB ; fully-qualified # ๐ฆต๐ป leg: light skin tone +1F9B5 1F3FC ; fully-qualified # ๐ฆต๐ผ leg: medium-light skin tone +1F9B5 1F3FD ; fully-qualified # ๐ฆต๐ฝ leg: medium skin tone +1F9B5 1F3FE ; fully-qualified # ๐ฆต๐พ leg: medium-dark skin tone +1F9B5 1F3FF ; fully-qualified # ๐ฆต๐ฟ leg: dark skin tone +1F9B6 ; fully-qualified # ๐ฆถ foot +1F9B6 1F3FB ; fully-qualified # ๐ฆถ๐ป foot: light skin tone +1F9B6 1F3FC ; fully-qualified # ๐ฆถ๐ผ foot: medium-light skin tone +1F9B6 1F3FD ; fully-qualified # ๐ฆถ๐ฝ foot: medium skin tone +1F9B6 1F3FE ; fully-qualified # ๐ฆถ๐พ foot: medium-dark skin tone +1F9B6 1F3FF ; fully-qualified # ๐ฆถ๐ฟ foot: dark skin tone 1F448 ; fully-qualified # ๐ backhand index pointing left 1F448 1F3FB ; fully-qualified # ๐๐ป backhand index pointing left: light skin tone 1F448 1F3FC ; fully-qualified # ๐๐ผ backhand index pointing left: medium-light skin tone @@ -1910,13 +2036,13 @@ 1F919 1F3FD ; fully-qualified # ๐ค๐ฝ call me hand: medium skin tone 1F919 1F3FE ; fully-qualified # ๐ค๐พ call me hand: medium-dark skin tone 1F919 1F3FF ; fully-qualified # ๐ค๐ฟ call me hand: dark skin tone -1F590 FE0F ; fully-qualified # ๐๏ธ raised hand with fingers splayed -1F590 ; non-fully-qualified # ๐ raised hand with fingers splayed -1F590 1F3FB ; fully-qualified # ๐๐ป raised hand with fingers splayed: light skin tone -1F590 1F3FC ; fully-qualified # ๐๐ผ raised hand with fingers splayed: medium-light skin tone -1F590 1F3FD ; fully-qualified # ๐๐ฝ raised hand with fingers splayed: medium skin tone -1F590 1F3FE ; fully-qualified # ๐๐พ raised hand with fingers splayed: medium-dark skin tone -1F590 1F3FF ; fully-qualified # ๐๐ฟ raised hand with fingers splayed: dark skin tone +1F590 FE0F ; fully-qualified # ๐๏ธ hand with fingers splayed +1F590 ; non-fully-qualified # ๐ hand with fingers splayed +1F590 1F3FB ; fully-qualified # ๐๐ป hand with fingers splayed: light skin tone +1F590 1F3FC ; fully-qualified # ๐๐ผ hand with fingers splayed: medium-light skin tone +1F590 1F3FD ; fully-qualified # ๐๐ฝ hand with fingers splayed: medium skin tone +1F590 1F3FE ; fully-qualified # ๐๐พ hand with fingers splayed: medium-dark skin tone +1F590 1F3FF ; fully-qualified # ๐๐ฟ hand with fingers splayed: dark skin tone 270B ; fully-qualified # โ raised hand 270B 1F3FB ; fully-qualified # โ๐ป raised hand: light skin tone 270B 1F3FC ; fully-qualified # โ๐ผ raised hand: medium-light skin tone @@ -2048,31 +2174,46 @@ 1F441 FE0F 200D 1F5E8 ; non-fully-qualified # ๐๏ธโ๐จ eye in speech bubble 1F441 200D 1F5E8 ; non-fully-qualified # ๐โ๐จ eye in speech bubble 1F9E0 ; fully-qualified # ๐ง brain +1F9B4 ; fully-qualified # ๐ฆด bone +1F9B7 ; fully-qualified # ๐ฆท tooth 1F445 ; fully-qualified # ๐
tongue 1F444 ; fully-qualified # ๐ mouth +# subgroup: skin-tone +1F3FB ; fully-qualified # ๐ป light skin tone +1F3FC ; fully-qualified # ๐ผ medium-light skin tone +1F3FD ; fully-qualified # ๐ฝ medium skin tone +1F3FE ; fully-qualified # ๐พ medium-dark skin tone +1F3FF ; fully-qualified # ๐ฟ dark skin tone + +# subgroup: hair-style +1F9B0 ; fully-qualified # ๐ฆฐ red hair +1F9B1 ; fully-qualified # ๐ฆฑ curly hair +1F9B3 ; fully-qualified # ๐ฆณ white hair +1F9B2 ; fully-qualified # ๐ฆฒ bald + # subgroup: emotion 1F48B ; fully-qualified # ๐ kiss mark 1F498 ; fully-qualified # ๐ heart with arrow -2764 FE0F ; fully-qualified # โค๏ธ red heart -2764 ; non-fully-qualified # โค red heart -1F493 ; fully-qualified # ๐ beating heart -1F494 ; fully-qualified # ๐ broken heart -1F495 ; fully-qualified # ๐ two hearts +1F49D ; fully-qualified # ๐ heart with ribbon 1F496 ; fully-qualified # ๐ sparkling heart 1F497 ; fully-qualified # ๐ growing heart -1F499 ; fully-qualified # ๐ blue heart -1F49A ; fully-qualified # ๐ green heart -1F49B ; fully-qualified # ๐ yellow heart +1F493 ; fully-qualified # ๐ beating heart +1F49E ; fully-qualified # ๐ revolving hearts +1F495 ; fully-qualified # ๐ two hearts +1F48C ; fully-qualified # ๐ love letter +2763 FE0F ; fully-qualified # โฃ๏ธ heavy heart exclamation +2763 ; non-fully-qualified # โฃ heavy heart exclamation +1F494 ; fully-qualified # ๐ broken heart +2764 FE0F ; fully-qualified # โค๏ธ red heart +2764 ; non-fully-qualified # โค red heart 1F9E1 ; fully-qualified # ๐งก orange heart +1F49B ; fully-qualified # ๐ yellow heart +1F49A ; fully-qualified # ๐ green heart +1F499 ; fully-qualified # ๐ blue heart 1F49C ; fully-qualified # ๐ purple heart 1F5A4 ; fully-qualified # ๐ค black heart -1F49D ; fully-qualified # ๐ heart with ribbon -1F49E ; fully-qualified # ๐ revolving hearts 1F49F ; fully-qualified # ๐ heart decoration -2763 FE0F ; fully-qualified # โฃ๏ธ heavy heart exclamation -2763 ; non-fully-qualified # โฃ heavy heart exclamation -1F48C ; fully-qualified # ๐ love letter 1F4A4 ; fully-qualified # ๐ค zzz 1F4A2 ; fully-qualified # ๐ข anger symbol 1F4A3 ; fully-qualified # ๐ฃ bomb @@ -2093,6 +2234,8 @@ 1F453 ; fully-qualified # ๐ glasses 1F576 FE0F ; fully-qualified # ๐ถ๏ธ sunglasses 1F576 ; non-fully-qualified # ๐ถ sunglasses +1F97D ; fully-qualified # ๐ฅฝ goggles +1F97C ; fully-qualified # ๐ฅผ lab coat 1F454 ; fully-qualified # ๐ necktie 1F455 ; fully-qualified # ๐ t-shirt 1F456 ; fully-qualified # ๐ jeans @@ -2109,9 +2252,11 @@ 1F45D ; fully-qualified # ๐ clutch bag 1F6CD FE0F ; fully-qualified # ๐๏ธ shopping bags 1F6CD ; non-fully-qualified # ๐ shopping bags -1F392 ; fully-qualified # ๐ school backpack +1F392 ; fully-qualified # ๐ backpack 1F45E ; fully-qualified # ๐ manโs shoe 1F45F ; fully-qualified # ๐ running shoe +1F97E ; fully-qualified # ๐ฅพ hiking boot +1F97F ; fully-qualified # ๐ฅฟ flat shoe 1F460 ; fully-qualified # ๐ high-heeled shoe 1F461 ; fully-qualified # ๐ก womanโs sandal 1F462 ; fully-qualified # ๐ข womanโs boot @@ -2127,8 +2272,8 @@ 1F48D ; fully-qualified # ๐ ring 1F48E ; fully-qualified # ๐ gem stone -# Smileys & People subtotal: 2069 -# Smileys & People subtotal: 589 w/o modifiers +# Smileys & People subtotal: 2210 +# Smileys & People subtotal: 625 w/o modifiers # group: Animals & Nature @@ -2141,6 +2286,7 @@ 1F429 ; fully-qualified # ๐ฉ poodle 1F43A ; fully-qualified # ๐บ wolf face 1F98A ; fully-qualified # ๐ฆ fox face +1F99D ; fully-qualified # ๐ฆ raccoon 1F431 ; fully-qualified # ๐ฑ cat face 1F408 ; fully-qualified # ๐ cat 1F981 ; fully-qualified # ๐ฆ lion face @@ -2165,9 +2311,11 @@ 1F410 ; fully-qualified # ๐ goat 1F42A ; fully-qualified # ๐ช camel 1F42B ; fully-qualified # ๐ซ two-hump camel +1F999 ; fully-qualified # ๐ฆ llama 1F992 ; fully-qualified # ๐ฆ giraffe 1F418 ; fully-qualified # ๐ elephant 1F98F ; fully-qualified # ๐ฆ rhinoceros +1F99B ; fully-qualified # ๐ฆ hippopotamus 1F42D ; fully-qualified # ๐ญ mouse face 1F401 ; fully-qualified # ๐ mouse 1F400 ; fully-qualified # ๐ rat @@ -2181,6 +2329,8 @@ 1F43B ; fully-qualified # ๐ป bear face 1F428 ; fully-qualified # ๐จ koala 1F43C ; fully-qualified # ๐ผ panda face +1F998 ; fully-qualified # ๐ฆ kangaroo +1F9A1 ; fully-qualified # ๐ฆก badger 1F43E ; fully-qualified # ๐พ paw prints # subgroup: animal-bird @@ -2196,7 +2346,10 @@ 1F54A ; non-fully-qualified # ๐ dove 1F985 ; fully-qualified # ๐ฆ
eagle 1F986 ; fully-qualified # ๐ฆ duck +1F9A2 ; fully-qualified # ๐ฆข swan 1F989 ; fully-qualified # ๐ฆ owl +1F99A ; fully-qualified # ๐ฆ peacock +1F99C ; fully-qualified # ๐ฆ parrot # subgroup: animal-amphibian 1F438 ; fully-qualified # ๐ธ frog face @@ -2222,6 +2375,7 @@ 1F419 ; fully-qualified # ๐ octopus 1F41A ; fully-qualified # ๐ spiral shell 1F980 ; fully-qualified # ๐ฆ crab +1F99E ; fully-qualified # ๐ฆ lobster 1F990 ; fully-qualified # ๐ฆ shrimp 1F991 ; fully-qualified # ๐ฆ squid @@ -2238,6 +2392,8 @@ 1F578 FE0F ; fully-qualified # ๐ธ๏ธ spider web 1F578 ; non-fully-qualified # ๐ธ spider web 1F982 ; fully-qualified # ๐ฆ scorpion +1F99F ; fully-qualified # ๐ฆ mosquito +1F9A0 ; fully-qualified # ๐ฆ microbe # subgroup: plant-flower 1F490 ; fully-qualified # ๐ bouquet @@ -2267,8 +2423,8 @@ 1F342 ; fully-qualified # ๐ fallen leaf 1F343 ; fully-qualified # ๐ leaf fluttering in wind -# Animals & Nature subtotal: 119 -# Animals & Nature subtotal: 119 w/o modifiers +# Animals & Nature subtotal: 130 +# Animals & Nature subtotal: 130 w/o modifiers # group: Food & Drink @@ -2280,6 +2436,7 @@ 1F34B ; fully-qualified # ๐ lemon 1F34C ; fully-qualified # ๐ banana 1F34D ; fully-qualified # ๐ pineapple +1F96D ; fully-qualified # ๐ฅญ mango 1F34E ; fully-qualified # ๐ red apple 1F34F ; fully-qualified # ๐ green apple 1F350 ; fully-qualified # ๐ pear @@ -2299,6 +2456,7 @@ 1F336 FE0F ; fully-qualified # ๐ถ๏ธ hot pepper 1F336 ; non-fully-qualified # ๐ถ hot pepper 1F952 ; fully-qualified # ๐ฅ cucumber +1F96C ; fully-qualified # ๐ฅฌ leafy green 1F966 ; fully-qualified # ๐ฅฆ broccoli 1F344 ; fully-qualified # ๐ mushroom 1F95C ; fully-qualified # ๐ฅ peanuts @@ -2309,6 +2467,7 @@ 1F950 ; fully-qualified # ๐ฅ croissant 1F956 ; fully-qualified # ๐ฅ baguette bread 1F968 ; fully-qualified # ๐ฅจ pretzel +1F96F ; fully-qualified # ๐ฅฏ bagel 1F95E ; fully-qualified # ๐ฅ pancakes 1F9C0 ; fully-qualified # ๐ง cheese wedge 1F356 ; fully-qualified # ๐ meat on bone @@ -2330,6 +2489,7 @@ 1F963 ; fully-qualified # ๐ฅฃ bowl with spoon 1F957 ; fully-qualified # ๐ฅ green salad 1F37F ; fully-qualified # ๐ฟ popcorn +1F9C2 ; fully-qualified # ๐ง salt 1F96B ; fully-qualified # ๐ฅซ canned food # subgroup: food-asian @@ -2345,6 +2505,7 @@ 1F363 ; fully-qualified # ๐ฃ sushi 1F364 ; fully-qualified # ๐ค fried shrimp 1F365 ; fully-qualified # ๐ฅ fish cake with swirl +1F96E ; fully-qualified # ๐ฅฎ moon cake 1F361 ; fully-qualified # ๐ก dango 1F95F ; fully-qualified # ๐ฅ dumpling 1F960 ; fully-qualified # ๐ฅ fortune cookie @@ -2358,6 +2519,7 @@ 1F36A ; fully-qualified # ๐ช cookie 1F382 ; fully-qualified # ๐ birthday cake 1F370 ; fully-qualified # ๐ฐ shortcake +1F9C1 ; fully-qualified # ๐ง cupcake 1F967 ; fully-qualified # ๐ฅง pie 1F36B ; fully-qualified # ๐ซ chocolate bar 1F36C ; fully-qualified # ๐ฌ candy @@ -2390,8 +2552,8 @@ 1F52A ; fully-qualified # ๐ช kitchen knife 1F3FA ; fully-qualified # ๐บ amphora -# Food & Drink subtotal: 104 -# Food & Drink subtotal: 104 w/o modifiers +# Food & Drink subtotal: 110 +# Food & Drink subtotal: 110 w/o modifiers # group: Travel & Places @@ -2403,6 +2565,7 @@ 1F5FA FE0F ; fully-qualified # ๐บ๏ธ world map 1F5FA ; non-fully-qualified # ๐บ world map 1F5FE ; fully-qualified # ๐พ map of Japan +1F9ED ; fully-qualified # ๐งญ compass # subgroup: place-geographic 1F3D4 FE0F ; fully-qualified # ๐๏ธ snow-capped mountain @@ -2429,10 +2592,9 @@ 1F3DB ; non-fully-qualified # ๐ classical building 1F3D7 FE0F ; fully-qualified # ๐๏ธ building construction 1F3D7 ; non-fully-qualified # ๐ building construction -1F3D8 FE0F ; fully-qualified # ๐๏ธ house -1F3D8 ; non-fully-qualified # ๐ house -1F3D9 FE0F ; fully-qualified # ๐๏ธ cityscape -1F3D9 ; non-fully-qualified # ๐ cityscape +1F9F1 ; fully-qualified # ๐งฑ brick +1F3D8 FE0F ; fully-qualified # ๐๏ธ houses +1F3D8 ; non-fully-qualified # ๐ houses 1F3DA FE0F ; fully-qualified # ๐๏ธ derelict house 1F3DA ; non-fully-qualified # ๐ derelict house 1F3E0 ; fully-qualified # ๐ house @@ -2467,6 +2629,8 @@ 26FA ; fully-qualified # โบ tent 1F301 ; fully-qualified # ๐ foggy 1F303 ; fully-qualified # ๐ night with stars +1F3D9 FE0F ; fully-qualified # ๐๏ธ cityscape +1F3D9 ; non-fully-qualified # ๐ cityscape 1F304 ; fully-qualified # ๐ sunrise over mountains 1F305 ; fully-qualified # ๐
sunrise 1F306 ; fully-qualified # ๐ cityscape at dusk @@ -2480,17 +2644,12 @@ 1F3A2 ; fully-qualified # ๐ข roller coaster 1F488 ; fully-qualified # ๐ barber pole 1F3AA ; fully-qualified # ๐ช circus tent -1F3AD ; fully-qualified # ๐ญ performing arts -1F5BC FE0F ; fully-qualified # ๐ผ๏ธ framed picture -1F5BC ; non-fully-qualified # ๐ผ framed picture -1F3A8 ; fully-qualified # ๐จ artist palette -1F3B0 ; fully-qualified # ๐ฐ slot machine # subgroup: transport-ground 1F682 ; fully-qualified # ๐ locomotive 1F683 ; fully-qualified # ๐ railway car 1F684 ; fully-qualified # ๐ high-speed train -1F685 ; fully-qualified # ๐
high-speed train with bullet nose +1F685 ; fully-qualified # ๐
bullet train 1F686 ; fully-qualified # ๐ train 1F687 ; fully-qualified # ๐ metro 1F688 ; fully-qualified # ๐ light rail @@ -2517,18 +2676,21 @@ 1F69C ; fully-qualified # ๐ tractor 1F6B2 ; fully-qualified # ๐ฒ bicycle 1F6F4 ; fully-qualified # ๐ด kick scooter +1F6F9 ; fully-qualified # ๐น skateboard 1F6F5 ; fully-qualified # ๐ต motor scooter 1F68F ; fully-qualified # ๐ bus stop 1F6E3 FE0F ; fully-qualified # ๐ฃ๏ธ motorway 1F6E3 ; non-fully-qualified # ๐ฃ motorway 1F6E4 FE0F ; fully-qualified # ๐ค๏ธ railway track 1F6E4 ; non-fully-qualified # ๐ค railway track +1F6E2 FE0F ; fully-qualified # ๐ข๏ธ oil drum +1F6E2 ; non-fully-qualified # ๐ข oil drum 26FD ; fully-qualified # โฝ fuel pump 1F6A8 ; fully-qualified # ๐จ police car light 1F6A5 ; fully-qualified # ๐ฅ horizontal traffic light 1F6A6 ; fully-qualified # ๐ฆ vertical traffic light -1F6A7 ; fully-qualified # ๐ง construction 1F6D1 ; fully-qualified # ๐ stop sign +1F6A7 ; fully-qualified # ๐ง construction # subgroup: transport-water 2693 ; fully-qualified # โ anchor @@ -2563,18 +2725,11 @@ # subgroup: hotel 1F6CE FE0F ; fully-qualified # ๐๏ธ bellhop bell 1F6CE ; non-fully-qualified # ๐ bellhop bell -1F6AA ; fully-qualified # ๐ช door -1F6CF FE0F ; fully-qualified # ๐๏ธ bed -1F6CF ; non-fully-qualified # ๐ bed -1F6CB FE0F ; fully-qualified # ๐๏ธ couch and lamp -1F6CB ; non-fully-qualified # ๐ couch and lamp -1F6BD ; fully-qualified # ๐ฝ toilet -1F6BF ; fully-qualified # ๐ฟ shower -1F6C1 ; fully-qualified # ๐ bathtub +1F9F3 ; fully-qualified # ๐งณ luggage # subgroup: time -231B ; fully-qualified # โ hourglass -23F3 ; fully-qualified # โณ hourglass with flowing sand +231B ; fully-qualified # โ hourglass done +23F3 ; fully-qualified # โณ hourglass not done 231A ; fully-qualified # โ watch 23F0 ; fully-qualified # โฐ alarm clock 23F1 FE0F ; fully-qualified # โฑ๏ธ stopwatch @@ -2619,15 +2774,15 @@ 1F318 ; fully-qualified # ๐ waning crescent moon 1F319 ; fully-qualified # ๐ crescent moon 1F31A ; fully-qualified # ๐ new moon face -1F31B ; fully-qualified # ๐ first quarter moon with face -1F31C ; fully-qualified # ๐ last quarter moon with face +1F31B ; fully-qualified # ๐ first quarter moon face +1F31C ; fully-qualified # ๐ last quarter moon face 1F321 FE0F ; fully-qualified # ๐ก๏ธ thermometer 1F321 ; non-fully-qualified # ๐ก thermometer 2600 FE0F ; fully-qualified # โ๏ธ sun 2600 ; non-fully-qualified # โ sun -1F31D ; fully-qualified # ๐ full moon with face +1F31D ; fully-qualified # ๐ full moon face 1F31E ; fully-qualified # ๐ sun with face -2B50 ; fully-qualified # โญ white medium star +2B50 ; fully-qualified # โญ star 1F31F ; fully-qualified # ๐ glowing star 1F320 ; fully-qualified # ๐ shooting star 2601 FE0F ; fully-qualified # โ๏ธ cloud @@ -2673,8 +2828,8 @@ 1F4A7 ; fully-qualified # ๐ง droplet 1F30A ; fully-qualified # ๐ water wave -# Travel & Places subtotal: 256 -# Travel & Places subtotal: 256 w/o modifiers +# Travel & Places subtotal: 249 +# Travel & Places subtotal: 249 w/o modifiers # group: Activities @@ -2683,6 +2838,7 @@ 1F384 ; fully-qualified # ๐ Christmas tree 1F386 ; fully-qualified # ๐ fireworks 1F387 ; fully-qualified # ๐ sparkler +1F9E8 ; fully-qualified # ๐งจ firecracker 2728 ; fully-qualified # โจ sparkles 1F388 ; fully-qualified # ๐ balloon 1F389 ; fully-qualified # ๐ party popper @@ -2693,6 +2849,7 @@ 1F38F ; fully-qualified # ๐ carp streamer 1F390 ; fully-qualified # ๐ wind chime 1F391 ; fully-qualified # ๐ moon viewing ceremony +1F9E7 ; fully-qualified # ๐งง red envelope 1F380 ; fully-qualified # ๐ ribbon 1F381 ; fully-qualified # ๐ wrapped gift 1F397 FE0F ; fully-qualified # ๐๏ธ reminder ribbon @@ -2713,22 +2870,23 @@ # subgroup: sport 26BD ; fully-qualified # โฝ soccer ball 26BE ; fully-qualified # โพ baseball +1F94E ; fully-qualified # ๐ฅ softball 1F3C0 ; fully-qualified # ๐ basketball 1F3D0 ; fully-qualified # ๐ volleyball 1F3C8 ; fully-qualified # ๐ american football 1F3C9 ; fully-qualified # ๐ rugby football 1F3BE ; fully-qualified # ๐พ tennis -1F3B1 ; fully-qualified # ๐ฑ pool 8 ball +1F94F ; fully-qualified # ๐ฅ flying disc 1F3B3 ; fully-qualified # ๐ณ bowling -1F3CF ; fully-qualified # ๐ cricket +1F3CF ; fully-qualified # ๐ cricket game 1F3D1 ; fully-qualified # ๐ field hockey 1F3D2 ; fully-qualified # ๐ ice hockey +1F94D ; fully-qualified # ๐ฅ lacrosse 1F3D3 ; fully-qualified # ๐ ping pong 1F3F8 ; fully-qualified # ๐ธ badminton 1F94A ; fully-qualified # ๐ฅ boxing glove 1F94B ; fully-qualified # ๐ฅ martial arts uniform 1F945 ; fully-qualified # ๐ฅ
goal net -1F3AF ; fully-qualified # ๐ฏ direct hit 26F3 ; fully-qualified # โณ flag in hole 26F8 FE0F ; fully-qualified # โธ๏ธ ice skate 26F8 ; non-fully-qualified # โธ ice skate @@ -2739,10 +2897,17 @@ 1F94C ; fully-qualified # ๐ฅ curling stone # subgroup: game +1F3AF ; fully-qualified # ๐ฏ direct hit +1F3B1 ; fully-qualified # ๐ฑ pool 8 ball +1F52E ; fully-qualified # ๐ฎ crystal ball +1F9FF ; fully-qualified # ๐งฟ nazar amulet 1F3AE ; fully-qualified # ๐ฎ video game 1F579 FE0F ; fully-qualified # ๐น๏ธ joystick 1F579 ; non-fully-qualified # ๐น joystick +1F3B0 ; fully-qualified # ๐ฐ slot machine 1F3B2 ; fully-qualified # ๐ฒ game die +1F9E9 ; fully-qualified # ๐งฉ jigsaw +1F9F8 ; fully-qualified # ๐งธ teddy bear 2660 FE0F ; fully-qualified # โ ๏ธ spade suit 2660 ; non-fully-qualified # โ spade suit 2665 FE0F ; fully-qualified # โฅ๏ธ heart suit @@ -2751,12 +2916,22 @@ 2666 ; non-fully-qualified # โฆ diamond suit 2663 FE0F ; fully-qualified # โฃ๏ธ club suit 2663 ; non-fully-qualified # โฃ club suit +265F FE0F ; fully-qualified # โ๏ธ chess pawn +265F ; non-fully-qualified # โ chess pawn 1F0CF ; fully-qualified # ๐ joker 1F004 ; fully-qualified # ๐ mahjong red dragon 1F3B4 ; fully-qualified # ๐ด flower playing cards -# Activities subtotal: 69 -# Activities subtotal: 69 w/o modifiers +# subgroup: arts & crafts +1F3AD ; fully-qualified # ๐ญ performing arts +1F5BC FE0F ; fully-qualified # ๐ผ๏ธ framed picture +1F5BC ; non-fully-qualified # ๐ผ framed picture +1F3A8 ; fully-qualified # ๐จ artist palette +1F9F5 ; fully-qualified # ๐งต thread +1F9F6 ; fully-qualified # ๐งถ yarn + +# Activities subtotal: 87 +# Activities subtotal: 87 w/o modifiers # group: Objects @@ -2820,6 +2995,7 @@ 1F4BE ; fully-qualified # ๐พ floppy disk 1F4BF ; fully-qualified # ๐ฟ optical disk 1F4C0 ; fully-qualified # ๐ dvd +1F9EE ; fully-qualified # ๐งฎ abacus # subgroup: light & video 1F3A5 ; fully-qualified # ๐ฅ movie camera @@ -2833,11 +3009,8 @@ 1F4F8 ; fully-qualified # ๐ธ camera with flash 1F4F9 ; fully-qualified # ๐น video camera 1F4FC ; fully-qualified # ๐ผ videocassette -1F50D ; fully-qualified # ๐ left-pointing magnifying glass -1F50E ; fully-qualified # ๐ right-pointing magnifying glass -1F52C ; fully-qualified # ๐ฌ microscope -1F52D ; fully-qualified # ๐ญ telescope -1F4E1 ; fully-qualified # ๐ก satellite antenna +1F50D ; fully-qualified # ๐ magnifying glass tilted left +1F50E ; fully-qualified # ๐ magnifying glass tilted right 1F56F FE0F ; fully-qualified # ๐ฏ๏ธ candle 1F56F ; non-fully-qualified # ๐ฏ candle 1F4A1 ; fully-qualified # ๐ก light bulb @@ -2873,6 +3046,7 @@ 1F4B7 ; fully-qualified # ๐ท pound banknote 1F4B8 ; fully-qualified # ๐ธ money with wings 1F4B3 ; fully-qualified # ๐ณ credit card +1F9FE ; fully-qualified # ๐งพ receipt 1F4B9 ; fully-qualified # ๐น chart increasing with yen 1F4B1 ; fully-qualified # ๐ฑ currency exchange 1F4B2 ; fully-qualified # ๐ฒ heavy dollar sign @@ -2973,18 +3147,47 @@ 2699 ; non-fully-qualified # โ gear 1F5DC FE0F ; fully-qualified # ๐๏ธ clamp 1F5DC ; non-fully-qualified # ๐ clamp -2697 FE0F ; fully-qualified # โ๏ธ alembic -2697 ; non-fully-qualified # โ alembic 2696 FE0F ; fully-qualified # โ๏ธ balance scale 2696 ; non-fully-qualified # โ balance scale 1F517 ; fully-qualified # ๐ link 26D3 FE0F ; fully-qualified # โ๏ธ chains 26D3 ; non-fully-qualified # โ chains +1F9F0 ; fully-qualified # ๐งฐ toolbox +1F9F2 ; fully-qualified # ๐งฒ magnet + +# subgroup: science +2697 FE0F ; fully-qualified # โ๏ธ alembic +2697 ; non-fully-qualified # โ alembic +1F9EA ; fully-qualified # ๐งช test tube +1F9EB ; fully-qualified # ๐งซ petri dish +1F9EC ; fully-qualified # ๐งฌ dna +1F52C ; fully-qualified # ๐ฌ microscope +1F52D ; fully-qualified # ๐ญ telescope +1F4E1 ; fully-qualified # ๐ก satellite antenna # subgroup: medical 1F489 ; fully-qualified # ๐ syringe 1F48A ; fully-qualified # ๐ pill +# subgroup: household +1F6AA ; fully-qualified # ๐ช door +1F6CF FE0F ; fully-qualified # ๐๏ธ bed +1F6CF ; non-fully-qualified # ๐ bed +1F6CB FE0F ; fully-qualified # ๐๏ธ couch and lamp +1F6CB ; non-fully-qualified # ๐ couch and lamp +1F6BD ; fully-qualified # ๐ฝ toilet +1F6BF ; fully-qualified # ๐ฟ shower +1F6C1 ; fully-qualified # ๐ bathtub +1F9F4 ; fully-qualified # ๐งด lotion bottle +1F9F7 ; fully-qualified # ๐งท safety pin +1F9F9 ; fully-qualified # ๐งน broom +1F9FA ; fully-qualified # ๐งบ basket +1F9FB ; fully-qualified # ๐งป roll of paper +1F9FC ; fully-qualified # ๐งผ soap +1F9FD ; fully-qualified # ๐งฝ sponge +1F9EF ; fully-qualified # ๐งฏ fire extinguisher +1F6D2 ; fully-qualified # ๐ shopping cart + # subgroup: other-object 1F6AC ; fully-qualified # ๐ฌ cigarette 26B0 FE0F ; fully-qualified # โฐ๏ธ coffin @@ -2992,13 +3195,9 @@ 26B1 FE0F ; fully-qualified # โฑ๏ธ funeral urn 26B1 ; non-fully-qualified # โฑ funeral urn 1F5FF ; fully-qualified # ๐ฟ moai -1F6E2 FE0F ; fully-qualified # ๐ข๏ธ oil drum -1F6E2 ; non-fully-qualified # ๐ข oil drum -1F52E ; fully-qualified # ๐ฎ crystal ball -1F6D2 ; fully-qualified # ๐ shopping cart -# Objects subtotal: 207 -# Objects subtotal: 207 w/o modifiers +# Objects subtotal: 227 +# Objects subtotal: 227 w/o modifiers # group: Symbols @@ -3065,7 +3264,7 @@ 2935 FE0F ; fully-qualified # โคต๏ธ right arrow curving down 2935 ; non-fully-qualified # โคต right arrow curving down 1F503 ; fully-qualified # ๐ clockwise vertical arrows -1F504 ; fully-qualified # ๐ anticlockwise arrows button +1F504 ; fully-qualified # ๐ counterclockwise arrows button 1F519 ; fully-qualified # ๐ BACK arrow 1F51A ; fully-qualified # ๐ END arrow 1F51B ; fully-qualified # ๐ ON! arrow @@ -3103,7 +3302,7 @@ 264C ; fully-qualified # โ Leo 264D ; fully-qualified # โ Virgo 264E ; fully-qualified # โ Libra -264F ; fully-qualified # โ Scorpius +264F ; fully-qualified # โ Scorpio 2650 ; fully-qualified # โ Sagittarius 2651 ; fully-qualified # โ Capricorn 2652 ; fully-qualified # โ Aquarius @@ -3126,9 +3325,9 @@ 23EA ; fully-qualified # โช fast reverse button 23EE FE0F ; fully-qualified # โฎ๏ธ last track button 23EE ; non-fully-qualified # โฎ last track button -1F53C ; fully-qualified # ๐ผ up button +1F53C ; fully-qualified # ๐ผ upwards button 23EB ; fully-qualified # โซ fast up button -1F53D ; fully-qualified # ๐ฝ down button +1F53D ; fully-qualified # ๐ฝ downwards button 23EC ; fully-qualified # โฌ fast down button 23F8 FE0F ; fully-qualified # โธ๏ธ pause button 23F8 ; non-fully-qualified # โธ pause button @@ -3152,6 +3351,8 @@ 2642 ; non-fully-qualified # โ male sign 2695 FE0F ; fully-qualified # โ๏ธ medical symbol 2695 ; non-fully-qualified # โ medical symbol +267E FE0F ; fully-qualified # โพ๏ธ infinity +267E ; non-fully-qualified # โพ infinity 267B FE0F ; fully-qualified # โป๏ธ recycling symbol 267B ; non-fully-qualified # โป recycling symbol 269C FE0F ; fully-qualified # โ๏ธ fleur-de-lis @@ -3224,7 +3425,7 @@ 0038 20E3 ; non-fully-qualified # 8โฃ keycap: 8 0039 FE0F 20E3 ; fully-qualified # 9๏ธโฃ keycap: 9 0039 20E3 ; non-fully-qualified # 9โฃ keycap: 9 -1F51F ; fully-qualified # ๐ keycap 10 +1F51F ; fully-qualified # ๐ keycap: 10 # subgroup: alphanum 1F4AF ; fully-qualified # ๐ฏ hundred points @@ -3279,18 +3480,22 @@ 1F235 ; fully-qualified # ๐ต Japanese โno vacancyโ button # subgroup: geometric -25AA FE0F ; fully-qualified # โช๏ธ black small square -25AA ; non-fully-qualified # โช black small square -25AB FE0F ; fully-qualified # โซ๏ธ white small square -25AB ; non-fully-qualified # โซ white small square -25FB FE0F ; fully-qualified # โป๏ธ white medium square -25FB ; non-fully-qualified # โป white medium square +1F534 ; fully-qualified # ๐ด red circle +1F535 ; fully-qualified # ๐ต blue circle +26AA ; fully-qualified # โช white circle +26AB ; fully-qualified # โซ black circle +2B1C ; fully-qualified # โฌ white large square +2B1B ; fully-qualified # โฌ black large square 25FC FE0F ; fully-qualified # โผ๏ธ black medium square 25FC ; non-fully-qualified # โผ black medium square +25FB FE0F ; fully-qualified # โป๏ธ white medium square +25FB ; non-fully-qualified # โป white medium square 25FD ; fully-qualified # โฝ white medium-small square 25FE ; fully-qualified # โพ black medium-small square -2B1B ; fully-qualified # โฌ black large square -2B1C ; fully-qualified # โฌ white large square +25AB FE0F ; fully-qualified # โซ๏ธ white small square +25AB ; non-fully-qualified # โซ white small square +25AA FE0F ; fully-qualified # โช๏ธ black small square +25AA ; non-fully-qualified # โช black small square 1F536 ; fully-qualified # ๐ถ large orange diamond 1F537 ; fully-qualified # ๐ท large blue diamond 1F538 ; fully-qualified # ๐ธ small orange diamond @@ -3301,13 +3506,9 @@ 1F518 ; fully-qualified # ๐ radio button 1F532 ; fully-qualified # ๐ฒ black square button 1F533 ; fully-qualified # ๐ณ white square button -26AA ; fully-qualified # โช white circle -26AB ; fully-qualified # โซ black circle -1F534 ; fully-qualified # ๐ด red circle -1F535 ; fully-qualified # ๐ต blue circle -# Symbols subtotal: 284 -# Symbols subtotal: 284 w/o modifiers +# Symbols subtotal: 286 +# Symbols subtotal: 286 w/o modifiers # group: Flags @@ -3320,273 +3521,275 @@ 1F3F3 ; non-fully-qualified # ๐ณ white flag 1F3F3 FE0F 200D 1F308 ; fully-qualified # ๐ณ๏ธโ๐ rainbow flag 1F3F3 200D 1F308 ; non-fully-qualified # ๐ณโ๐ rainbow flag +1F3F4 200D 2620 FE0F ; fully-qualified # ๐ดโโ ๏ธ pirate flag +1F3F4 200D 2620 ; non-fully-qualified # ๐ดโโ pirate flag # subgroup: country-flag -1F1E6 1F1E8 ; fully-qualified # ๐ฆ๐จ Ascension Island -1F1E6 1F1E9 ; fully-qualified # ๐ฆ๐ฉ Andorra -1F1E6 1F1EA ; fully-qualified # ๐ฆ๐ช United Arab Emirates -1F1E6 1F1EB ; fully-qualified # ๐ฆ๐ซ Afghanistan -1F1E6 1F1EC ; fully-qualified # ๐ฆ๐ฌ Antigua & Barbuda -1F1E6 1F1EE ; fully-qualified # ๐ฆ๐ฎ Anguilla -1F1E6 1F1F1 ; fully-qualified # ๐ฆ๐ฑ Albania -1F1E6 1F1F2 ; fully-qualified # ๐ฆ๐ฒ Armenia -1F1E6 1F1F4 ; fully-qualified # ๐ฆ๐ด Angola -1F1E6 1F1F6 ; fully-qualified # ๐ฆ๐ถ Antarctica -1F1E6 1F1F7 ; fully-qualified # ๐ฆ๐ท Argentina -1F1E6 1F1F8 ; fully-qualified # ๐ฆ๐ธ American Samoa -1F1E6 1F1F9 ; fully-qualified # ๐ฆ๐น Austria -1F1E6 1F1FA ; fully-qualified # ๐ฆ๐บ Australia -1F1E6 1F1FC ; fully-qualified # ๐ฆ๐ผ Aruba -1F1E6 1F1FD ; fully-qualified # ๐ฆ๐ฝ ร
land Islands -1F1E6 1F1FF ; fully-qualified # ๐ฆ๐ฟ Azerbaijan -1F1E7 1F1E6 ; fully-qualified # ๐ง๐ฆ Bosnia & Herzegovina -1F1E7 1F1E7 ; fully-qualified # ๐ง๐ง Barbados -1F1E7 1F1E9 ; fully-qualified # ๐ง๐ฉ Bangladesh -1F1E7 1F1EA ; fully-qualified # ๐ง๐ช Belgium -1F1E7 1F1EB ; fully-qualified # ๐ง๐ซ Burkina Faso -1F1E7 1F1EC ; fully-qualified # ๐ง๐ฌ Bulgaria -1F1E7 1F1ED ; fully-qualified # ๐ง๐ญ Bahrain -1F1E7 1F1EE ; fully-qualified # ๐ง๐ฎ Burundi -1F1E7 1F1EF ; fully-qualified # ๐ง๐ฏ Benin -1F1E7 1F1F1 ; fully-qualified # ๐ง๐ฑ St. Barthรฉlemy -1F1E7 1F1F2 ; fully-qualified # ๐ง๐ฒ Bermuda -1F1E7 1F1F3 ; fully-qualified # ๐ง๐ณ Brunei -1F1E7 1F1F4 ; fully-qualified # ๐ง๐ด Bolivia -1F1E7 1F1F6 ; fully-qualified # ๐ง๐ถ Caribbean Netherlands -1F1E7 1F1F7 ; fully-qualified # ๐ง๐ท Brazil -1F1E7 1F1F8 ; fully-qualified # ๐ง๐ธ Bahamas -1F1E7 1F1F9 ; fully-qualified # ๐ง๐น Bhutan -1F1E7 1F1FB ; fully-qualified # ๐ง๐ป Bouvet Island -1F1E7 1F1FC ; fully-qualified # ๐ง๐ผ Botswana -1F1E7 1F1FE ; fully-qualified # ๐ง๐พ Belarus -1F1E7 1F1FF ; fully-qualified # ๐ง๐ฟ Belize -1F1E8 1F1E6 ; fully-qualified # ๐จ๐ฆ Canada -1F1E8 1F1E8 ; fully-qualified # ๐จ๐จ Cocos (Keeling) Islands -1F1E8 1F1E9 ; fully-qualified # ๐จ๐ฉ Congo - Kinshasa -1F1E8 1F1EB ; fully-qualified # ๐จ๐ซ Central African Republic -1F1E8 1F1EC ; fully-qualified # ๐จ๐ฌ Congo - Brazzaville -1F1E8 1F1ED ; fully-qualified # ๐จ๐ญ Switzerland -1F1E8 1F1EE ; fully-qualified # ๐จ๐ฎ Cรดte dโIvoire -1F1E8 1F1F0 ; fully-qualified # ๐จ๐ฐ Cook Islands -1F1E8 1F1F1 ; fully-qualified # ๐จ๐ฑ Chile -1F1E8 1F1F2 ; fully-qualified # ๐จ๐ฒ Cameroon -1F1E8 1F1F3 ; fully-qualified # ๐จ๐ณ China -1F1E8 1F1F4 ; fully-qualified # ๐จ๐ด Colombia -1F1E8 1F1F5 ; fully-qualified # ๐จ๐ต Clipperton Island -1F1E8 1F1F7 ; fully-qualified # ๐จ๐ท Costa Rica -1F1E8 1F1FA ; fully-qualified # ๐จ๐บ Cuba -1F1E8 1F1FB ; fully-qualified # ๐จ๐ป Cape Verde -1F1E8 1F1FC ; fully-qualified # ๐จ๐ผ Curaรงao -1F1E8 1F1FD ; fully-qualified # ๐จ๐ฝ Christmas Island -1F1E8 1F1FE ; fully-qualified # ๐จ๐พ Cyprus -1F1E8 1F1FF ; fully-qualified # ๐จ๐ฟ Czechia -1F1E9 1F1EA ; fully-qualified # ๐ฉ๐ช Germany -1F1E9 1F1EC ; fully-qualified # ๐ฉ๐ฌ Diego Garcia -1F1E9 1F1EF ; fully-qualified # ๐ฉ๐ฏ Djibouti -1F1E9 1F1F0 ; fully-qualified # ๐ฉ๐ฐ Denmark -1F1E9 1F1F2 ; fully-qualified # ๐ฉ๐ฒ Dominica -1F1E9 1F1F4 ; fully-qualified # ๐ฉ๐ด Dominican Republic -1F1E9 1F1FF ; fully-qualified # ๐ฉ๐ฟ Algeria -1F1EA 1F1E6 ; fully-qualified # ๐ช๐ฆ Ceuta & Melilla -1F1EA 1F1E8 ; fully-qualified # ๐ช๐จ Ecuador -1F1EA 1F1EA ; fully-qualified # ๐ช๐ช Estonia -1F1EA 1F1EC ; fully-qualified # ๐ช๐ฌ Egypt -1F1EA 1F1ED ; fully-qualified # ๐ช๐ญ Western Sahara -1F1EA 1F1F7 ; fully-qualified # ๐ช๐ท Eritrea -1F1EA 1F1F8 ; fully-qualified # ๐ช๐ธ Spain -1F1EA 1F1F9 ; fully-qualified # ๐ช๐น Ethiopia -1F1EA 1F1FA ; fully-qualified # ๐ช๐บ European Union -1F1EB 1F1EE ; fully-qualified # ๐ซ๐ฎ Finland -1F1EB 1F1EF ; fully-qualified # ๐ซ๐ฏ Fiji -1F1EB 1F1F0 ; fully-qualified # ๐ซ๐ฐ Falkland Islands -1F1EB 1F1F2 ; fully-qualified # ๐ซ๐ฒ Micronesia -1F1EB 1F1F4 ; fully-qualified # ๐ซ๐ด Faroe Islands -1F1EB 1F1F7 ; fully-qualified # ๐ซ๐ท France -1F1EC 1F1E6 ; fully-qualified # ๐ฌ๐ฆ Gabon -1F1EC 1F1E7 ; fully-qualified # ๐ฌ๐ง United Kingdom -1F1EC 1F1E9 ; fully-qualified # ๐ฌ๐ฉ Grenada -1F1EC 1F1EA ; fully-qualified # ๐ฌ๐ช Georgia -1F1EC 1F1EB ; fully-qualified # ๐ฌ๐ซ French Guiana -1F1EC 1F1EC ; fully-qualified # ๐ฌ๐ฌ Guernsey -1F1EC 1F1ED ; fully-qualified # ๐ฌ๐ญ Ghana -1F1EC 1F1EE ; fully-qualified # ๐ฌ๐ฎ Gibraltar -1F1EC 1F1F1 ; fully-qualified # ๐ฌ๐ฑ Greenland -1F1EC 1F1F2 ; fully-qualified # ๐ฌ๐ฒ Gambia -1F1EC 1F1F3 ; fully-qualified # ๐ฌ๐ณ Guinea -1F1EC 1F1F5 ; fully-qualified # ๐ฌ๐ต Guadeloupe -1F1EC 1F1F6 ; fully-qualified # ๐ฌ๐ถ Equatorial Guinea -1F1EC 1F1F7 ; fully-qualified # ๐ฌ๐ท Greece -1F1EC 1F1F8 ; fully-qualified # ๐ฌ๐ธ South Georgia & South Sandwich Islands -1F1EC 1F1F9 ; fully-qualified # ๐ฌ๐น Guatemala -1F1EC 1F1FA ; fully-qualified # ๐ฌ๐บ Guam -1F1EC 1F1FC ; fully-qualified # ๐ฌ๐ผ Guinea-Bissau -1F1EC 1F1FE ; fully-qualified # ๐ฌ๐พ Guyana -1F1ED 1F1F0 ; fully-qualified # ๐ญ๐ฐ Hong Kong SAR China -1F1ED 1F1F2 ; fully-qualified # ๐ญ๐ฒ Heard & McDonald Islands -1F1ED 1F1F3 ; fully-qualified # ๐ญ๐ณ Honduras -1F1ED 1F1F7 ; fully-qualified # ๐ญ๐ท Croatia -1F1ED 1F1F9 ; fully-qualified # ๐ญ๐น Haiti -1F1ED 1F1FA ; fully-qualified # ๐ญ๐บ Hungary -1F1EE 1F1E8 ; fully-qualified # ๐ฎ๐จ Canary Islands -1F1EE 1F1E9 ; fully-qualified # ๐ฎ๐ฉ Indonesia -1F1EE 1F1EA ; fully-qualified # ๐ฎ๐ช Ireland -1F1EE 1F1F1 ; fully-qualified # ๐ฎ๐ฑ Israel -1F1EE 1F1F2 ; fully-qualified # ๐ฎ๐ฒ Isle of Man -1F1EE 1F1F3 ; fully-qualified # ๐ฎ๐ณ India -1F1EE 1F1F4 ; fully-qualified # ๐ฎ๐ด British Indian Ocean Territory -1F1EE 1F1F6 ; fully-qualified # ๐ฎ๐ถ Iraq -1F1EE 1F1F7 ; fully-qualified # ๐ฎ๐ท Iran -1F1EE 1F1F8 ; fully-qualified # ๐ฎ๐ธ Iceland -1F1EE 1F1F9 ; fully-qualified # ๐ฎ๐น Italy -1F1EF 1F1EA ; fully-qualified # ๐ฏ๐ช Jersey -1F1EF 1F1F2 ; fully-qualified # ๐ฏ๐ฒ Jamaica -1F1EF 1F1F4 ; fully-qualified # ๐ฏ๐ด Jordan -1F1EF 1F1F5 ; fully-qualified # ๐ฏ๐ต Japan -1F1F0 1F1EA ; fully-qualified # ๐ฐ๐ช Kenya -1F1F0 1F1EC ; fully-qualified # ๐ฐ๐ฌ Kyrgyzstan -1F1F0 1F1ED ; fully-qualified # ๐ฐ๐ญ Cambodia -1F1F0 1F1EE ; fully-qualified # ๐ฐ๐ฎ Kiribati -1F1F0 1F1F2 ; fully-qualified # ๐ฐ๐ฒ Comoros -1F1F0 1F1F3 ; fully-qualified # ๐ฐ๐ณ St. Kitts & Nevis -1F1F0 1F1F5 ; fully-qualified # ๐ฐ๐ต North Korea -1F1F0 1F1F7 ; fully-qualified # ๐ฐ๐ท South Korea -1F1F0 1F1FC ; fully-qualified # ๐ฐ๐ผ Kuwait -1F1F0 1F1FE ; fully-qualified # ๐ฐ๐พ Cayman Islands -1F1F0 1F1FF ; fully-qualified # ๐ฐ๐ฟ Kazakhstan -1F1F1 1F1E6 ; fully-qualified # ๐ฑ๐ฆ Laos -1F1F1 1F1E7 ; fully-qualified # ๐ฑ๐ง Lebanon -1F1F1 1F1E8 ; fully-qualified # ๐ฑ๐จ St. Lucia -1F1F1 1F1EE ; fully-qualified # ๐ฑ๐ฎ Liechtenstein -1F1F1 1F1F0 ; fully-qualified # ๐ฑ๐ฐ Sri Lanka -1F1F1 1F1F7 ; fully-qualified # ๐ฑ๐ท Liberia -1F1F1 1F1F8 ; fully-qualified # ๐ฑ๐ธ Lesotho -1F1F1 1F1F9 ; fully-qualified # ๐ฑ๐น Lithuania -1F1F1 1F1FA ; fully-qualified # ๐ฑ๐บ Luxembourg -1F1F1 1F1FB ; fully-qualified # ๐ฑ๐ป Latvia -1F1F1 1F1FE ; fully-qualified # ๐ฑ๐พ Libya -1F1F2 1F1E6 ; fully-qualified # ๐ฒ๐ฆ Morocco -1F1F2 1F1E8 ; fully-qualified # ๐ฒ๐จ Monaco -1F1F2 1F1E9 ; fully-qualified # ๐ฒ๐ฉ Moldova -1F1F2 1F1EA ; fully-qualified # ๐ฒ๐ช Montenegro -1F1F2 1F1EB ; fully-qualified # ๐ฒ๐ซ St. Martin -1F1F2 1F1EC ; fully-qualified # ๐ฒ๐ฌ Madagascar -1F1F2 1F1ED ; fully-qualified # ๐ฒ๐ญ Marshall Islands -1F1F2 1F1F0 ; fully-qualified # ๐ฒ๐ฐ Macedonia -1F1F2 1F1F1 ; fully-qualified # ๐ฒ๐ฑ Mali -1F1F2 1F1F2 ; fully-qualified # ๐ฒ๐ฒ Myanmar (Burma) -1F1F2 1F1F3 ; fully-qualified # ๐ฒ๐ณ Mongolia -1F1F2 1F1F4 ; fully-qualified # ๐ฒ๐ด Macau SAR China -1F1F2 1F1F5 ; fully-qualified # ๐ฒ๐ต Northern Mariana Islands -1F1F2 1F1F6 ; fully-qualified # ๐ฒ๐ถ Martinique -1F1F2 1F1F7 ; fully-qualified # ๐ฒ๐ท Mauritania -1F1F2 1F1F8 ; fully-qualified # ๐ฒ๐ธ Montserrat -1F1F2 1F1F9 ; fully-qualified # ๐ฒ๐น Malta -1F1F2 1F1FA ; fully-qualified # ๐ฒ๐บ Mauritius -1F1F2 1F1FB ; fully-qualified # ๐ฒ๐ป Maldives -1F1F2 1F1FC ; fully-qualified # ๐ฒ๐ผ Malawi -1F1F2 1F1FD ; fully-qualified # ๐ฒ๐ฝ Mexico -1F1F2 1F1FE ; fully-qualified # ๐ฒ๐พ Malaysia -1F1F2 1F1FF ; fully-qualified # ๐ฒ๐ฟ Mozambique -1F1F3 1F1E6 ; fully-qualified # ๐ณ๐ฆ Namibia -1F1F3 1F1E8 ; fully-qualified # ๐ณ๐จ New Caledonia -1F1F3 1F1EA ; fully-qualified # ๐ณ๐ช Niger -1F1F3 1F1EB ; fully-qualified # ๐ณ๐ซ Norfolk Island -1F1F3 1F1EC ; fully-qualified # ๐ณ๐ฌ Nigeria -1F1F3 1F1EE ; fully-qualified # ๐ณ๐ฎ Nicaragua -1F1F3 1F1F1 ; fully-qualified # ๐ณ๐ฑ Netherlands -1F1F3 1F1F4 ; fully-qualified # ๐ณ๐ด Norway -1F1F3 1F1F5 ; fully-qualified # ๐ณ๐ต Nepal -1F1F3 1F1F7 ; fully-qualified # ๐ณ๐ท Nauru -1F1F3 1F1FA ; fully-qualified # ๐ณ๐บ Niue -1F1F3 1F1FF ; fully-qualified # ๐ณ๐ฟ New Zealand -1F1F4 1F1F2 ; fully-qualified # ๐ด๐ฒ Oman -1F1F5 1F1E6 ; fully-qualified # ๐ต๐ฆ Panama -1F1F5 1F1EA ; fully-qualified # ๐ต๐ช Peru -1F1F5 1F1EB ; fully-qualified # ๐ต๐ซ French Polynesia -1F1F5 1F1EC ; fully-qualified # ๐ต๐ฌ Papua New Guinea -1F1F5 1F1ED ; fully-qualified # ๐ต๐ญ Philippines -1F1F5 1F1F0 ; fully-qualified # ๐ต๐ฐ Pakistan -1F1F5 1F1F1 ; fully-qualified # ๐ต๐ฑ Poland -1F1F5 1F1F2 ; fully-qualified # ๐ต๐ฒ St. Pierre & Miquelon -1F1F5 1F1F3 ; fully-qualified # ๐ต๐ณ Pitcairn Islands -1F1F5 1F1F7 ; fully-qualified # ๐ต๐ท Puerto Rico -1F1F5 1F1F8 ; fully-qualified # ๐ต๐ธ Palestinian Territories -1F1F5 1F1F9 ; fully-qualified # ๐ต๐น Portugal -1F1F5 1F1FC ; fully-qualified # ๐ต๐ผ Palau -1F1F5 1F1FE ; fully-qualified # ๐ต๐พ Paraguay -1F1F6 1F1E6 ; fully-qualified # ๐ถ๐ฆ Qatar -1F1F7 1F1EA ; fully-qualified # ๐ท๐ช Rรฉunion -1F1F7 1F1F4 ; fully-qualified # ๐ท๐ด Romania -1F1F7 1F1F8 ; fully-qualified # ๐ท๐ธ Serbia -1F1F7 1F1FA ; fully-qualified # ๐ท๐บ Russia -1F1F7 1F1FC ; fully-qualified # ๐ท๐ผ Rwanda -1F1F8 1F1E6 ; fully-qualified # ๐ธ๐ฆ Saudi Arabia -1F1F8 1F1E7 ; fully-qualified # ๐ธ๐ง Solomon Islands -1F1F8 1F1E8 ; fully-qualified # ๐ธ๐จ Seychelles -1F1F8 1F1E9 ; fully-qualified # ๐ธ๐ฉ Sudan -1F1F8 1F1EA ; fully-qualified # ๐ธ๐ช Sweden -1F1F8 1F1EC ; fully-qualified # ๐ธ๐ฌ Singapore -1F1F8 1F1ED ; fully-qualified # ๐ธ๐ญ St. Helena -1F1F8 1F1EE ; fully-qualified # ๐ธ๐ฎ Slovenia -1F1F8 1F1EF ; fully-qualified # ๐ธ๐ฏ Svalbard & Jan Mayen -1F1F8 1F1F0 ; fully-qualified # ๐ธ๐ฐ Slovakia -1F1F8 1F1F1 ; fully-qualified # ๐ธ๐ฑ Sierra Leone -1F1F8 1F1F2 ; fully-qualified # ๐ธ๐ฒ San Marino -1F1F8 1F1F3 ; fully-qualified # ๐ธ๐ณ Senegal -1F1F8 1F1F4 ; fully-qualified # ๐ธ๐ด Somalia -1F1F8 1F1F7 ; fully-qualified # ๐ธ๐ท Suriname -1F1F8 1F1F8 ; fully-qualified # ๐ธ๐ธ South Sudan -1F1F8 1F1F9 ; fully-qualified # ๐ธ๐น Sรฃo Tomรฉ & Prรญncipe -1F1F8 1F1FB ; fully-qualified # ๐ธ๐ป El Salvador -1F1F8 1F1FD ; fully-qualified # ๐ธ๐ฝ Sint Maarten -1F1F8 1F1FE ; fully-qualified # ๐ธ๐พ Syria -1F1F8 1F1FF ; fully-qualified # ๐ธ๐ฟ Swaziland -1F1F9 1F1E6 ; fully-qualified # ๐น๐ฆ Tristan da Cunha -1F1F9 1F1E8 ; fully-qualified # ๐น๐จ Turks & Caicos Islands -1F1F9 1F1E9 ; fully-qualified # ๐น๐ฉ Chad -1F1F9 1F1EB ; fully-qualified # ๐น๐ซ French Southern Territories -1F1F9 1F1EC ; fully-qualified # ๐น๐ฌ Togo -1F1F9 1F1ED ; fully-qualified # ๐น๐ญ Thailand -1F1F9 1F1EF ; fully-qualified # ๐น๐ฏ Tajikistan -1F1F9 1F1F0 ; fully-qualified # ๐น๐ฐ Tokelau -1F1F9 1F1F1 ; fully-qualified # ๐น๐ฑ Timor-Leste -1F1F9 1F1F2 ; fully-qualified # ๐น๐ฒ Turkmenistan -1F1F9 1F1F3 ; fully-qualified # ๐น๐ณ Tunisia -1F1F9 1F1F4 ; fully-qualified # ๐น๐ด Tonga -1F1F9 1F1F7 ; fully-qualified # ๐น๐ท Turkey -1F1F9 1F1F9 ; fully-qualified # ๐น๐น Trinidad & Tobago -1F1F9 1F1FB ; fully-qualified # ๐น๐ป Tuvalu -1F1F9 1F1FC ; fully-qualified # ๐น๐ผ Taiwan -1F1F9 1F1FF ; fully-qualified # ๐น๐ฟ Tanzania -1F1FA 1F1E6 ; fully-qualified # ๐บ๐ฆ Ukraine -1F1FA 1F1EC ; fully-qualified # ๐บ๐ฌ Uganda -1F1FA 1F1F2 ; fully-qualified # ๐บ๐ฒ U.S. Outlying Islands -1F1FA 1F1F3 ; fully-qualified # ๐บ๐ณ United Nations -1F1FA 1F1F8 ; fully-qualified # ๐บ๐ธ United States -1F1FA 1F1FE ; fully-qualified # ๐บ๐พ Uruguay -1F1FA 1F1FF ; fully-qualified # ๐บ๐ฟ Uzbekistan -1F1FB 1F1E6 ; fully-qualified # ๐ป๐ฆ Vatican City -1F1FB 1F1E8 ; fully-qualified # ๐ป๐จ St. Vincent & Grenadines -1F1FB 1F1EA ; fully-qualified # ๐ป๐ช Venezuela -1F1FB 1F1EC ; fully-qualified # ๐ป๐ฌ British Virgin Islands -1F1FB 1F1EE ; fully-qualified # ๐ป๐ฎ U.S. Virgin Islands -1F1FB 1F1F3 ; fully-qualified # ๐ป๐ณ Vietnam -1F1FB 1F1FA ; fully-qualified # ๐ป๐บ Vanuatu -1F1FC 1F1EB ; fully-qualified # ๐ผ๐ซ Wallis & Futuna -1F1FC 1F1F8 ; fully-qualified # ๐ผ๐ธ Samoa -1F1FD 1F1F0 ; fully-qualified # ๐ฝ๐ฐ Kosovo -1F1FE 1F1EA ; fully-qualified # ๐พ๐ช Yemen -1F1FE 1F1F9 ; fully-qualified # ๐พ๐น Mayotte -1F1FF 1F1E6 ; fully-qualified # ๐ฟ๐ฆ South Africa -1F1FF 1F1F2 ; fully-qualified # ๐ฟ๐ฒ Zambia -1F1FF 1F1FC ; fully-qualified # ๐ฟ๐ผ Zimbabwe +1F1E6 1F1E8 ; fully-qualified # ๐ฆ๐จ flag: Ascension Island +1F1E6 1F1E9 ; fully-qualified # ๐ฆ๐ฉ flag: Andorra +1F1E6 1F1EA ; fully-qualified # ๐ฆ๐ช flag: United Arab Emirates +1F1E6 1F1EB ; fully-qualified # ๐ฆ๐ซ flag: Afghanistan +1F1E6 1F1EC ; fully-qualified # ๐ฆ๐ฌ flag: Antigua & Barbuda +1F1E6 1F1EE ; fully-qualified # ๐ฆ๐ฎ flag: Anguilla +1F1E6 1F1F1 ; fully-qualified # ๐ฆ๐ฑ flag: Albania +1F1E6 1F1F2 ; fully-qualified # ๐ฆ๐ฒ flag: Armenia +1F1E6 1F1F4 ; fully-qualified # ๐ฆ๐ด flag: Angola +1F1E6 1F1F6 ; fully-qualified # ๐ฆ๐ถ flag: Antarctica +1F1E6 1F1F7 ; fully-qualified # ๐ฆ๐ท flag: Argentina +1F1E6 1F1F8 ; fully-qualified # ๐ฆ๐ธ flag: American Samoa +1F1E6 1F1F9 ; fully-qualified # ๐ฆ๐น flag: Austria +1F1E6 1F1FA ; fully-qualified # ๐ฆ๐บ flag: Australia +1F1E6 1F1FC ; fully-qualified # ๐ฆ๐ผ flag: Aruba +1F1E6 1F1FD ; fully-qualified # ๐ฆ๐ฝ flag: ร
land Islands +1F1E6 1F1FF ; fully-qualified # ๐ฆ๐ฟ flag: Azerbaijan +1F1E7 1F1E6 ; fully-qualified # ๐ง๐ฆ flag: Bosnia & Herzegovina +1F1E7 1F1E7 ; fully-qualified # ๐ง๐ง flag: Barbados +1F1E7 1F1E9 ; fully-qualified # ๐ง๐ฉ flag: Bangladesh +1F1E7 1F1EA ; fully-qualified # ๐ง๐ช flag: Belgium +1F1E7 1F1EB ; fully-qualified # ๐ง๐ซ flag: Burkina Faso +1F1E7 1F1EC ; fully-qualified # ๐ง๐ฌ flag: Bulgaria +1F1E7 1F1ED ; fully-qualified # ๐ง๐ญ flag: Bahrain +1F1E7 1F1EE ; fully-qualified # ๐ง๐ฎ flag: Burundi +1F1E7 1F1EF ; fully-qualified # ๐ง๐ฏ flag: Benin +1F1E7 1F1F1 ; fully-qualified # ๐ง๐ฑ flag: St. Barthรฉlemy +1F1E7 1F1F2 ; fully-qualified # ๐ง๐ฒ flag: Bermuda +1F1E7 1F1F3 ; fully-qualified # ๐ง๐ณ flag: Brunei +1F1E7 1F1F4 ; fully-qualified # ๐ง๐ด flag: Bolivia +1F1E7 1F1F6 ; fully-qualified # ๐ง๐ถ flag: Caribbean Netherlands +1F1E7 1F1F7 ; fully-qualified # ๐ง๐ท flag: Brazil +1F1E7 1F1F8 ; fully-qualified # ๐ง๐ธ flag: Bahamas +1F1E7 1F1F9 ; fully-qualified # ๐ง๐น flag: Bhutan +1F1E7 1F1FB ; fully-qualified # ๐ง๐ป flag: Bouvet Island +1F1E7 1F1FC ; fully-qualified # ๐ง๐ผ flag: Botswana +1F1E7 1F1FE ; fully-qualified # ๐ง๐พ flag: Belarus +1F1E7 1F1FF ; fully-qualified # ๐ง๐ฟ flag: Belize +1F1E8 1F1E6 ; fully-qualified # ๐จ๐ฆ flag: Canada +1F1E8 1F1E8 ; fully-qualified # ๐จ๐จ flag: Cocos (Keeling) Islands +1F1E8 1F1E9 ; fully-qualified # ๐จ๐ฉ flag: Congo - Kinshasa +1F1E8 1F1EB ; fully-qualified # ๐จ๐ซ flag: Central African Republic +1F1E8 1F1EC ; fully-qualified # ๐จ๐ฌ flag: Congo - Brazzaville +1F1E8 1F1ED ; fully-qualified # ๐จ๐ญ flag: Switzerland +1F1E8 1F1EE ; fully-qualified # ๐จ๐ฎ flag: Cรดte dโIvoire +1F1E8 1F1F0 ; fully-qualified # ๐จ๐ฐ flag: Cook Islands +1F1E8 1F1F1 ; fully-qualified # ๐จ๐ฑ flag: Chile +1F1E8 1F1F2 ; fully-qualified # ๐จ๐ฒ flag: Cameroon +1F1E8 1F1F3 ; fully-qualified # ๐จ๐ณ flag: China +1F1E8 1F1F4 ; fully-qualified # ๐จ๐ด flag: Colombia +1F1E8 1F1F5 ; fully-qualified # ๐จ๐ต flag: Clipperton Island +1F1E8 1F1F7 ; fully-qualified # ๐จ๐ท flag: Costa Rica +1F1E8 1F1FA ; fully-qualified # ๐จ๐บ flag: Cuba +1F1E8 1F1FB ; fully-qualified # ๐จ๐ป flag: Cape Verde +1F1E8 1F1FC ; fully-qualified # ๐จ๐ผ flag: Curaรงao +1F1E8 1F1FD ; fully-qualified # ๐จ๐ฝ flag: Christmas Island +1F1E8 1F1FE ; fully-qualified # ๐จ๐พ flag: Cyprus +1F1E8 1F1FF ; fully-qualified # ๐จ๐ฟ flag: Czechia +1F1E9 1F1EA ; fully-qualified # ๐ฉ๐ช flag: Germany +1F1E9 1F1EC ; fully-qualified # ๐ฉ๐ฌ flag: Diego Garcia +1F1E9 1F1EF ; fully-qualified # ๐ฉ๐ฏ flag: Djibouti +1F1E9 1F1F0 ; fully-qualified # ๐ฉ๐ฐ flag: Denmark +1F1E9 1F1F2 ; fully-qualified # ๐ฉ๐ฒ flag: Dominica +1F1E9 1F1F4 ; fully-qualified # ๐ฉ๐ด flag: Dominican Republic +1F1E9 1F1FF ; fully-qualified # ๐ฉ๐ฟ flag: Algeria +1F1EA 1F1E6 ; fully-qualified # ๐ช๐ฆ flag: Ceuta & Melilla +1F1EA 1F1E8 ; fully-qualified # ๐ช๐จ flag: Ecuador +1F1EA 1F1EA ; fully-qualified # ๐ช๐ช flag: Estonia +1F1EA 1F1EC ; fully-qualified # ๐ช๐ฌ flag: Egypt +1F1EA 1F1ED ; fully-qualified # ๐ช๐ญ flag: Western Sahara +1F1EA 1F1F7 ; fully-qualified # ๐ช๐ท flag: Eritrea +1F1EA 1F1F8 ; fully-qualified # ๐ช๐ธ flag: Spain +1F1EA 1F1F9 ; fully-qualified # ๐ช๐น flag: Ethiopia +1F1EA 1F1FA ; fully-qualified # ๐ช๐บ flag: European Union +1F1EB 1F1EE ; fully-qualified # ๐ซ๐ฎ flag: Finland +1F1EB 1F1EF ; fully-qualified # ๐ซ๐ฏ flag: Fiji +1F1EB 1F1F0 ; fully-qualified # ๐ซ๐ฐ flag: Falkland Islands +1F1EB 1F1F2 ; fully-qualified # ๐ซ๐ฒ flag: Micronesia +1F1EB 1F1F4 ; fully-qualified # ๐ซ๐ด flag: Faroe Islands +1F1EB 1F1F7 ; fully-qualified # ๐ซ๐ท flag: France +1F1EC 1F1E6 ; fully-qualified # ๐ฌ๐ฆ flag: Gabon +1F1EC 1F1E7 ; fully-qualified # ๐ฌ๐ง flag: United Kingdom +1F1EC 1F1E9 ; fully-qualified # ๐ฌ๐ฉ flag: Grenada +1F1EC 1F1EA ; fully-qualified # ๐ฌ๐ช flag: Georgia +1F1EC 1F1EB ; fully-qualified # ๐ฌ๐ซ flag: French Guiana +1F1EC 1F1EC ; fully-qualified # ๐ฌ๐ฌ flag: Guernsey +1F1EC 1F1ED ; fully-qualified # ๐ฌ๐ญ flag: Ghana +1F1EC 1F1EE ; fully-qualified # ๐ฌ๐ฎ flag: Gibraltar +1F1EC 1F1F1 ; fully-qualified # ๐ฌ๐ฑ flag: Greenland +1F1EC 1F1F2 ; fully-qualified # ๐ฌ๐ฒ flag: Gambia +1F1EC 1F1F3 ; fully-qualified # ๐ฌ๐ณ flag: Guinea +1F1EC 1F1F5 ; fully-qualified # ๐ฌ๐ต flag: Guadeloupe +1F1EC 1F1F6 ; fully-qualified # ๐ฌ๐ถ flag: Equatorial Guinea +1F1EC 1F1F7 ; fully-qualified # ๐ฌ๐ท flag: Greece +1F1EC 1F1F8 ; fully-qualified # ๐ฌ๐ธ flag: South Georgia & South Sandwich Islands +1F1EC 1F1F9 ; fully-qualified # ๐ฌ๐น flag: Guatemala +1F1EC 1F1FA ; fully-qualified # ๐ฌ๐บ flag: Guam +1F1EC 1F1FC ; fully-qualified # ๐ฌ๐ผ flag: Guinea-Bissau +1F1EC 1F1FE ; fully-qualified # ๐ฌ๐พ flag: Guyana +1F1ED 1F1F0 ; fully-qualified # ๐ญ๐ฐ flag: Hong Kong SAR China +1F1ED 1F1F2 ; fully-qualified # ๐ญ๐ฒ flag: Heard & McDonald Islands +1F1ED 1F1F3 ; fully-qualified # ๐ญ๐ณ flag: Honduras +1F1ED 1F1F7 ; fully-qualified # ๐ญ๐ท flag: Croatia +1F1ED 1F1F9 ; fully-qualified # ๐ญ๐น flag: Haiti +1F1ED 1F1FA ; fully-qualified # ๐ญ๐บ flag: Hungary +1F1EE 1F1E8 ; fully-qualified # ๐ฎ๐จ flag: Canary Islands +1F1EE 1F1E9 ; fully-qualified # ๐ฎ๐ฉ flag: Indonesia +1F1EE 1F1EA ; fully-qualified # ๐ฎ๐ช flag: Ireland +1F1EE 1F1F1 ; fully-qualified # ๐ฎ๐ฑ flag: Israel +1F1EE 1F1F2 ; fully-qualified # ๐ฎ๐ฒ flag: Isle of Man +1F1EE 1F1F3 ; fully-qualified # ๐ฎ๐ณ flag: India +1F1EE 1F1F4 ; fully-qualified # ๐ฎ๐ด flag: British Indian Ocean Territory +1F1EE 1F1F6 ; fully-qualified # ๐ฎ๐ถ flag: Iraq +1F1EE 1F1F7 ; fully-qualified # ๐ฎ๐ท flag: Iran +1F1EE 1F1F8 ; fully-qualified # ๐ฎ๐ธ flag: Iceland +1F1EE 1F1F9 ; fully-qualified # ๐ฎ๐น flag: Italy +1F1EF 1F1EA ; fully-qualified # ๐ฏ๐ช flag: Jersey +1F1EF 1F1F2 ; fully-qualified # ๐ฏ๐ฒ flag: Jamaica +1F1EF 1F1F4 ; fully-qualified # ๐ฏ๐ด flag: Jordan +1F1EF 1F1F5 ; fully-qualified # ๐ฏ๐ต flag: Japan +1F1F0 1F1EA ; fully-qualified # ๐ฐ๐ช flag: Kenya +1F1F0 1F1EC ; fully-qualified # ๐ฐ๐ฌ flag: Kyrgyzstan +1F1F0 1F1ED ; fully-qualified # ๐ฐ๐ญ flag: Cambodia +1F1F0 1F1EE ; fully-qualified # ๐ฐ๐ฎ flag: Kiribati +1F1F0 1F1F2 ; fully-qualified # ๐ฐ๐ฒ flag: Comoros +1F1F0 1F1F3 ; fully-qualified # ๐ฐ๐ณ flag: St. Kitts & Nevis +1F1F0 1F1F5 ; fully-qualified # ๐ฐ๐ต flag: North Korea +1F1F0 1F1F7 ; fully-qualified # ๐ฐ๐ท flag: South Korea +1F1F0 1F1FC ; fully-qualified # ๐ฐ๐ผ flag: Kuwait +1F1F0 1F1FE ; fully-qualified # ๐ฐ๐พ flag: Cayman Islands +1F1F0 1F1FF ; fully-qualified # ๐ฐ๐ฟ flag: Kazakhstan +1F1F1 1F1E6 ; fully-qualified # ๐ฑ๐ฆ flag: Laos +1F1F1 1F1E7 ; fully-qualified # ๐ฑ๐ง flag: Lebanon +1F1F1 1F1E8 ; fully-qualified # ๐ฑ๐จ flag: St. Lucia +1F1F1 1F1EE ; fully-qualified # ๐ฑ๐ฎ flag: Liechtenstein +1F1F1 1F1F0 ; fully-qualified # ๐ฑ๐ฐ flag: Sri Lanka +1F1F1 1F1F7 ; fully-qualified # ๐ฑ๐ท flag: Liberia +1F1F1 1F1F8 ; fully-qualified # ๐ฑ๐ธ flag: Lesotho +1F1F1 1F1F9 ; fully-qualified # ๐ฑ๐น flag: Lithuania +1F1F1 1F1FA ; fully-qualified # ๐ฑ๐บ flag: Luxembourg +1F1F1 1F1FB ; fully-qualified # ๐ฑ๐ป flag: Latvia +1F1F1 1F1FE ; fully-qualified # ๐ฑ๐พ flag: Libya +1F1F2 1F1E6 ; fully-qualified # ๐ฒ๐ฆ flag: Morocco +1F1F2 1F1E8 ; fully-qualified # ๐ฒ๐จ flag: Monaco +1F1F2 1F1E9 ; fully-qualified # ๐ฒ๐ฉ flag: Moldova +1F1F2 1F1EA ; fully-qualified # ๐ฒ๐ช flag: Montenegro +1F1F2 1F1EB ; fully-qualified # ๐ฒ๐ซ flag: St. Martin +1F1F2 1F1EC ; fully-qualified # ๐ฒ๐ฌ flag: Madagascar +1F1F2 1F1ED ; fully-qualified # ๐ฒ๐ญ flag: Marshall Islands +1F1F2 1F1F0 ; fully-qualified # ๐ฒ๐ฐ flag: Macedonia +1F1F2 1F1F1 ; fully-qualified # ๐ฒ๐ฑ flag: Mali +1F1F2 1F1F2 ; fully-qualified # ๐ฒ๐ฒ flag: Myanmar (Burma) +1F1F2 1F1F3 ; fully-qualified # ๐ฒ๐ณ flag: Mongolia +1F1F2 1F1F4 ; fully-qualified # ๐ฒ๐ด flag: Macau SAR China +1F1F2 1F1F5 ; fully-qualified # ๐ฒ๐ต flag: Northern Mariana Islands +1F1F2 1F1F6 ; fully-qualified # ๐ฒ๐ถ flag: Martinique +1F1F2 1F1F7 ; fully-qualified # ๐ฒ๐ท flag: Mauritania +1F1F2 1F1F8 ; fully-qualified # ๐ฒ๐ธ flag: Montserrat +1F1F2 1F1F9 ; fully-qualified # ๐ฒ๐น flag: Malta +1F1F2 1F1FA ; fully-qualified # ๐ฒ๐บ flag: Mauritius +1F1F2 1F1FB ; fully-qualified # ๐ฒ๐ป flag: Maldives +1F1F2 1F1FC ; fully-qualified # ๐ฒ๐ผ flag: Malawi +1F1F2 1F1FD ; fully-qualified # ๐ฒ๐ฝ flag: Mexico +1F1F2 1F1FE ; fully-qualified # ๐ฒ๐พ flag: Malaysia +1F1F2 1F1FF ; fully-qualified # ๐ฒ๐ฟ flag: Mozambique +1F1F3 1F1E6 ; fully-qualified # ๐ณ๐ฆ flag: Namibia +1F1F3 1F1E8 ; fully-qualified # ๐ณ๐จ flag: New Caledonia +1F1F3 1F1EA ; fully-qualified # ๐ณ๐ช flag: Niger +1F1F3 1F1EB ; fully-qualified # ๐ณ๐ซ flag: Norfolk Island +1F1F3 1F1EC ; fully-qualified # ๐ณ๐ฌ flag: Nigeria +1F1F3 1F1EE ; fully-qualified # ๐ณ๐ฎ flag: Nicaragua +1F1F3 1F1F1 ; fully-qualified # ๐ณ๐ฑ flag: Netherlands +1F1F3 1F1F4 ; fully-qualified # ๐ณ๐ด flag: Norway +1F1F3 1F1F5 ; fully-qualified # ๐ณ๐ต flag: Nepal +1F1F3 1F1F7 ; fully-qualified # ๐ณ๐ท flag: Nauru +1F1F3 1F1FA ; fully-qualified # ๐ณ๐บ flag: Niue +1F1F3 1F1FF ; fully-qualified # ๐ณ๐ฟ flag: New Zealand +1F1F4 1F1F2 ; fully-qualified # ๐ด๐ฒ flag: Oman +1F1F5 1F1E6 ; fully-qualified # ๐ต๐ฆ flag: Panama +1F1F5 1F1EA ; fully-qualified # ๐ต๐ช flag: Peru +1F1F5 1F1EB ; fully-qualified # ๐ต๐ซ flag: French Polynesia +1F1F5 1F1EC ; fully-qualified # ๐ต๐ฌ flag: Papua New Guinea +1F1F5 1F1ED ; fully-qualified # ๐ต๐ญ flag: Philippines +1F1F5 1F1F0 ; fully-qualified # ๐ต๐ฐ flag: Pakistan +1F1F5 1F1F1 ; fully-qualified # ๐ต๐ฑ flag: Poland +1F1F5 1F1F2 ; fully-qualified # ๐ต๐ฒ flag: St. Pierre & Miquelon +1F1F5 1F1F3 ; fully-qualified # ๐ต๐ณ flag: Pitcairn Islands +1F1F5 1F1F7 ; fully-qualified # ๐ต๐ท flag: Puerto Rico +1F1F5 1F1F8 ; fully-qualified # ๐ต๐ธ flag: Palestinian Territories +1F1F5 1F1F9 ; fully-qualified # ๐ต๐น flag: Portugal +1F1F5 1F1FC ; fully-qualified # ๐ต๐ผ flag: Palau +1F1F5 1F1FE ; fully-qualified # ๐ต๐พ flag: Paraguay +1F1F6 1F1E6 ; fully-qualified # ๐ถ๐ฆ flag: Qatar +1F1F7 1F1EA ; fully-qualified # ๐ท๐ช flag: Rรฉunion +1F1F7 1F1F4 ; fully-qualified # ๐ท๐ด flag: Romania +1F1F7 1F1F8 ; fully-qualified # ๐ท๐ธ flag: Serbia +1F1F7 1F1FA ; fully-qualified # ๐ท๐บ flag: Russia +1F1F7 1F1FC ; fully-qualified # ๐ท๐ผ flag: Rwanda +1F1F8 1F1E6 ; fully-qualified # ๐ธ๐ฆ flag: Saudi Arabia +1F1F8 1F1E7 ; fully-qualified # ๐ธ๐ง flag: Solomon Islands +1F1F8 1F1E8 ; fully-qualified # ๐ธ๐จ flag: Seychelles +1F1F8 1F1E9 ; fully-qualified # ๐ธ๐ฉ flag: Sudan +1F1F8 1F1EA ; fully-qualified # ๐ธ๐ช flag: Sweden +1F1F8 1F1EC ; fully-qualified # ๐ธ๐ฌ flag: Singapore +1F1F8 1F1ED ; fully-qualified # ๐ธ๐ญ flag: St. Helena +1F1F8 1F1EE ; fully-qualified # ๐ธ๐ฎ flag: Slovenia +1F1F8 1F1EF ; fully-qualified # ๐ธ๐ฏ flag: Svalbard & Jan Mayen +1F1F8 1F1F0 ; fully-qualified # ๐ธ๐ฐ flag: Slovakia +1F1F8 1F1F1 ; fully-qualified # ๐ธ๐ฑ flag: Sierra Leone +1F1F8 1F1F2 ; fully-qualified # ๐ธ๐ฒ flag: San Marino +1F1F8 1F1F3 ; fully-qualified # ๐ธ๐ณ flag: Senegal +1F1F8 1F1F4 ; fully-qualified # ๐ธ๐ด flag: Somalia +1F1F8 1F1F7 ; fully-qualified # ๐ธ๐ท flag: Suriname +1F1F8 1F1F8 ; fully-qualified # ๐ธ๐ธ flag: South Sudan +1F1F8 1F1F9 ; fully-qualified # ๐ธ๐น flag: Sรฃo Tomรฉ & Prรญncipe +1F1F8 1F1FB ; fully-qualified # ๐ธ๐ป flag: El Salvador +1F1F8 1F1FD ; fully-qualified # ๐ธ๐ฝ flag: Sint Maarten +1F1F8 1F1FE ; fully-qualified # ๐ธ๐พ flag: Syria +1F1F8 1F1FF ; fully-qualified # ๐ธ๐ฟ flag: Swaziland +1F1F9 1F1E6 ; fully-qualified # ๐น๐ฆ flag: Tristan da Cunha +1F1F9 1F1E8 ; fully-qualified # ๐น๐จ flag: Turks & Caicos Islands +1F1F9 1F1E9 ; fully-qualified # ๐น๐ฉ flag: Chad +1F1F9 1F1EB ; fully-qualified # ๐น๐ซ flag: French Southern Territories +1F1F9 1F1EC ; fully-qualified # ๐น๐ฌ flag: Togo +1F1F9 1F1ED ; fully-qualified # ๐น๐ญ flag: Thailand +1F1F9 1F1EF ; fully-qualified # ๐น๐ฏ flag: Tajikistan +1F1F9 1F1F0 ; fully-qualified # ๐น๐ฐ flag: Tokelau +1F1F9 1F1F1 ; fully-qualified # ๐น๐ฑ flag: Timor-Leste +1F1F9 1F1F2 ; fully-qualified # ๐น๐ฒ flag: Turkmenistan +1F1F9 1F1F3 ; fully-qualified # ๐น๐ณ flag: Tunisia +1F1F9 1F1F4 ; fully-qualified # ๐น๐ด flag: Tonga +1F1F9 1F1F7 ; fully-qualified # ๐น๐ท flag: Turkey +1F1F9 1F1F9 ; fully-qualified # ๐น๐น flag: Trinidad & Tobago +1F1F9 1F1FB ; fully-qualified # ๐น๐ป flag: Tuvalu +1F1F9 1F1FC ; fully-qualified # ๐น๐ผ flag: Taiwan +1F1F9 1F1FF ; fully-qualified # ๐น๐ฟ flag: Tanzania +1F1FA 1F1E6 ; fully-qualified # ๐บ๐ฆ flag: Ukraine +1F1FA 1F1EC ; fully-qualified # ๐บ๐ฌ flag: Uganda +1F1FA 1F1F2 ; fully-qualified # ๐บ๐ฒ flag: U.S. Outlying Islands +1F1FA 1F1F3 ; fully-qualified # ๐บ๐ณ flag: United Nations +1F1FA 1F1F8 ; fully-qualified # ๐บ๐ธ flag: United States +1F1FA 1F1FE ; fully-qualified # ๐บ๐พ flag: Uruguay +1F1FA 1F1FF ; fully-qualified # ๐บ๐ฟ flag: Uzbekistan +1F1FB 1F1E6 ; fully-qualified # ๐ป๐ฆ flag: Vatican City +1F1FB 1F1E8 ; fully-qualified # ๐ป๐จ flag: St. Vincent & Grenadines +1F1FB 1F1EA ; fully-qualified # ๐ป๐ช flag: Venezuela +1F1FB 1F1EC ; fully-qualified # ๐ป๐ฌ flag: British Virgin Islands +1F1FB 1F1EE ; fully-qualified # ๐ป๐ฎ flag: U.S. Virgin Islands +1F1FB 1F1F3 ; fully-qualified # ๐ป๐ณ flag: Vietnam +1F1FB 1F1FA ; fully-qualified # ๐ป๐บ flag: Vanuatu +1F1FC 1F1EB ; fully-qualified # ๐ผ๐ซ flag: Wallis & Futuna +1F1FC 1F1F8 ; fully-qualified # ๐ผ๐ธ flag: Samoa +1F1FD 1F1F0 ; fully-qualified # ๐ฝ๐ฐ flag: Kosovo +1F1FE 1F1EA ; fully-qualified # ๐พ๐ช flag: Yemen +1F1FE 1F1F9 ; fully-qualified # ๐พ๐น flag: Mayotte +1F1FF 1F1E6 ; fully-qualified # ๐ฟ๐ฆ flag: South Africa +1F1FF 1F1F2 ; fully-qualified # ๐ฟ๐ฒ flag: Zambia +1F1FF 1F1FC ; fully-qualified # ๐ฟ๐ผ flag: Zimbabwe # subgroup: subdivision-flag -1F3F4 E0067 E0062 E0065 E006E E0067 E007F ; fully-qualified # ๐ด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ England -1F3F4 E0067 E0062 E0073 E0063 E0074 E007F ; fully-qualified # ๐ด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ Scotland -1F3F4 E0067 E0062 E0077 E006C E0073 E007F ; fully-qualified # ๐ด๓ ง๓ ข๓ ท๓ ฌ๓ ณ๓ ฟ Wales +1F3F4 E0067 E0062 E0065 E006E E0067 E007F ; fully-qualified # ๐ด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ flag: England +1F3F4 E0067 E0062 E0073 E0063 E0074 E007F ; fully-qualified # ๐ด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ flag: Scotland +1F3F4 E0067 E0062 E0077 E006C E0073 E007F ; fully-qualified # ๐ด๓ ง๓ ข๓ ท๓ ฌ๓ ณ๓ ฟ flag: Wales -# Flags subtotal: 269 -# Flags subtotal: 269 w/o modifiers +# Flags subtotal: 271 +# Flags subtotal: 271 w/o modifiers #EOF |