aboutsummaryrefslogtreecommitdiffstats
path: root/tools/java/org
diff options
context:
space:
mode:
authorFredrik Roubert <roubert@google.com>2018-07-09 12:38:00 +0200
committerFredrik Roubert <roubert@google.com>2018-07-09 12:38:00 +0200
commit916131948aa91e4ad53c3f359daa1037518595b9 (patch)
treedfb69acf5fe0e20b1d79313ff3916d5092334a2f /tools/java/org
parent178614513228a6e8143bc010170f4f3a087f1e39 (diff)
parent1cc09cde2a712b3e802585d933d14fd5f7bd4860 (diff)
downloadandroid_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')
-rw-r--r--tools/java/org/unicode/cldr/draft/ScriptMetadata.java12
-rw-r--r--tools/java/org/unicode/cldr/test/CheckCLDR.java2
-rw-r--r--tools/java/org/unicode/cldr/test/CheckWidths.java63
-rw-r--r--tools/java/org/unicode/cldr/test/EmojiSubdivisionNames.java146
-rw-r--r--tools/java/org/unicode/cldr/test/ExampleGenerator.java384
-rw-r--r--tools/java/org/unicode/cldr/tool/CLDRModify.java8
-rw-r--r--tools/java/org/unicode/cldr/tool/ChartAnnotations.java12
-rw-r--r--tools/java/org/unicode/cldr/tool/GenerateMaximalLocales.java3
-rw-r--r--tools/java/org/unicode/cldr/tool/GetChanges.java114
-rw-r--r--tools/java/org/unicode/cldr/tool/ToolConstants.java3
-rw-r--r--tools/java/org/unicode/cldr/util/Annotations.java155
-rw-r--r--tools/java/org/unicode/cldr/util/CLDRConfig.java40
-rw-r--r--tools/java/org/unicode/cldr/util/CLDRFile.java2
-rw-r--r--tools/java/org/unicode/cldr/util/Emoji.java30
-rw-r--r--tools/java/org/unicode/cldr/util/EmojiConstants.java107
-rw-r--r--tools/java/org/unicode/cldr/util/LanguageGroup.java7
-rw-r--r--tools/java/org/unicode/cldr/util/PathHeader.java61
-rw-r--r--tools/java/org/unicode/cldr/util/XListFormatter.java82
-rw-r--r--tools/java/org/unicode/cldr/util/XMLSource.java2
-rw-r--r--tools/java/org/unicode/cldr/util/data/Script_Metadata.csv4
-rw-r--r--tools/java/org/unicode/cldr/util/data/emoji/emoji-test.txt1077
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