diff --git a/.github/workflows/gofuzz.yml b/.github/workflows/gofuzz.yml
index 3806ac5..ce1e51f 100644
--- a/.github/workflows/gofuzz.yml
+++ b/.github/workflows/gofuzz.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- fuzzer: [FuzzBytesAndString, FuzzRune, FuzzTruncateStringAndBytes, FuzzControlSequences]
+ fuzzer: [FuzzBytesAndString, FuzzRune, FuzzTruncateStringAndBytes, FuzzControlSequences, FuzzHasEligibleVS16Pair]
steps:
- name: Check out code
uses: actions/checkout@v6
diff --git a/README.md b/README.md
index ee3a149..00b2c2f 100644
--- a/README.md
+++ b/README.md
@@ -152,39 +152,39 @@ goarch: arm64
pkg: github.com/clipperhouse/displaywidth/comparison
cpu: Apple M2
-BenchmarkString_Mixed/clipperhouse/displaywidth-8 6326 ns/op 266.66 MB/s 0 B/op 0 allocs/op
-BenchmarkString_Mixed/mattn/go-runewidth-8 9984 ns/op 168.97 MB/s 0 B/op 0 allocs/op
-BenchmarkString_Mixed/rivo/uniseg-8 19602 ns/op 86.06 MB/s 0 B/op 0 allocs/op
+BenchmarkString_Mixed/clipperhouse/displaywidth-8 6085 ns/op 277.23 MB/s 0 B/op 0 allocs/op
+BenchmarkString_Mixed/mattn/go-runewidth-8 9970 ns/op 169.21 MB/s 0 B/op 0 allocs/op
+BenchmarkString_Mixed/rivo/uniseg-8 19060 ns/op 88.51 MB/s 0 B/op 0 allocs/op
-BenchmarkString_EastAsian/clipperhouse/displaywidth-8 6167 ns/op 273.55 MB/s 0 B/op 0 allocs/op
-BenchmarkString_EastAsian/mattn/go-runewidth-8 14022 ns/op 120.31 MB/s 0 B/op 0 allocs/op
-BenchmarkString_EastAsian/rivo/uniseg-8 19608 ns/op 86.04 MB/s 0 B/op 0 allocs/op
+BenchmarkString_EastAsian/clipperhouse/displaywidth-8 6118 ns/op 275.76 MB/s 0 B/op 0 allocs/op
+BenchmarkString_EastAsian/mattn/go-runewidth-8 13917 ns/op 121.22 MB/s 0 B/op 0 allocs/op
+BenchmarkString_EastAsian/rivo/uniseg-8 19263 ns/op 87.58 MB/s 0 B/op 0 allocs/op
-BenchmarkString_ASCII/clipperhouse/displaywidth-8 60.62 ns/op 2111.60 MB/s 0 B/op 0 allocs/op
-BenchmarkString_ASCII/mattn/go-runewidth-8 122.3 ns/op 1047.01 MB/s 0 B/op 0 allocs/op
-BenchmarkString_ASCII/rivo/uniseg-8 1490 ns/op 85.89 MB/s 0 B/op 0 allocs/op
+BenchmarkString_ASCII/clipperhouse/displaywidth-8 54.54 ns/op 2347.10 MB/s 0 B/op 0 allocs/op
+BenchmarkString_ASCII/mattn/go-runewidth-8 125.5 ns/op 1020.32 MB/s 0 B/op 0 allocs/op
+BenchmarkString_ASCII/rivo/uniseg-8 1478 ns/op 86.62 MB/s 0 B/op 0 allocs/op
-BenchmarkString_Emoji/clipperhouse/displaywidth-8 3313 ns/op 218.51 MB/s 0 B/op 0 allocs/op
-BenchmarkString_Emoji/mattn/go-runewidth-8 5009 ns/op 144.55 MB/s 0 B/op 0 allocs/op
-BenchmarkString_Emoji/rivo/uniseg-8 6868 ns/op 105.42 MB/s 0 B/op 0 allocs/op
+BenchmarkString_Emoji/clipperhouse/displaywidth-8 3265 ns/op 221.74 MB/s 0 B/op 0 allocs/op
+BenchmarkString_Emoji/mattn/go-runewidth-8 5110 ns/op 141.69 MB/s 0 B/op 0 allocs/op
+BenchmarkString_Emoji/rivo/uniseg-8 7137 ns/op 101.44 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_Mixed/clipperhouse/displaywidth-8 3430 ns/op 491.90 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_Mixed/mattn/go-runewidth-8 4833 ns/op 349.09 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_Mixed/clipperhouse/displaywidth-8 3517 ns/op 479.72 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_Mixed/mattn/go-runewidth-8 4746 ns/op 355.48 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_EastAsian/clipperhouse/displaywidth-8 3494 ns/op 482.77 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_EastAsian/mattn/go-runewidth-8 11724 ns/op 143.89 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_EastAsian/clipperhouse/displaywidth-8 3454 ns/op 488.36 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_EastAsian/mattn/go-runewidth-8 11432 ns/op 147.56 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_ASCII/clipperhouse/displaywidth-8 256.0 ns/op 500.02 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_ASCII/mattn/go-runewidth-8 265.0 ns/op 483.01 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_ASCII/clipperhouse/displaywidth-8 255.5 ns/op 500.88 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_ASCII/mattn/go-runewidth-8 264.7 ns/op 483.48 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_Emoji/clipperhouse/displaywidth-8 1381 ns/op 524.30 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_Emoji/mattn/go-runewidth-8 2345 ns/op 308.70 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_Emoji/clipperhouse/displaywidth-8 1320 ns/op 548.44 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_Emoji/mattn/go-runewidth-8 2286 ns/op 316.72 MB/s 0 B/op 0 allocs/op
-BenchmarkTruncateWithTail/clipperhouse/displaywidth-8 2755 ns/op 64.24 MB/s 192 B/op 14 allocs/op
-BenchmarkTruncateWithTail/mattn/go-runewidth-8 4683 ns/op 37.80 MB/s 192 B/op 14 allocs/op
+BenchmarkTruncateWithTail/clipperhouse/displaywidth-8 2495 ns/op 70.94 MB/s 192 B/op 14 allocs/op
+BenchmarkTruncateWithTail/mattn/go-runewidth-8 4569 ns/op 38.74 MB/s 192 B/op 14 allocs/op
-BenchmarkTruncateWithoutTail/clipperhouse/displaywidth-8 2481 ns/op 92.30 MB/s 0 B/op 0 allocs/op
-BenchmarkTruncateWithoutTail/mattn/go-runewidth-8 5334 ns/op 42.93 MB/s 0 B/op 0 allocs/op
+BenchmarkTruncateWithoutTail/clipperhouse/displaywidth-8 2456 ns/op 93.25 MB/s 0 B/op 0 allocs/op
+BenchmarkTruncateWithoutTail/mattn/go-runewidth-8 5182 ns/op 44.19 MB/s 0 B/op 0 allocs/op
```
Here are some notes on [how to make Unicode things fast](https://clipperhouse.com/go-unicode/).
diff --git a/comparison/README.md b/comparison/README.md
index 57e38b4..f1d33c0 100644
--- a/comparison/README.md
+++ b/comparison/README.md
@@ -19,37 +19,37 @@ goarch: arm64
pkg: github.com/clipperhouse/displaywidth/comparison
cpu: Apple M2
-BenchmarkString_Mixed/clipperhouse/displaywidth-8 6326 ns/op 266.66 MB/s 0 B/op 0 allocs/op
-BenchmarkString_Mixed/mattn/go-runewidth-8 9984 ns/op 168.97 MB/s 0 B/op 0 allocs/op
-BenchmarkString_Mixed/rivo/uniseg-8 19602 ns/op 86.06 MB/s 0 B/op 0 allocs/op
+BenchmarkString_Mixed/clipperhouse/displaywidth-8 6085 ns/op 277.23 MB/s 0 B/op 0 allocs/op
+BenchmarkString_Mixed/mattn/go-runewidth-8 9970 ns/op 169.21 MB/s 0 B/op 0 allocs/op
+BenchmarkString_Mixed/rivo/uniseg-8 19060 ns/op 88.51 MB/s 0 B/op 0 allocs/op
-BenchmarkString_EastAsian/clipperhouse/displaywidth-8 6167 ns/op 273.55 MB/s 0 B/op 0 allocs/op
-BenchmarkString_EastAsian/mattn/go-runewidth-8 14022 ns/op 120.31 MB/s 0 B/op 0 allocs/op
-BenchmarkString_EastAsian/rivo/uniseg-8 19608 ns/op 86.04 MB/s 0 B/op 0 allocs/op
+BenchmarkString_EastAsian/clipperhouse/displaywidth-8 6118 ns/op 275.76 MB/s 0 B/op 0 allocs/op
+BenchmarkString_EastAsian/mattn/go-runewidth-8 13917 ns/op 121.22 MB/s 0 B/op 0 allocs/op
+BenchmarkString_EastAsian/rivo/uniseg-8 19263 ns/op 87.58 MB/s 0 B/op 0 allocs/op
-BenchmarkString_ASCII/clipperhouse/displaywidth-8 60.62 ns/op 2111.60 MB/s 0 B/op 0 allocs/op
-BenchmarkString_ASCII/mattn/go-runewidth-8 122.3 ns/op 1047.01 MB/s 0 B/op 0 allocs/op
-BenchmarkString_ASCII/rivo/uniseg-8 1490 ns/op 85.89 MB/s 0 B/op 0 allocs/op
+BenchmarkString_ASCII/clipperhouse/displaywidth-8 54.54 ns/op 2347.10 MB/s 0 B/op 0 allocs/op
+BenchmarkString_ASCII/mattn/go-runewidth-8 125.5 ns/op 1020.32 MB/s 0 B/op 0 allocs/op
+BenchmarkString_ASCII/rivo/uniseg-8 1478 ns/op 86.62 MB/s 0 B/op 0 allocs/op
-BenchmarkString_Emoji/clipperhouse/displaywidth-8 3313 ns/op 218.51 MB/s 0 B/op 0 allocs/op
-BenchmarkString_Emoji/mattn/go-runewidth-8 5009 ns/op 144.55 MB/s 0 B/op 0 allocs/op
-BenchmarkString_Emoji/rivo/uniseg-8 6868 ns/op 105.42 MB/s 0 B/op 0 allocs/op
+BenchmarkString_Emoji/clipperhouse/displaywidth-8 3265 ns/op 221.74 MB/s 0 B/op 0 allocs/op
+BenchmarkString_Emoji/mattn/go-runewidth-8 5110 ns/op 141.69 MB/s 0 B/op 0 allocs/op
+BenchmarkString_Emoji/rivo/uniseg-8 7137 ns/op 101.44 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_Mixed/clipperhouse/displaywidth-8 3430 ns/op 491.90 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_Mixed/mattn/go-runewidth-8 4833 ns/op 349.09 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_Mixed/clipperhouse/displaywidth-8 3517 ns/op 479.72 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_Mixed/mattn/go-runewidth-8 4746 ns/op 355.48 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_EastAsian/clipperhouse/displaywidth-8 3494 ns/op 482.77 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_EastAsian/mattn/go-runewidth-8 11724 ns/op 143.89 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_EastAsian/clipperhouse/displaywidth-8 3454 ns/op 488.36 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_EastAsian/mattn/go-runewidth-8 11432 ns/op 147.56 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_ASCII/clipperhouse/displaywidth-8 256.0 ns/op 500.02 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_ASCII/mattn/go-runewidth-8 265.0 ns/op 483.01 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_ASCII/clipperhouse/displaywidth-8 255.5 ns/op 500.88 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_ASCII/mattn/go-runewidth-8 264.7 ns/op 483.48 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_Emoji/clipperhouse/displaywidth-8 1381 ns/op 524.30 MB/s 0 B/op 0 allocs/op
-BenchmarkRune_Emoji/mattn/go-runewidth-8 2345 ns/op 308.70 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_Emoji/clipperhouse/displaywidth-8 1320 ns/op 548.44 MB/s 0 B/op 0 allocs/op
+BenchmarkRune_Emoji/mattn/go-runewidth-8 2286 ns/op 316.72 MB/s 0 B/op 0 allocs/op
-BenchmarkTruncateWithTail/clipperhouse/displaywidth-8 2755 ns/op 64.24 MB/s 192 B/op 14 allocs/op
-BenchmarkTruncateWithTail/mattn/go-runewidth-8 4683 ns/op 37.80 MB/s 192 B/op 14 allocs/op
+BenchmarkTruncateWithTail/clipperhouse/displaywidth-8 2495 ns/op 70.94 MB/s 192 B/op 14 allocs/op
+BenchmarkTruncateWithTail/mattn/go-runewidth-8 4569 ns/op 38.74 MB/s 192 B/op 14 allocs/op
-BenchmarkTruncateWithoutTail/clipperhouse/displaywidth-8 2481 ns/op 92.30 MB/s 0 B/op 0 allocs/op
-BenchmarkTruncateWithoutTail/mattn/go-runewidth-8 5334 ns/op 42.93 MB/s 0 B/op 0 allocs/op
+BenchmarkTruncateWithoutTail/clipperhouse/displaywidth-8 2456 ns/op 93.25 MB/s 0 B/op 0 allocs/op
+BenchmarkTruncateWithoutTail/mattn/go-runewidth-8 5182 ns/op 44.19 MB/s 0 B/op 0 allocs/op
```
diff --git a/fuzz_test.go b/fuzz_test.go
index e076a3a..f9eebe6 100644
--- a/fuzz_test.go
+++ b/fuzz_test.go
@@ -443,3 +443,77 @@ func FuzzControlSequences(f *testing.F) {
}
})
}
+
+// FuzzHasEligibleVS16Pair fuzzes byte-level VS16 detection against
+// a slower UTF-8-decoding reference implementation.
+func FuzzHasEligibleVS16Pair(f *testing.F) {
+ if testing.Short() {
+ f.Skip("skipping fuzz test in short mode")
+ }
+
+ seeds := []string{
+ "",
+ "a",
+ "a\uFE0F", // invalid VS16 base
+ "✡\uFE0F", // valid immediate VS16 pair
+ "👩❤️👨", // later VS16 in ZWJ sequence
+ "\u26F9\U0001F3FB\u200D\u2642\uFE0F", // later VS16 in skin-tone+gender sequence
+ "\u26F9\u0301\uFE0E\u200D\u2660\uFE0F", // non-FE0F 0xEF (FE0E) before the real FE0F
+ "\u26F9\uFE20\u200D\u2660\uFE0F", // non-FE0F 0xEF (FE20) before the real FE0F
+ "\xff\xfe\xfd", // invalid UTF-8
+ }
+ for _, s := range seeds {
+ f.Add([]byte(s), uint16(0))
+ f.Add([]byte(s), uint16(1))
+ f.Add([]byte(s), uint16(7))
+ }
+
+ f.Fuzz(func(t *testing.T, text []byte, startSeed uint16) {
+ // Exercise a range that includes in-bounds and out-of-bounds starts.
+ start := int(startSeed)
+ if len(text) > 0 {
+ start %= (len(text) + 3)
+ }
+
+ gotBytes := hasEligibleVS16Pair(text, start)
+ gotString := hasEligibleVS16Pair(string(text), start)
+ if gotBytes != gotString {
+ t.Errorf("hasEligibleVS16Pair bytes/string mismatch for %q start=%d: %v != %v", text, start, gotBytes, gotString)
+ }
+
+ want := hasEligibleVS16PairReference(text, start)
+ if gotBytes != want {
+ t.Errorf("hasEligibleVS16Pair(%q, start=%d) = %v, want %v", text, start, gotBytes, want)
+ }
+ })
+}
+
+func hasEligibleVS16PairReference(b []byte, start int) bool {
+ if len(b) == 0 || start >= len(b) {
+ return false
+ }
+ if start < 0 {
+ start = 0
+ }
+
+ i := 0
+ prevStart := -1
+ for i < len(b) {
+ r, sz := utf8.DecodeRune(b[i:])
+ if sz <= 0 {
+ break
+ }
+
+ if i >= start && r == '\uFE0F' && prevStart >= 0 {
+ p, rsz := lookup(b[prevStart:])
+ if rsz > 0 && prevStart+rsz == i && property(p).is(_VS16_Eligible) {
+ return true
+ }
+ }
+
+ prevStart = i
+ i += sz
+ }
+
+ return false
+}
diff --git a/graphemes.go b/graphemes.go
index 14a5278..67c6244 100644
--- a/graphemes.go
+++ b/graphemes.go
@@ -8,7 +8,7 @@ import (
//
// Iterate using the Next method, and get the width of the current grapheme
// using the Width method.
-type Graphemes[T ~string | []byte] struct {
+type Graphemes[T ~string | ~[]byte] struct {
iter *graphemes.Iterator[T]
options Options
}
diff --git a/internal/gen/data/17.0.0/emoji-variation-sequences.txt b/internal/gen/data/17.0.0/emoji-variation-sequences.txt
new file mode 100644
index 0000000..8d999cf
--- /dev/null
+++ b/internal/gen/data/17.0.0/emoji-variation-sequences.txt
@@ -0,0 +1,757 @@
+# emoji-variation-sequences.txt
+# Date: 2025-01-30, 21:48:29 GMT
+# © 2025 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+# For terms of use and license, see https://www.unicode.org/terms_of_use.html
+#
+# Emoji Variation Sequences for UTS #51
+# Version: 17.0
+#
+# For documentation and usage, see https://www.unicode.org/reports/tr51
+#
+0023 FE0E ; text style; # (1.1) NUMBER SIGN
+0023 FE0F ; emoji style; # (1.1) NUMBER SIGN
+002A FE0E ; text style; # (1.1) ASTERISK
+002A FE0F ; emoji style; # (1.1) ASTERISK
+0030 FE0E ; text style; # (1.1) DIGIT ZERO
+0030 FE0F ; emoji style; # (1.1) DIGIT ZERO
+0031 FE0E ; text style; # (1.1) DIGIT ONE
+0031 FE0F ; emoji style; # (1.1) DIGIT ONE
+0032 FE0E ; text style; # (1.1) DIGIT TWO
+0032 FE0F ; emoji style; # (1.1) DIGIT TWO
+0033 FE0E ; text style; # (1.1) DIGIT THREE
+0033 FE0F ; emoji style; # (1.1) DIGIT THREE
+0034 FE0E ; text style; # (1.1) DIGIT FOUR
+0034 FE0F ; emoji style; # (1.1) DIGIT FOUR
+0035 FE0E ; text style; # (1.1) DIGIT FIVE
+0035 FE0F ; emoji style; # (1.1) DIGIT FIVE
+0036 FE0E ; text style; # (1.1) DIGIT SIX
+0036 FE0F ; emoji style; # (1.1) DIGIT SIX
+0037 FE0E ; text style; # (1.1) DIGIT SEVEN
+0037 FE0F ; emoji style; # (1.1) DIGIT SEVEN
+0038 FE0E ; text style; # (1.1) DIGIT EIGHT
+0038 FE0F ; emoji style; # (1.1) DIGIT EIGHT
+0039 FE0E ; text style; # (1.1) DIGIT NINE
+0039 FE0F ; emoji style; # (1.1) DIGIT NINE
+00A9 FE0E ; text style; # (1.1) COPYRIGHT SIGN
+00A9 FE0F ; emoji style; # (1.1) COPYRIGHT SIGN
+00AE FE0E ; text style; # (1.1) REGISTERED SIGN
+00AE FE0F ; emoji style; # (1.1) REGISTERED SIGN
+203C FE0E ; text style; # (1.1) DOUBLE EXCLAMATION MARK
+203C FE0F ; emoji style; # (1.1) DOUBLE EXCLAMATION MARK
+2049 FE0E ; text style; # (3.0) EXCLAMATION QUESTION MARK
+2049 FE0F ; emoji style; # (3.0) EXCLAMATION QUESTION MARK
+2122 FE0E ; text style; # (1.1) TRADE MARK SIGN
+2122 FE0F ; emoji style; # (1.1) TRADE MARK SIGN
+2139 FE0E ; text style; # (3.0) INFORMATION SOURCE
+2139 FE0F ; emoji style; # (3.0) INFORMATION SOURCE
+2194 FE0E ; text style; # (1.1) LEFT RIGHT ARROW
+2194 FE0F ; emoji style; # (1.1) LEFT RIGHT ARROW
+2195 FE0E ; text style; # (1.1) UP DOWN ARROW
+2195 FE0F ; emoji style; # (1.1) UP DOWN ARROW
+2196 FE0E ; text style; # (1.1) NORTH WEST ARROW
+2196 FE0F ; emoji style; # (1.1) NORTH WEST ARROW
+2197 FE0E ; text style; # (1.1) NORTH EAST ARROW
+2197 FE0F ; emoji style; # (1.1) NORTH EAST ARROW
+2198 FE0E ; text style; # (1.1) SOUTH EAST ARROW
+2198 FE0F ; emoji style; # (1.1) SOUTH EAST ARROW
+2199 FE0E ; text style; # (1.1) SOUTH WEST ARROW
+2199 FE0F ; emoji style; # (1.1) SOUTH WEST ARROW
+21A9 FE0E ; text style; # (1.1) LEFTWARDS ARROW WITH HOOK
+21A9 FE0F ; emoji style; # (1.1) LEFTWARDS ARROW WITH HOOK
+21AA FE0E ; text style; # (1.1) RIGHTWARDS ARROW WITH HOOK
+21AA FE0F ; emoji style; # (1.1) RIGHTWARDS ARROW WITH HOOK
+231A FE0E ; text style; # (1.1) WATCH
+231A FE0F ; emoji style; # (1.1) WATCH
+231B FE0E ; text style; # (1.1) HOURGLASS
+231B FE0F ; emoji style; # (1.1) HOURGLASS
+2328 FE0E ; text style; # (1.1) KEYBOARD
+2328 FE0F ; emoji style; # (1.1) KEYBOARD
+23CF FE0E ; text style; # (4.0) EJECT SYMBOL
+23CF FE0F ; emoji style; # (4.0) EJECT SYMBOL
+23E9 FE0E ; text style; # (6.0) BLACK RIGHT-POINTING DOUBLE TRIANGLE
+23E9 FE0F ; emoji style; # (6.0) BLACK RIGHT-POINTING DOUBLE TRIANGLE
+23EA FE0E ; text style; # (6.0) BLACK LEFT-POINTING DOUBLE TRIANGLE
+23EA FE0F ; emoji style; # (6.0) BLACK LEFT-POINTING DOUBLE TRIANGLE
+23EB FE0E ; text style; # (6.0) BLACK UP-POINTING DOUBLE TRIANGLE
+23EB FE0F ; emoji style; # (6.0) BLACK UP-POINTING DOUBLE TRIANGLE
+23EC FE0E ; text style; # (6.0) BLACK DOWN-POINTING DOUBLE TRIANGLE
+23EC FE0F ; emoji style; # (6.0) BLACK DOWN-POINTING DOUBLE TRIANGLE
+23ED FE0E ; text style; # (6.0) BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR
+23ED FE0F ; emoji style; # (6.0) BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR
+23EE FE0E ; text style; # (6.0) BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR
+23EE FE0F ; emoji style; # (6.0) BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR
+23EF FE0E ; text style; # (6.0) BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR
+23EF FE0F ; emoji style; # (6.0) BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR
+23F0 FE0E ; text style; # (6.0) ALARM CLOCK
+23F0 FE0F ; emoji style; # (6.0) ALARM CLOCK
+23F1 FE0E ; text style; # (6.0) STOPWATCH
+23F1 FE0F ; emoji style; # (6.0) STOPWATCH
+23F2 FE0E ; text style; # (6.0) TIMER CLOCK
+23F2 FE0F ; emoji style; # (6.0) TIMER CLOCK
+23F3 FE0E ; text style; # (6.0) HOURGLASS WITH FLOWING SAND
+23F3 FE0F ; emoji style; # (6.0) HOURGLASS WITH FLOWING SAND
+23F8 FE0E ; text style; # (7.0) DOUBLE VERTICAL BAR
+23F8 FE0F ; emoji style; # (7.0) DOUBLE VERTICAL BAR
+23F9 FE0E ; text style; # (7.0) BLACK SQUARE FOR STOP
+23F9 FE0F ; emoji style; # (7.0) BLACK SQUARE FOR STOP
+23FA FE0E ; text style; # (7.0) BLACK CIRCLE FOR RECORD
+23FA FE0F ; emoji style; # (7.0) BLACK CIRCLE FOR RECORD
+24C2 FE0E ; text style; # (1.1) CIRCLED LATIN CAPITAL LETTER M
+24C2 FE0F ; emoji style; # (1.1) CIRCLED LATIN CAPITAL LETTER M
+25AA FE0E ; text style; # (1.1) BLACK SMALL SQUARE
+25AA FE0F ; emoji style; # (1.1) BLACK SMALL SQUARE
+25AB FE0E ; text style; # (1.1) WHITE SMALL SQUARE
+25AB FE0F ; emoji style; # (1.1) WHITE SMALL SQUARE
+25B6 FE0E ; text style; # (1.1) BLACK RIGHT-POINTING TRIANGLE
+25B6 FE0F ; emoji style; # (1.1) BLACK RIGHT-POINTING TRIANGLE
+25C0 FE0E ; text style; # (1.1) BLACK LEFT-POINTING TRIANGLE
+25C0 FE0F ; emoji style; # (1.1) BLACK LEFT-POINTING TRIANGLE
+25FB FE0E ; text style; # (3.2) WHITE MEDIUM SQUARE
+25FB FE0F ; emoji style; # (3.2) WHITE MEDIUM SQUARE
+25FC FE0E ; text style; # (3.2) BLACK MEDIUM SQUARE
+25FC FE0F ; emoji style; # (3.2) BLACK MEDIUM SQUARE
+25FD FE0E ; text style; # (3.2) WHITE MEDIUM SMALL SQUARE
+25FD FE0F ; emoji style; # (3.2) WHITE MEDIUM SMALL SQUARE
+25FE FE0E ; text style; # (3.2) BLACK MEDIUM SMALL SQUARE
+25FE FE0F ; emoji style; # (3.2) BLACK MEDIUM SMALL SQUARE
+2600 FE0E ; text style; # (1.1) BLACK SUN WITH RAYS
+2600 FE0F ; emoji style; # (1.1) BLACK SUN WITH RAYS
+2601 FE0E ; text style; # (1.1) CLOUD
+2601 FE0F ; emoji style; # (1.1) CLOUD
+2602 FE0E ; text style; # (1.1) UMBRELLA
+2602 FE0F ; emoji style; # (1.1) UMBRELLA
+2603 FE0E ; text style; # (1.1) SNOWMAN
+2603 FE0F ; emoji style; # (1.1) SNOWMAN
+2604 FE0E ; text style; # (1.1) COMET
+2604 FE0F ; emoji style; # (1.1) COMET
+260E FE0E ; text style; # (1.1) BLACK TELEPHONE
+260E FE0F ; emoji style; # (1.1) BLACK TELEPHONE
+2611 FE0E ; text style; # (1.1) BALLOT BOX WITH CHECK
+2611 FE0F ; emoji style; # (1.1) BALLOT BOX WITH CHECK
+2614 FE0E ; text style; # (4.0) UMBRELLA WITH RAIN DROPS
+2614 FE0F ; emoji style; # (4.0) UMBRELLA WITH RAIN DROPS
+2615 FE0E ; text style; # (4.0) HOT BEVERAGE
+2615 FE0F ; emoji style; # (4.0) HOT BEVERAGE
+2618 FE0E ; text style; # (4.1) SHAMROCK
+2618 FE0F ; emoji style; # (4.1) SHAMROCK
+261D FE0E ; text style; # (1.1) WHITE UP POINTING INDEX
+261D FE0F ; emoji style; # (1.1) WHITE UP POINTING INDEX
+2620 FE0E ; text style; # (1.1) SKULL AND CROSSBONES
+2620 FE0F ; emoji style; # (1.1) SKULL AND CROSSBONES
+2622 FE0E ; text style; # (1.1) RADIOACTIVE SIGN
+2622 FE0F ; emoji style; # (1.1) RADIOACTIVE SIGN
+2623 FE0E ; text style; # (1.1) BIOHAZARD SIGN
+2623 FE0F ; emoji style; # (1.1) BIOHAZARD SIGN
+2626 FE0E ; text style; # (1.1) ORTHODOX CROSS
+2626 FE0F ; emoji style; # (1.1) ORTHODOX CROSS
+262A FE0E ; text style; # (1.1) STAR AND CRESCENT
+262A FE0F ; emoji style; # (1.1) STAR AND CRESCENT
+262E FE0E ; text style; # (1.1) PEACE SYMBOL
+262E FE0F ; emoji style; # (1.1) PEACE SYMBOL
+262F FE0E ; text style; # (1.1) YIN YANG
+262F FE0F ; emoji style; # (1.1) YIN YANG
+2638 FE0E ; text style; # (1.1) WHEEL OF DHARMA
+2638 FE0F ; emoji style; # (1.1) WHEEL OF DHARMA
+2639 FE0E ; text style; # (1.1) WHITE FROWNING FACE
+2639 FE0F ; emoji style; # (1.1) WHITE FROWNING FACE
+263A FE0E ; text style; # (1.1) WHITE SMILING FACE
+263A FE0F ; emoji style; # (1.1) WHITE SMILING FACE
+2640 FE0E ; text style; # (1.1) FEMALE SIGN
+2640 FE0F ; emoji style; # (1.1) FEMALE SIGN
+2642 FE0E ; text style; # (1.1) MALE SIGN
+2642 FE0F ; emoji style; # (1.1) MALE SIGN
+2648 FE0E ; text style; # (1.1) ARIES
+2648 FE0F ; emoji style; # (1.1) ARIES
+2649 FE0E ; text style; # (1.1) TAURUS
+2649 FE0F ; emoji style; # (1.1) TAURUS
+264A FE0E ; text style; # (1.1) GEMINI
+264A FE0F ; emoji style; # (1.1) GEMINI
+264B FE0E ; text style; # (1.1) CANCER
+264B FE0F ; emoji style; # (1.1) CANCER
+264C FE0E ; text style; # (1.1) LEO
+264C FE0F ; emoji style; # (1.1) LEO
+264D FE0E ; text style; # (1.1) VIRGO
+264D FE0F ; emoji style; # (1.1) VIRGO
+264E FE0E ; text style; # (1.1) LIBRA
+264E FE0F ; emoji style; # (1.1) LIBRA
+264F FE0E ; text style; # (1.1) SCORPIUS
+264F FE0F ; emoji style; # (1.1) SCORPIUS
+2650 FE0E ; text style; # (1.1) SAGITTARIUS
+2650 FE0F ; emoji style; # (1.1) SAGITTARIUS
+2651 FE0E ; text style; # (1.1) CAPRICORN
+2651 FE0F ; emoji style; # (1.1) CAPRICORN
+2652 FE0E ; text style; # (1.1) AQUARIUS
+2652 FE0F ; emoji style; # (1.1) AQUARIUS
+2653 FE0E ; text style; # (1.1) PISCES
+2653 FE0F ; emoji style; # (1.1) PISCES
+265F FE0E ; text style; # (1.1) BLACK CHESS PAWN
+265F FE0F ; emoji style; # (1.1) BLACK CHESS PAWN
+2660 FE0E ; text style; # (1.1) BLACK SPADE SUIT
+2660 FE0F ; emoji style; # (1.1) BLACK SPADE SUIT
+2663 FE0E ; text style; # (1.1) BLACK CLUB SUIT
+2663 FE0F ; emoji style; # (1.1) BLACK CLUB SUIT
+2665 FE0E ; text style; # (1.1) BLACK HEART SUIT
+2665 FE0F ; emoji style; # (1.1) BLACK HEART SUIT
+2666 FE0E ; text style; # (1.1) BLACK DIAMOND SUIT
+2666 FE0F ; emoji style; # (1.1) BLACK DIAMOND SUIT
+2668 FE0E ; text style; # (1.1) HOT SPRINGS
+2668 FE0F ; emoji style; # (1.1) HOT SPRINGS
+267B FE0E ; text style; # (3.2) BLACK UNIVERSAL RECYCLING SYMBOL
+267B FE0F ; emoji style; # (3.2) BLACK UNIVERSAL RECYCLING SYMBOL
+267E FE0E ; text style; # (4.1) PERMANENT PAPER SIGN
+267E FE0F ; emoji style; # (4.1) PERMANENT PAPER SIGN
+267F FE0E ; text style; # (4.1) WHEELCHAIR SYMBOL
+267F FE0F ; emoji style; # (4.1) WHEELCHAIR SYMBOL
+2692 FE0E ; text style; # (4.1) HAMMER AND PICK
+2692 FE0F ; emoji style; # (4.1) HAMMER AND PICK
+2693 FE0E ; text style; # (4.1) ANCHOR
+2693 FE0F ; emoji style; # (4.1) ANCHOR
+2694 FE0E ; text style; # (4.1) CROSSED SWORDS
+2694 FE0F ; emoji style; # (4.1) CROSSED SWORDS
+2695 FE0E ; text style; # (4.1) STAFF OF AESCULAPIUS
+2695 FE0F ; emoji style; # (4.1) STAFF OF AESCULAPIUS
+2696 FE0E ; text style; # (4.1) SCALES
+2696 FE0F ; emoji style; # (4.1) SCALES
+2697 FE0E ; text style; # (4.1) ALEMBIC
+2697 FE0F ; emoji style; # (4.1) ALEMBIC
+2699 FE0E ; text style; # (4.1) GEAR
+2699 FE0F ; emoji style; # (4.1) GEAR
+269B FE0E ; text style; # (4.1) ATOM SYMBOL
+269B FE0F ; emoji style; # (4.1) ATOM SYMBOL
+269C FE0E ; text style; # (4.1) FLEUR-DE-LIS
+269C FE0F ; emoji style; # (4.1) FLEUR-DE-LIS
+26A0 FE0E ; text style; # (4.0) WARNING SIGN
+26A0 FE0F ; emoji style; # (4.0) WARNING SIGN
+26A1 FE0E ; text style; # (4.0) HIGH VOLTAGE SIGN
+26A1 FE0F ; emoji style; # (4.0) HIGH VOLTAGE SIGN
+26A7 FE0E ; text style; # (4.1) MALE WITH STROKE AND MALE AND FEMALE SIGN
+26A7 FE0F ; emoji style; # (4.1) MALE WITH STROKE AND MALE AND FEMALE SIGN
+26AA FE0E ; text style; # (4.1) MEDIUM WHITE CIRCLE
+26AA FE0F ; emoji style; # (4.1) MEDIUM WHITE CIRCLE
+26AB FE0E ; text style; # (4.1) MEDIUM BLACK CIRCLE
+26AB FE0F ; emoji style; # (4.1) MEDIUM BLACK CIRCLE
+26B0 FE0E ; text style; # (4.1) COFFIN
+26B0 FE0F ; emoji style; # (4.1) COFFIN
+26B1 FE0E ; text style; # (4.1) FUNERAL URN
+26B1 FE0F ; emoji style; # (4.1) FUNERAL URN
+26BD FE0E ; text style; # (5.2) SOCCER BALL
+26BD FE0F ; emoji style; # (5.2) SOCCER BALL
+26BE FE0E ; text style; # (5.2) BASEBALL
+26BE FE0F ; emoji style; # (5.2) BASEBALL
+26C4 FE0E ; text style; # (5.2) SNOWMAN WITHOUT SNOW
+26C4 FE0F ; emoji style; # (5.2) SNOWMAN WITHOUT SNOW
+26C5 FE0E ; text style; # (5.2) SUN BEHIND CLOUD
+26C5 FE0F ; emoji style; # (5.2) SUN BEHIND CLOUD
+26C8 FE0E ; text style; # (5.2) THUNDER CLOUD AND RAIN
+26C8 FE0F ; emoji style; # (5.2) THUNDER CLOUD AND RAIN
+26CE FE0E ; text style; # (6.0) OPHIUCHUS
+26CE FE0F ; emoji style; # (6.0) OPHIUCHUS
+26CF FE0E ; text style; # (5.2) PICK
+26CF FE0F ; emoji style; # (5.2) PICK
+26D1 FE0E ; text style; # (5.2) HELMET WITH WHITE CROSS
+26D1 FE0F ; emoji style; # (5.2) HELMET WITH WHITE CROSS
+26D3 FE0E ; text style; # (5.2) CHAINS
+26D3 FE0F ; emoji style; # (5.2) CHAINS
+26D4 FE0E ; text style; # (5.2) NO ENTRY
+26D4 FE0F ; emoji style; # (5.2) NO ENTRY
+26E9 FE0E ; text style; # (5.2) SHINTO SHRINE
+26E9 FE0F ; emoji style; # (5.2) SHINTO SHRINE
+26EA FE0E ; text style; # (5.2) CHURCH
+26EA FE0F ; emoji style; # (5.2) CHURCH
+26F0 FE0E ; text style; # (5.2) MOUNTAIN
+26F0 FE0F ; emoji style; # (5.2) MOUNTAIN
+26F1 FE0E ; text style; # (5.2) UMBRELLA ON GROUND
+26F1 FE0F ; emoji style; # (5.2) UMBRELLA ON GROUND
+26F2 FE0E ; text style; # (5.2) FOUNTAIN
+26F2 FE0F ; emoji style; # (5.2) FOUNTAIN
+26F3 FE0E ; text style; # (5.2) FLAG IN HOLE
+26F3 FE0F ; emoji style; # (5.2) FLAG IN HOLE
+26F4 FE0E ; text style; # (5.2) FERRY
+26F4 FE0F ; emoji style; # (5.2) FERRY
+26F5 FE0E ; text style; # (5.2) SAILBOAT
+26F5 FE0F ; emoji style; # (5.2) SAILBOAT
+26F7 FE0E ; text style; # (5.2) SKIER
+26F7 FE0F ; emoji style; # (5.2) SKIER
+26F8 FE0E ; text style; # (5.2) ICE SKATE
+26F8 FE0F ; emoji style; # (5.2) ICE SKATE
+26F9 FE0E ; text style; # (5.2) PERSON WITH BALL
+26F9 FE0F ; emoji style; # (5.2) PERSON WITH BALL
+26FA FE0E ; text style; # (5.2) TENT
+26FA FE0F ; emoji style; # (5.2) TENT
+26FD FE0E ; text style; # (5.2) FUEL PUMP
+26FD FE0F ; emoji style; # (5.2) FUEL PUMP
+2702 FE0E ; text style; # (1.1) BLACK SCISSORS
+2702 FE0F ; emoji style; # (1.1) BLACK SCISSORS
+2705 FE0E ; text style; # (6.0) WHITE HEAVY CHECK MARK
+2705 FE0F ; emoji style; # (6.0) WHITE HEAVY CHECK MARK
+2708 FE0E ; text style; # (1.1) AIRPLANE
+2708 FE0F ; emoji style; # (1.1) AIRPLANE
+2709 FE0E ; text style; # (1.1) ENVELOPE
+2709 FE0F ; emoji style; # (1.1) ENVELOPE
+270A FE0E ; text style; # (6.0) RAISED FIST
+270A FE0F ; emoji style; # (6.0) RAISED FIST
+270B FE0E ; text style; # (6.0) RAISED HAND
+270B FE0F ; emoji style; # (6.0) RAISED HAND
+270C FE0E ; text style; # (1.1) VICTORY HAND
+270C FE0F ; emoji style; # (1.1) VICTORY HAND
+270D FE0E ; text style; # (1.1) WRITING HAND
+270D FE0F ; emoji style; # (1.1) WRITING HAND
+270F FE0E ; text style; # (1.1) PENCIL
+270F FE0F ; emoji style; # (1.1) PENCIL
+2712 FE0E ; text style; # (1.1) BLACK NIB
+2712 FE0F ; emoji style; # (1.1) BLACK NIB
+2714 FE0E ; text style; # (1.1) HEAVY CHECK MARK
+2714 FE0F ; emoji style; # (1.1) HEAVY CHECK MARK
+2716 FE0E ; text style; # (1.1) HEAVY MULTIPLICATION X
+2716 FE0F ; emoji style; # (1.1) HEAVY MULTIPLICATION X
+271D FE0E ; text style; # (1.1) LATIN CROSS
+271D FE0F ; emoji style; # (1.1) LATIN CROSS
+2721 FE0E ; text style; # (1.1) STAR OF DAVID
+2721 FE0F ; emoji style; # (1.1) STAR OF DAVID
+2728 FE0E ; text style; # (6.0) SPARKLES
+2728 FE0F ; emoji style; # (6.0) SPARKLES
+2733 FE0E ; text style; # (1.1) EIGHT SPOKED ASTERISK
+2733 FE0F ; emoji style; # (1.1) EIGHT SPOKED ASTERISK
+2734 FE0E ; text style; # (1.1) EIGHT POINTED BLACK STAR
+2734 FE0F ; emoji style; # (1.1) EIGHT POINTED BLACK STAR
+2744 FE0E ; text style; # (1.1) SNOWFLAKE
+2744 FE0F ; emoji style; # (1.1) SNOWFLAKE
+2747 FE0E ; text style; # (1.1) SPARKLE
+2747 FE0F ; emoji style; # (1.1) SPARKLE
+274C FE0E ; text style; # (6.0) CROSS MARK
+274C FE0F ; emoji style; # (6.0) CROSS MARK
+274E FE0E ; text style; # (6.0) NEGATIVE SQUARED CROSS MARK
+274E FE0F ; emoji style; # (6.0) NEGATIVE SQUARED CROSS MARK
+2753 FE0E ; text style; # (6.0) BLACK QUESTION MARK ORNAMENT
+2753 FE0F ; emoji style; # (6.0) BLACK QUESTION MARK ORNAMENT
+2754 FE0E ; text style; # (6.0) WHITE QUESTION MARK ORNAMENT
+2754 FE0F ; emoji style; # (6.0) WHITE QUESTION MARK ORNAMENT
+2755 FE0E ; text style; # (6.0) WHITE EXCLAMATION MARK ORNAMENT
+2755 FE0F ; emoji style; # (6.0) WHITE EXCLAMATION MARK ORNAMENT
+2757 FE0E ; text style; # (5.2) HEAVY EXCLAMATION MARK SYMBOL
+2757 FE0F ; emoji style; # (5.2) HEAVY EXCLAMATION MARK SYMBOL
+2763 FE0E ; text style; # (1.1) HEAVY HEART EXCLAMATION MARK ORNAMENT
+2763 FE0F ; emoji style; # (1.1) HEAVY HEART EXCLAMATION MARK ORNAMENT
+2764 FE0E ; text style; # (1.1) HEAVY BLACK HEART
+2764 FE0F ; emoji style; # (1.1) HEAVY BLACK HEART
+2795 FE0E ; text style; # (6.0) HEAVY PLUS SIGN
+2795 FE0F ; emoji style; # (6.0) HEAVY PLUS SIGN
+2796 FE0E ; text style; # (6.0) HEAVY MINUS SIGN
+2796 FE0F ; emoji style; # (6.0) HEAVY MINUS SIGN
+2797 FE0E ; text style; # (6.0) HEAVY DIVISION SIGN
+2797 FE0F ; emoji style; # (6.0) HEAVY DIVISION SIGN
+27A1 FE0E ; text style; # (1.1) BLACK RIGHTWARDS ARROW
+27A1 FE0F ; emoji style; # (1.1) BLACK RIGHTWARDS ARROW
+27B0 FE0E ; text style; # (6.0) CURLY LOOP
+27B0 FE0F ; emoji style; # (6.0) CURLY LOOP
+27BF FE0E ; text style; # (6.0) DOUBLE CURLY LOOP
+27BF FE0F ; emoji style; # (6.0) DOUBLE CURLY LOOP
+2934 FE0E ; text style; # (3.2) ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS
+2934 FE0F ; emoji style; # (3.2) ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS
+2935 FE0E ; text style; # (3.2) ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS
+2935 FE0F ; emoji style; # (3.2) ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS
+2B05 FE0E ; text style; # (4.0) LEFTWARDS BLACK ARROW
+2B05 FE0F ; emoji style; # (4.0) LEFTWARDS BLACK ARROW
+2B06 FE0E ; text style; # (4.0) UPWARDS BLACK ARROW
+2B06 FE0F ; emoji style; # (4.0) UPWARDS BLACK ARROW
+2B07 FE0E ; text style; # (4.0) DOWNWARDS BLACK ARROW
+2B07 FE0F ; emoji style; # (4.0) DOWNWARDS BLACK ARROW
+2B1B FE0E ; text style; # (5.1) BLACK LARGE SQUARE
+2B1B FE0F ; emoji style; # (5.1) BLACK LARGE SQUARE
+2B1C FE0E ; text style; # (5.1) WHITE LARGE SQUARE
+2B1C FE0F ; emoji style; # (5.1) WHITE LARGE SQUARE
+2B50 FE0E ; text style; # (5.1) WHITE MEDIUM STAR
+2B50 FE0F ; emoji style; # (5.1) WHITE MEDIUM STAR
+2B55 FE0E ; text style; # (5.2) HEAVY LARGE CIRCLE
+2B55 FE0F ; emoji style; # (5.2) HEAVY LARGE CIRCLE
+3030 FE0E ; text style; # (1.1) WAVY DASH
+3030 FE0F ; emoji style; # (1.1) WAVY DASH
+303D FE0E ; text style; # (3.2) PART ALTERNATION MARK
+303D FE0F ; emoji style; # (3.2) PART ALTERNATION MARK
+3297 FE0E ; text style; # (1.1) CIRCLED IDEOGRAPH CONGRATULATION
+3297 FE0F ; emoji style; # (1.1) CIRCLED IDEOGRAPH CONGRATULATION
+3299 FE0E ; text style; # (1.1) CIRCLED IDEOGRAPH SECRET
+3299 FE0F ; emoji style; # (1.1) CIRCLED IDEOGRAPH SECRET
+1F004 FE0E ; text style; # (5.1) MAHJONG TILE RED DRAGON
+1F004 FE0F ; emoji style; # (5.1) MAHJONG TILE RED DRAGON
+1F170 FE0E ; text style; # (6.0) NEGATIVE SQUARED LATIN CAPITAL LETTER A
+1F170 FE0F ; emoji style; # (6.0) NEGATIVE SQUARED LATIN CAPITAL LETTER A
+1F171 FE0E ; text style; # (6.0) NEGATIVE SQUARED LATIN CAPITAL LETTER B
+1F171 FE0F ; emoji style; # (6.0) NEGATIVE SQUARED LATIN CAPITAL LETTER B
+1F17E FE0E ; text style; # (6.0) NEGATIVE SQUARED LATIN CAPITAL LETTER O
+1F17E FE0F ; emoji style; # (6.0) NEGATIVE SQUARED LATIN CAPITAL LETTER O
+1F17F FE0E ; text style; # (5.2) NEGATIVE SQUARED LATIN CAPITAL LETTER P
+1F17F FE0F ; emoji style; # (5.2) NEGATIVE SQUARED LATIN CAPITAL LETTER P
+1F202 FE0E ; text style; # (6.0) SQUARED KATAKANA SA
+1F202 FE0F ; emoji style; # (6.0) SQUARED KATAKANA SA
+1F21A FE0E ; text style; # (5.2) SQUARED CJK UNIFIED IDEOGRAPH-7121
+1F21A FE0F ; emoji style; # (5.2) SQUARED CJK UNIFIED IDEOGRAPH-7121
+1F22F FE0E ; text style; # (5.2) SQUARED CJK UNIFIED IDEOGRAPH-6307
+1F22F FE0F ; emoji style; # (5.2) SQUARED CJK UNIFIED IDEOGRAPH-6307
+1F237 FE0E ; text style; # (6.0) SQUARED CJK UNIFIED IDEOGRAPH-6708
+1F237 FE0F ; emoji style; # (6.0) SQUARED CJK UNIFIED IDEOGRAPH-6708
+1F30D FE0E ; text style; # (6.0) EARTH GLOBE EUROPE-AFRICA
+1F30D FE0F ; emoji style; # (6.0) EARTH GLOBE EUROPE-AFRICA
+1F30E FE0E ; text style; # (6.0) EARTH GLOBE AMERICAS
+1F30E FE0F ; emoji style; # (6.0) EARTH GLOBE AMERICAS
+1F30F FE0E ; text style; # (6.0) EARTH GLOBE ASIA-AUSTRALIA
+1F30F FE0F ; emoji style; # (6.0) EARTH GLOBE ASIA-AUSTRALIA
+1F315 FE0E ; text style; # (6.0) FULL MOON SYMBOL
+1F315 FE0F ; emoji style; # (6.0) FULL MOON SYMBOL
+1F31C FE0E ; text style; # (6.0) LAST QUARTER MOON WITH FACE
+1F31C FE0F ; emoji style; # (6.0) LAST QUARTER MOON WITH FACE
+1F321 FE0E ; text style; # (7.0) THERMOMETER
+1F321 FE0F ; emoji style; # (7.0) THERMOMETER
+1F324 FE0E ; text style; # (7.0) WHITE SUN WITH SMALL CLOUD
+1F324 FE0F ; emoji style; # (7.0) WHITE SUN WITH SMALL CLOUD
+1F325 FE0E ; text style; # (7.0) WHITE SUN BEHIND CLOUD
+1F325 FE0F ; emoji style; # (7.0) WHITE SUN BEHIND CLOUD
+1F326 FE0E ; text style; # (7.0) WHITE SUN BEHIND CLOUD WITH RAIN
+1F326 FE0F ; emoji style; # (7.0) WHITE SUN BEHIND CLOUD WITH RAIN
+1F327 FE0E ; text style; # (7.0) CLOUD WITH RAIN
+1F327 FE0F ; emoji style; # (7.0) CLOUD WITH RAIN
+1F328 FE0E ; text style; # (7.0) CLOUD WITH SNOW
+1F328 FE0F ; emoji style; # (7.0) CLOUD WITH SNOW
+1F329 FE0E ; text style; # (7.0) CLOUD WITH LIGHTNING
+1F329 FE0F ; emoji style; # (7.0) CLOUD WITH LIGHTNING
+1F32A FE0E ; text style; # (7.0) CLOUD WITH TORNADO
+1F32A FE0F ; emoji style; # (7.0) CLOUD WITH TORNADO
+1F32B FE0E ; text style; # (7.0) FOG
+1F32B FE0F ; emoji style; # (7.0) FOG
+1F32C FE0E ; text style; # (7.0) WIND BLOWING FACE
+1F32C FE0F ; emoji style; # (7.0) WIND BLOWING FACE
+1F336 FE0E ; text style; # (7.0) HOT PEPPER
+1F336 FE0F ; emoji style; # (7.0) HOT PEPPER
+1F378 FE0E ; text style; # (6.0) COCKTAIL GLASS
+1F378 FE0F ; emoji style; # (6.0) COCKTAIL GLASS
+1F37D FE0E ; text style; # (7.0) FORK AND KNIFE WITH PLATE
+1F37D FE0F ; emoji style; # (7.0) FORK AND KNIFE WITH PLATE
+1F393 FE0E ; text style; # (6.0) GRADUATION CAP
+1F393 FE0F ; emoji style; # (6.0) GRADUATION CAP
+1F396 FE0E ; text style; # (7.0) MILITARY MEDAL
+1F396 FE0F ; emoji style; # (7.0) MILITARY MEDAL
+1F397 FE0E ; text style; # (7.0) REMINDER RIBBON
+1F397 FE0F ; emoji style; # (7.0) REMINDER RIBBON
+1F399 FE0E ; text style; # (7.0) STUDIO MICROPHONE
+1F399 FE0F ; emoji style; # (7.0) STUDIO MICROPHONE
+1F39A FE0E ; text style; # (7.0) LEVEL SLIDER
+1F39A FE0F ; emoji style; # (7.0) LEVEL SLIDER
+1F39B FE0E ; text style; # (7.0) CONTROL KNOBS
+1F39B FE0F ; emoji style; # (7.0) CONTROL KNOBS
+1F39E FE0E ; text style; # (7.0) FILM FRAMES
+1F39E FE0F ; emoji style; # (7.0) FILM FRAMES
+1F39F FE0E ; text style; # (7.0) ADMISSION TICKETS
+1F39F FE0F ; emoji style; # (7.0) ADMISSION TICKETS
+1F3A7 FE0E ; text style; # (6.0) HEADPHONE
+1F3A7 FE0F ; emoji style; # (6.0) HEADPHONE
+1F3AC FE0E ; text style; # (6.0) CLAPPER BOARD
+1F3AC FE0F ; emoji style; # (6.0) CLAPPER BOARD
+1F3AD FE0E ; text style; # (6.0) PERFORMING ARTS
+1F3AD FE0F ; emoji style; # (6.0) PERFORMING ARTS
+1F3AE FE0E ; text style; # (6.0) VIDEO GAME
+1F3AE FE0F ; emoji style; # (6.0) VIDEO GAME
+1F3C2 FE0E ; text style; # (6.0) SNOWBOARDER
+1F3C2 FE0F ; emoji style; # (6.0) SNOWBOARDER
+1F3C4 FE0E ; text style; # (6.0) SURFER
+1F3C4 FE0F ; emoji style; # (6.0) SURFER
+1F3C6 FE0E ; text style; # (6.0) TROPHY
+1F3C6 FE0F ; emoji style; # (6.0) TROPHY
+1F3CA FE0E ; text style; # (6.0) SWIMMER
+1F3CA FE0F ; emoji style; # (6.0) SWIMMER
+1F3CB FE0E ; text style; # (7.0) WEIGHT LIFTER
+1F3CB FE0F ; emoji style; # (7.0) WEIGHT LIFTER
+1F3CC FE0E ; text style; # (7.0) GOLFER
+1F3CC FE0F ; emoji style; # (7.0) GOLFER
+1F3CD FE0E ; text style; # (7.0) RACING MOTORCYCLE
+1F3CD FE0F ; emoji style; # (7.0) RACING MOTORCYCLE
+1F3CE FE0E ; text style; # (7.0) RACING CAR
+1F3CE FE0F ; emoji style; # (7.0) RACING CAR
+1F3D4 FE0E ; text style; # (7.0) SNOW CAPPED MOUNTAIN
+1F3D4 FE0F ; emoji style; # (7.0) SNOW CAPPED MOUNTAIN
+1F3D5 FE0E ; text style; # (7.0) CAMPING
+1F3D5 FE0F ; emoji style; # (7.0) CAMPING
+1F3D6 FE0E ; text style; # (7.0) BEACH WITH UMBRELLA
+1F3D6 FE0F ; emoji style; # (7.0) BEACH WITH UMBRELLA
+1F3D7 FE0E ; text style; # (7.0) BUILDING CONSTRUCTION
+1F3D7 FE0F ; emoji style; # (7.0) BUILDING CONSTRUCTION
+1F3D8 FE0E ; text style; # (7.0) HOUSE BUILDINGS
+1F3D8 FE0F ; emoji style; # (7.0) HOUSE BUILDINGS
+1F3D9 FE0E ; text style; # (7.0) CITYSCAPE
+1F3D9 FE0F ; emoji style; # (7.0) CITYSCAPE
+1F3DA FE0E ; text style; # (7.0) DERELICT HOUSE BUILDING
+1F3DA FE0F ; emoji style; # (7.0) DERELICT HOUSE BUILDING
+1F3DB FE0E ; text style; # (7.0) CLASSICAL BUILDING
+1F3DB FE0F ; emoji style; # (7.0) CLASSICAL BUILDING
+1F3DC FE0E ; text style; # (7.0) DESERT
+1F3DC FE0F ; emoji style; # (7.0) DESERT
+1F3DD FE0E ; text style; # (7.0) DESERT ISLAND
+1F3DD FE0F ; emoji style; # (7.0) DESERT ISLAND
+1F3DE FE0E ; text style; # (7.0) NATIONAL PARK
+1F3DE FE0F ; emoji style; # (7.0) NATIONAL PARK
+1F3DF FE0E ; text style; # (7.0) STADIUM
+1F3DF FE0F ; emoji style; # (7.0) STADIUM
+1F3E0 FE0E ; text style; # (6.0) HOUSE BUILDING
+1F3E0 FE0F ; emoji style; # (6.0) HOUSE BUILDING
+1F3ED FE0E ; text style; # (6.0) FACTORY
+1F3ED FE0F ; emoji style; # (6.0) FACTORY
+1F3F3 FE0E ; text style; # (7.0) WAVING WHITE FLAG
+1F3F3 FE0F ; emoji style; # (7.0) WAVING WHITE FLAG
+1F3F5 FE0E ; text style; # (7.0) ROSETTE
+1F3F5 FE0F ; emoji style; # (7.0) ROSETTE
+1F3F7 FE0E ; text style; # (7.0) LABEL
+1F3F7 FE0F ; emoji style; # (7.0) LABEL
+1F408 FE0E ; text style; # (6.0) CAT
+1F408 FE0F ; emoji style; # (6.0) CAT
+1F415 FE0E ; text style; # (6.0) DOG
+1F415 FE0F ; emoji style; # (6.0) DOG
+1F41F FE0E ; text style; # (6.0) FISH
+1F41F FE0F ; emoji style; # (6.0) FISH
+1F426 FE0E ; text style; # (6.0) BIRD
+1F426 FE0F ; emoji style; # (6.0) BIRD
+1F43F FE0E ; text style; # (7.0) CHIPMUNK
+1F43F FE0F ; emoji style; # (7.0) CHIPMUNK
+1F441 FE0E ; text style; # (7.0) EYE
+1F441 FE0F ; emoji style; # (7.0) EYE
+1F442 FE0E ; text style; # (6.0) EAR
+1F442 FE0F ; emoji style; # (6.0) EAR
+1F446 FE0E ; text style; # (6.0) WHITE UP POINTING BACKHAND INDEX
+1F446 FE0F ; emoji style; # (6.0) WHITE UP POINTING BACKHAND INDEX
+1F447 FE0E ; text style; # (6.0) WHITE DOWN POINTING BACKHAND INDEX
+1F447 FE0F ; emoji style; # (6.0) WHITE DOWN POINTING BACKHAND INDEX
+1F448 FE0E ; text style; # (6.0) WHITE LEFT POINTING BACKHAND INDEX
+1F448 FE0F ; emoji style; # (6.0) WHITE LEFT POINTING BACKHAND INDEX
+1F449 FE0E ; text style; # (6.0) WHITE RIGHT POINTING BACKHAND INDEX
+1F449 FE0F ; emoji style; # (6.0) WHITE RIGHT POINTING BACKHAND INDEX
+1F44D FE0E ; text style; # (6.0) THUMBS UP SIGN
+1F44D FE0F ; emoji style; # (6.0) THUMBS UP SIGN
+1F44E FE0E ; text style; # (6.0) THUMBS DOWN SIGN
+1F44E FE0F ; emoji style; # (6.0) THUMBS DOWN SIGN
+1F453 FE0E ; text style; # (6.0) EYEGLASSES
+1F453 FE0F ; emoji style; # (6.0) EYEGLASSES
+1F46A FE0E ; text style; # (6.0) FAMILY
+1F46A FE0F ; emoji style; # (6.0) FAMILY
+1F47D FE0E ; text style; # (6.0) EXTRATERRESTRIAL ALIEN
+1F47D FE0F ; emoji style; # (6.0) EXTRATERRESTRIAL ALIEN
+1F4A3 FE0E ; text style; # (6.0) BOMB
+1F4A3 FE0F ; emoji style; # (6.0) BOMB
+1F4B0 FE0E ; text style; # (6.0) MONEY BAG
+1F4B0 FE0F ; emoji style; # (6.0) MONEY BAG
+1F4B3 FE0E ; text style; # (6.0) CREDIT CARD
+1F4B3 FE0F ; emoji style; # (6.0) CREDIT CARD
+1F4BB FE0E ; text style; # (6.0) PERSONAL COMPUTER
+1F4BB FE0F ; emoji style; # (6.0) PERSONAL COMPUTER
+1F4BF FE0E ; text style; # (6.0) OPTICAL DISC
+1F4BF FE0F ; emoji style; # (6.0) OPTICAL DISC
+1F4CB FE0E ; text style; # (6.0) CLIPBOARD
+1F4CB FE0F ; emoji style; # (6.0) CLIPBOARD
+1F4DA FE0E ; text style; # (6.0) BOOKS
+1F4DA FE0F ; emoji style; # (6.0) BOOKS
+1F4DF FE0E ; text style; # (6.0) PAGER
+1F4DF FE0F ; emoji style; # (6.0) PAGER
+1F4E4 FE0E ; text style; # (6.0) OUTBOX TRAY
+1F4E4 FE0F ; emoji style; # (6.0) OUTBOX TRAY
+1F4E5 FE0E ; text style; # (6.0) INBOX TRAY
+1F4E5 FE0F ; emoji style; # (6.0) INBOX TRAY
+1F4E6 FE0E ; text style; # (6.0) PACKAGE
+1F4E6 FE0F ; emoji style; # (6.0) PACKAGE
+1F4EA FE0E ; text style; # (6.0) CLOSED MAILBOX WITH LOWERED FLAG
+1F4EA FE0F ; emoji style; # (6.0) CLOSED MAILBOX WITH LOWERED FLAG
+1F4EB FE0E ; text style; # (6.0) CLOSED MAILBOX WITH RAISED FLAG
+1F4EB FE0F ; emoji style; # (6.0) CLOSED MAILBOX WITH RAISED FLAG
+1F4EC FE0E ; text style; # (6.0) OPEN MAILBOX WITH RAISED FLAG
+1F4EC FE0F ; emoji style; # (6.0) OPEN MAILBOX WITH RAISED FLAG
+1F4ED FE0E ; text style; # (6.0) OPEN MAILBOX WITH LOWERED FLAG
+1F4ED FE0F ; emoji style; # (6.0) OPEN MAILBOX WITH LOWERED FLAG
+1F4F7 FE0E ; text style; # (6.0) CAMERA
+1F4F7 FE0F ; emoji style; # (6.0) CAMERA
+1F4F9 FE0E ; text style; # (6.0) VIDEO CAMERA
+1F4F9 FE0F ; emoji style; # (6.0) VIDEO CAMERA
+1F4FA FE0E ; text style; # (6.0) TELEVISION
+1F4FA FE0F ; emoji style; # (6.0) TELEVISION
+1F4FB FE0E ; text style; # (6.0) RADIO
+1F4FB FE0F ; emoji style; # (6.0) RADIO
+1F4FD FE0E ; text style; # (7.0) FILM PROJECTOR
+1F4FD FE0F ; emoji style; # (7.0) FILM PROJECTOR
+1F508 FE0E ; text style; # (6.0) SPEAKER
+1F508 FE0F ; emoji style; # (6.0) SPEAKER
+1F50D FE0E ; text style; # (6.0) LEFT-POINTING MAGNIFYING GLASS
+1F50D FE0F ; emoji style; # (6.0) LEFT-POINTING MAGNIFYING GLASS
+1F512 FE0E ; text style; # (6.0) LOCK
+1F512 FE0F ; emoji style; # (6.0) LOCK
+1F513 FE0E ; text style; # (6.0) OPEN LOCK
+1F513 FE0F ; emoji style; # (6.0) OPEN LOCK
+1F549 FE0E ; text style; # (7.0) OM SYMBOL
+1F549 FE0F ; emoji style; # (7.0) OM SYMBOL
+1F54A FE0E ; text style; # (7.0) DOVE OF PEACE
+1F54A FE0F ; emoji style; # (7.0) DOVE OF PEACE
+1F550 FE0E ; text style; # (6.0) CLOCK FACE ONE OCLOCK
+1F550 FE0F ; emoji style; # (6.0) CLOCK FACE ONE OCLOCK
+1F551 FE0E ; text style; # (6.0) CLOCK FACE TWO OCLOCK
+1F551 FE0F ; emoji style; # (6.0) CLOCK FACE TWO OCLOCK
+1F552 FE0E ; text style; # (6.0) CLOCK FACE THREE OCLOCK
+1F552 FE0F ; emoji style; # (6.0) CLOCK FACE THREE OCLOCK
+1F553 FE0E ; text style; # (6.0) CLOCK FACE FOUR OCLOCK
+1F553 FE0F ; emoji style; # (6.0) CLOCK FACE FOUR OCLOCK
+1F554 FE0E ; text style; # (6.0) CLOCK FACE FIVE OCLOCK
+1F554 FE0F ; emoji style; # (6.0) CLOCK FACE FIVE OCLOCK
+1F555 FE0E ; text style; # (6.0) CLOCK FACE SIX OCLOCK
+1F555 FE0F ; emoji style; # (6.0) CLOCK FACE SIX OCLOCK
+1F556 FE0E ; text style; # (6.0) CLOCK FACE SEVEN OCLOCK
+1F556 FE0F ; emoji style; # (6.0) CLOCK FACE SEVEN OCLOCK
+1F557 FE0E ; text style; # (6.0) CLOCK FACE EIGHT OCLOCK
+1F557 FE0F ; emoji style; # (6.0) CLOCK FACE EIGHT OCLOCK
+1F558 FE0E ; text style; # (6.0) CLOCK FACE NINE OCLOCK
+1F558 FE0F ; emoji style; # (6.0) CLOCK FACE NINE OCLOCK
+1F559 FE0E ; text style; # (6.0) CLOCK FACE TEN OCLOCK
+1F559 FE0F ; emoji style; # (6.0) CLOCK FACE TEN OCLOCK
+1F55A FE0E ; text style; # (6.0) CLOCK FACE ELEVEN OCLOCK
+1F55A FE0F ; emoji style; # (6.0) CLOCK FACE ELEVEN OCLOCK
+1F55B FE0E ; text style; # (6.0) CLOCK FACE TWELVE OCLOCK
+1F55B FE0F ; emoji style; # (6.0) CLOCK FACE TWELVE OCLOCK
+1F55C FE0E ; text style; # (6.0) CLOCK FACE ONE-THIRTY
+1F55C FE0F ; emoji style; # (6.0) CLOCK FACE ONE-THIRTY
+1F55D FE0E ; text style; # (6.0) CLOCK FACE TWO-THIRTY
+1F55D FE0F ; emoji style; # (6.0) CLOCK FACE TWO-THIRTY
+1F55E FE0E ; text style; # (6.0) CLOCK FACE THREE-THIRTY
+1F55E FE0F ; emoji style; # (6.0) CLOCK FACE THREE-THIRTY
+1F55F FE0E ; text style; # (6.0) CLOCK FACE FOUR-THIRTY
+1F55F FE0F ; emoji style; # (6.0) CLOCK FACE FOUR-THIRTY
+1F560 FE0E ; text style; # (6.0) CLOCK FACE FIVE-THIRTY
+1F560 FE0F ; emoji style; # (6.0) CLOCK FACE FIVE-THIRTY
+1F561 FE0E ; text style; # (6.0) CLOCK FACE SIX-THIRTY
+1F561 FE0F ; emoji style; # (6.0) CLOCK FACE SIX-THIRTY
+1F562 FE0E ; text style; # (6.0) CLOCK FACE SEVEN-THIRTY
+1F562 FE0F ; emoji style; # (6.0) CLOCK FACE SEVEN-THIRTY
+1F563 FE0E ; text style; # (6.0) CLOCK FACE EIGHT-THIRTY
+1F563 FE0F ; emoji style; # (6.0) CLOCK FACE EIGHT-THIRTY
+1F564 FE0E ; text style; # (6.0) CLOCK FACE NINE-THIRTY
+1F564 FE0F ; emoji style; # (6.0) CLOCK FACE NINE-THIRTY
+1F565 FE0E ; text style; # (6.0) CLOCK FACE TEN-THIRTY
+1F565 FE0F ; emoji style; # (6.0) CLOCK FACE TEN-THIRTY
+1F566 FE0E ; text style; # (6.0) CLOCK FACE ELEVEN-THIRTY
+1F566 FE0F ; emoji style; # (6.0) CLOCK FACE ELEVEN-THIRTY
+1F567 FE0E ; text style; # (6.0) CLOCK FACE TWELVE-THIRTY
+1F567 FE0F ; emoji style; # (6.0) CLOCK FACE TWELVE-THIRTY
+1F56F FE0E ; text style; # (7.0) CANDLE
+1F56F FE0F ; emoji style; # (7.0) CANDLE
+1F570 FE0E ; text style; # (7.0) MANTELPIECE CLOCK
+1F570 FE0F ; emoji style; # (7.0) MANTELPIECE CLOCK
+1F573 FE0E ; text style; # (7.0) HOLE
+1F573 FE0F ; emoji style; # (7.0) HOLE
+1F574 FE0E ; text style; # (7.0) MAN IN BUSINESS SUIT LEVITATING
+1F574 FE0F ; emoji style; # (7.0) MAN IN BUSINESS SUIT LEVITATING
+1F575 FE0E ; text style; # (7.0) SLEUTH OR SPY
+1F575 FE0F ; emoji style; # (7.0) SLEUTH OR SPY
+1F576 FE0E ; text style; # (7.0) DARK SUNGLASSES
+1F576 FE0F ; emoji style; # (7.0) DARK SUNGLASSES
+1F577 FE0E ; text style; # (7.0) SPIDER
+1F577 FE0F ; emoji style; # (7.0) SPIDER
+1F578 FE0E ; text style; # (7.0) SPIDER WEB
+1F578 FE0F ; emoji style; # (7.0) SPIDER WEB
+1F579 FE0E ; text style; # (7.0) JOYSTICK
+1F579 FE0F ; emoji style; # (7.0) JOYSTICK
+1F587 FE0E ; text style; # (7.0) LINKED PAPERCLIPS
+1F587 FE0F ; emoji style; # (7.0) LINKED PAPERCLIPS
+1F58A FE0E ; text style; # (7.0) LOWER LEFT BALLPOINT PEN
+1F58A FE0F ; emoji style; # (7.0) LOWER LEFT BALLPOINT PEN
+1F58B FE0E ; text style; # (7.0) LOWER LEFT FOUNTAIN PEN
+1F58B FE0F ; emoji style; # (7.0) LOWER LEFT FOUNTAIN PEN
+1F58C FE0E ; text style; # (7.0) LOWER LEFT PAINTBRUSH
+1F58C FE0F ; emoji style; # (7.0) LOWER LEFT PAINTBRUSH
+1F58D FE0E ; text style; # (7.0) LOWER LEFT CRAYON
+1F58D FE0F ; emoji style; # (7.0) LOWER LEFT CRAYON
+1F590 FE0E ; text style; # (7.0) RAISED HAND WITH FINGERS SPLAYED
+1F590 FE0F ; emoji style; # (7.0) RAISED HAND WITH FINGERS SPLAYED
+1F5A5 FE0E ; text style; # (7.0) DESKTOP COMPUTER
+1F5A5 FE0F ; emoji style; # (7.0) DESKTOP COMPUTER
+1F5A8 FE0E ; text style; # (7.0) PRINTER
+1F5A8 FE0F ; emoji style; # (7.0) PRINTER
+1F5B1 FE0E ; text style; # (7.0) THREE BUTTON MOUSE
+1F5B1 FE0F ; emoji style; # (7.0) THREE BUTTON MOUSE
+1F5B2 FE0E ; text style; # (7.0) TRACKBALL
+1F5B2 FE0F ; emoji style; # (7.0) TRACKBALL
+1F5BC FE0E ; text style; # (7.0) FRAME WITH PICTURE
+1F5BC FE0F ; emoji style; # (7.0) FRAME WITH PICTURE
+1F5C2 FE0E ; text style; # (7.0) CARD INDEX DIVIDERS
+1F5C2 FE0F ; emoji style; # (7.0) CARD INDEX DIVIDERS
+1F5C3 FE0E ; text style; # (7.0) CARD FILE BOX
+1F5C3 FE0F ; emoji style; # (7.0) CARD FILE BOX
+1F5C4 FE0E ; text style; # (7.0) FILE CABINET
+1F5C4 FE0F ; emoji style; # (7.0) FILE CABINET
+1F5D1 FE0E ; text style; # (7.0) WASTEBASKET
+1F5D1 FE0F ; emoji style; # (7.0) WASTEBASKET
+1F5D2 FE0E ; text style; # (7.0) SPIRAL NOTE PAD
+1F5D2 FE0F ; emoji style; # (7.0) SPIRAL NOTE PAD
+1F5D3 FE0E ; text style; # (7.0) SPIRAL CALENDAR PAD
+1F5D3 FE0F ; emoji style; # (7.0) SPIRAL CALENDAR PAD
+1F5DC FE0E ; text style; # (7.0) COMPRESSION
+1F5DC FE0F ; emoji style; # (7.0) COMPRESSION
+1F5DD FE0E ; text style; # (7.0) OLD KEY
+1F5DD FE0F ; emoji style; # (7.0) OLD KEY
+1F5DE FE0E ; text style; # (7.0) ROLLED-UP NEWSPAPER
+1F5DE FE0F ; emoji style; # (7.0) ROLLED-UP NEWSPAPER
+1F5E1 FE0E ; text style; # (7.0) DAGGER KNIFE
+1F5E1 FE0F ; emoji style; # (7.0) DAGGER KNIFE
+1F5E3 FE0E ; text style; # (7.0) SPEAKING HEAD IN SILHOUETTE
+1F5E3 FE0F ; emoji style; # (7.0) SPEAKING HEAD IN SILHOUETTE
+1F5E8 FE0E ; text style; # (7.0) LEFT SPEECH BUBBLE
+1F5E8 FE0F ; emoji style; # (7.0) LEFT SPEECH BUBBLE
+1F5EF FE0E ; text style; # (7.0) RIGHT ANGER BUBBLE
+1F5EF FE0F ; emoji style; # (7.0) RIGHT ANGER BUBBLE
+1F5F3 FE0E ; text style; # (7.0) BALLOT BOX WITH BALLOT
+1F5F3 FE0F ; emoji style; # (7.0) BALLOT BOX WITH BALLOT
+1F5FA FE0E ; text style; # (7.0) WORLD MAP
+1F5FA FE0F ; emoji style; # (7.0) WORLD MAP
+1F610 FE0E ; text style; # (6.0) NEUTRAL FACE
+1F610 FE0F ; emoji style; # (6.0) NEUTRAL FACE
+1F687 FE0E ; text style; # (6.0) METRO
+1F687 FE0F ; emoji style; # (6.0) METRO
+1F68D FE0E ; text style; # (6.0) ONCOMING BUS
+1F68D FE0F ; emoji style; # (6.0) ONCOMING BUS
+1F691 FE0E ; text style; # (6.0) AMBULANCE
+1F691 FE0F ; emoji style; # (6.0) AMBULANCE
+1F694 FE0E ; text style; # (6.0) ONCOMING POLICE CAR
+1F694 FE0F ; emoji style; # (6.0) ONCOMING POLICE CAR
+1F698 FE0E ; text style; # (6.0) ONCOMING AUTOMOBILE
+1F698 FE0F ; emoji style; # (6.0) ONCOMING AUTOMOBILE
+1F6AD FE0E ; text style; # (6.0) NO SMOKING SYMBOL
+1F6AD FE0F ; emoji style; # (6.0) NO SMOKING SYMBOL
+1F6B2 FE0E ; text style; # (6.0) BICYCLE
+1F6B2 FE0F ; emoji style; # (6.0) BICYCLE
+1F6B9 FE0E ; text style; # (6.0) MENS SYMBOL
+1F6B9 FE0F ; emoji style; # (6.0) MENS SYMBOL
+1F6BA FE0E ; text style; # (6.0) WOMENS SYMBOL
+1F6BA FE0F ; emoji style; # (6.0) WOMENS SYMBOL
+1F6BC FE0E ; text style; # (6.0) BABY SYMBOL
+1F6BC FE0F ; emoji style; # (6.0) BABY SYMBOL
+1F6CB FE0E ; text style; # (7.0) COUCH AND LAMP
+1F6CB FE0F ; emoji style; # (7.0) COUCH AND LAMP
+1F6CD FE0E ; text style; # (7.0) SHOPPING BAGS
+1F6CD FE0F ; emoji style; # (7.0) SHOPPING BAGS
+1F6CE FE0E ; text style; # (7.0) BELLHOP BELL
+1F6CE FE0F ; emoji style; # (7.0) BELLHOP BELL
+1F6CF FE0E ; text style; # (7.0) BED
+1F6CF FE0F ; emoji style; # (7.0) BED
+1F6E0 FE0E ; text style; # (7.0) HAMMER AND WRENCH
+1F6E0 FE0F ; emoji style; # (7.0) HAMMER AND WRENCH
+1F6E1 FE0E ; text style; # (7.0) SHIELD
+1F6E1 FE0F ; emoji style; # (7.0) SHIELD
+1F6E2 FE0E ; text style; # (7.0) OIL DRUM
+1F6E2 FE0F ; emoji style; # (7.0) OIL DRUM
+1F6E3 FE0E ; text style; # (7.0) MOTORWAY
+1F6E3 FE0F ; emoji style; # (7.0) MOTORWAY
+1F6E4 FE0E ; text style; # (7.0) RAILWAY TRACK
+1F6E4 FE0F ; emoji style; # (7.0) RAILWAY TRACK
+1F6E5 FE0E ; text style; # (7.0) MOTOR BOAT
+1F6E5 FE0F ; emoji style; # (7.0) MOTOR BOAT
+1F6E9 FE0E ; text style; # (7.0) SMALL AIRPLANE
+1F6E9 FE0F ; emoji style; # (7.0) SMALL AIRPLANE
+1F6F0 FE0E ; text style; # (7.0) SATELLITE
+1F6F0 FE0F ; emoji style; # (7.0) SATELLITE
+1F6F3 FE0E ; text style; # (7.0) PASSENGER SHIP
+1F6F3 FE0F ; emoji style; # (7.0) PASSENGER SHIP
+
+#Total sequences: 371
+
+#EOF
diff --git a/internal/gen/trie.go b/internal/gen/trie.go
index 484bdab..7143b39 100644
--- a/internal/gen/trie.go
+++ b/internal/gen/trie.go
@@ -67,7 +67,7 @@ func WriteTrieGo(trie *triegen.Trie, outputPath string) error {
b = bytes.ReplaceAll(b, []byte(typeDefSig), []byte(noTypeDef))
lookupSig := `(t *` + typename + `) lookup(s []byte)`
- genericLookupSig := `lookup[T ~string | []byte](s T)`
+ genericLookupSig := `lookup[T ~string | ~[]byte](s T)`
b = bytes.ReplaceAll(b, []byte(lookupSig), []byte(genericLookupSig))
lookupValueSig := `(t *` + typename + `) lookupValue`
@@ -101,7 +101,7 @@ func WriteTrieGo(trie *triegen.Trie, outputPath string) error {
// writeProperties writes the character properties definitions to the buffer.
// It uses PropertyDefinitions from unicode.go as the single source of truth.
func writeProperties(w io.Writer) {
- fmt.Fprintf(w, "// property is an enum representing the properties of a character\n")
+ fmt.Fprintf(w, "// property is a bitmap representing the properties of a character\n")
fmt.Fprintf(w, "type property uint8\n\n")
fmt.Fprintf(w, "const (\n")
@@ -110,7 +110,7 @@ func writeProperties(w io.Writer) {
constName := "_" + prop.Name
if i == 0 {
- fmt.Fprintf(w, "%s property = iota + 1\n", constName)
+ fmt.Fprintf(w, "%s property = 1 << iota\n", constName)
} else {
fmt.Fprintf(w, "%s\n", constName)
}
diff --git a/internal/gen/unicode.go b/internal/gen/unicode.go
index 59d1e32..8c658d3 100644
--- a/internal/gen/unicode.go
+++ b/internal/gen/unicode.go
@@ -18,6 +18,7 @@ type UnicodeData struct {
EastAsianWidth map[rune]string // From EastAsianWidth.txt
ExtendedPictographic map[rune]bool // From emoji-data.txt (Extended_Pictographic property)
EmojiPresentation map[rune]bool // From emoji-data.txt (Emoji_Presentation property)
+ VS16Eligible map[rune]bool // From emoji-variation-sequences.txt (base chars with valid FE0F sequence)
RegionalIndicator map[rune]bool // From emoji-data.txt (Regional Indicator symbols, range 1F1E6..1F1FF)
ControlChars map[rune]bool // From Go stdlib
CombiningMarks map[rune]bool // From Go stdlib (Mn, Me only - Mc excluded for proper width)
@@ -39,17 +40,20 @@ var PropertyDefinitions = []PropertyDefinition{
{"Zero_Width", "Always 0 width, includes combining marks, control characters, non-printable, etc"},
{"Wide", "Always 2 wide (East Asian Wide F/W, Emoji, Regional Indicator)"},
{"East_Asian_Ambiguous", "Width depends on EastAsianWidth option"},
+ {"VS16_Eligible", "Default width 1, but FE0F (VS16) requests emoji presentation (width 2)"},
}
// these constants are used to build the property bitmap, internally.
// the external properties are above. Keep them in the same order!
const (
// ZWSP, ZWJ, ZWNJ, etc.
- zero_Width property = iota + 1
+ zero_Width property = 1 << iota
// F, W (East Asian Wide), Emoji, Regional Indicator
wide
// A (East Asian Ambiguous)
east_Asian_Ambiguous
+ // Valid base for emoji variation sequence with VS16 (FE0F)
+ vs16_Eligible
)
// ParseUnicodeData downloads and parses all required Unicode data files
@@ -58,6 +62,7 @@ func ParseUnicodeData() (*UnicodeData, error) {
EastAsianWidth: make(map[rune]string),
ExtendedPictographic: make(map[rune]bool),
EmojiPresentation: make(map[rune]bool),
+ VS16Eligible: make(map[rune]bool),
RegionalIndicator: make(map[rune]bool),
ControlChars: make(map[rune]bool),
CombiningMarks: make(map[rune]bool),
@@ -91,6 +96,14 @@ func ParseUnicodeData() (*UnicodeData, error) {
}
}
+ variationFile := filepath.Join(dataDir, "emoji-variation-sequences.txt")
+ if err := downloadFile(fmt.Sprintf("https://unicode.org/Public/%s/ucd/emoji/emoji-variation-sequences.txt", unicodeVersion), variationFile); err != nil {
+ return nil, fmt.Errorf("failed to download emoji-variation-sequences.txt: %v", err)
+ }
+ if err := parseEmojiVariationSequences(variationFile, data); err != nil {
+ return nil, fmt.Errorf("failed to parse emoji-variation-sequences.txt: %v", err)
+ }
+
extractStdlibData(data)
return data, nil
@@ -277,6 +290,62 @@ func parseEmojiData(filename string, data *UnicodeData) error {
return scanner.Err()
}
+// parseEmojiVariationSequences parses emoji-variation-sequences.txt and marks
+// bases that have a valid emoji presentation sequence (base + FE0F).
+//
+// Any non-blank, non-comment line that does not match the expected
+// " ;