From 8d7c8742a89906c36fae71065e02b46cff49149a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 14 Jul 2024 23:39:45 +0300 Subject: [PATCH] variationselector: generate go code instead of json files --- CHANGELOG.md | 2 + .../emojis-with-extra-variations.json | 1 - variationselector/emojis.go | 1348 +++++++++++++++++ .../fully-qualified-variations.json | 1 - variationselector/generate.go | 100 ++ variationselector/generate.sh | 29 - variationselector/variationselector.go | 42 +- variationselector/variationselector_test.go | 74 +- 8 files changed, 1509 insertions(+), 88 deletions(-) delete mode 100644 variationselector/emojis-with-extra-variations.json create mode 100644 variationselector/emojis.go delete mode 100644 variationselector/fully-qualified-variations.json create mode 100644 variationselector/generate.go delete mode 100755 variationselector/generate.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index b495a46..8ede0cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ * *(gnuzip)* Added wrappers for gzip that operate on `[]byte`s instead of `io.Reader`/`Writer`s. * *(lottie)* Added wrapper for [lottieconverter] similar to ffmpeg. +* *(variationselector)* Fixed edge cases where `Add` and `FullyQualify` + produced invalid output. [lottieconverter]: https://github.com/sot-tech/LottieConverter diff --git a/variationselector/emojis-with-extra-variations.json b/variationselector/emojis-with-extra-variations.json deleted file mode 100644 index 48a4a1e..0000000 --- a/variationselector/emojis-with-extra-variations.json +++ /dev/null @@ -1 +0,0 @@ -["*","0","1","2","3","4","5","6","7","8","9","⌚","⌛","⏩","⏪","⏫","⏬","⏰","⏳","◽","◾","☔","☕","♈","♉","♊","♋","♌","♍","♎","♏","♐","♑","♒","♓","♿","⚓","⚡","⚪","⚫","⚽","⚾","⛄","⛅","⛎","⛔","⛪","⛲","⛳","⛵","⛺","⛽","✅","✊","✋","✨","❌","❎","❓","❔","❕","❗","➕","➖","➗","➰","➿","⬛","⬜","⭐","⭕","🀄","🈚","🈯","🌍","🌎","🌏","🌕","🌜","🍸","🎓","🎧","🎬","🎭","🎮","🏂","🏄","🏆","🏊","🏠","🏭","🐈","🐕","🐟","🐦","👂","👆","👇","👈","👉","👍","👎","👓","👪","👽","💣","💰","💳","💻","💿","📋","📚","📟","📤","📥","📦","📪","📫","📬","📭","📷","📹","📺","📻","🔈","🔍","🔒","🔓","🕐","🕑","🕒","🕓","🕔","🕕","🕖","🕗","🕘","🕙","🕚","🕛","🕜","🕝","🕞","🕟","🕠","🕡","🕢","🕣","🕤","🕥","🕦","🕧","😐","🚇","🚍","🚑","🚔","🚘","🚭","🚲","🚹","🚺","🚼"] diff --git a/variationselector/emojis.go b/variationselector/emojis.go new file mode 100644 index 0000000..4d01ba7 --- /dev/null +++ b/variationselector/emojis.go @@ -0,0 +1,1348 @@ +// Code generated by go generate; DO NOT EDIT. + +package variationselector + +import ( + "regexp" + "strings" +) + +func doInit() { + variationRegex = regexp.MustCompile( + `(^|[^\x{200D}])(` + + `\x{0023}|` + + `\x{002A}|` + + `\x{0030}|` + + `\x{0031}|` + + `\x{0032}|` + + `\x{0033}|` + + `\x{0034}|` + + `\x{0035}|` + + `\x{0036}|` + + `\x{0037}|` + + `\x{0038}|` + + `\x{0039}|` + + `\x{231A}|` + + `\x{231B}|` + + `\x{23E9}|` + + `\x{23EA}|` + + `\x{23EB}|` + + `\x{23EC}|` + + `\x{23F0}|` + + `\x{23F3}|` + + `\x{25FD}|` + + `\x{25FE}|` + + `\x{2614}|` + + `\x{2615}|` + + `\x{2648}|` + + `\x{2649}|` + + `\x{264A}|` + + `\x{264B}|` + + `\x{264C}|` + + `\x{264D}|` + + `\x{264E}|` + + `\x{264F}|` + + `\x{2650}|` + + `\x{2651}|` + + `\x{2652}|` + + `\x{2653}|` + + `\x{267F}|` + + `\x{2693}|` + + `\x{26A1}|` + + `\x{26AA}|` + + `\x{26AB}|` + + `\x{26BD}|` + + `\x{26BE}|` + + `\x{26C4}|` + + `\x{26C5}|` + + `\x{26CE}|` + + `\x{26D4}|` + + `\x{26EA}|` + + `\x{26F2}|` + + `\x{26F3}|` + + `\x{26F5}|` + + `\x{26FA}|` + + `\x{26FD}|` + + `\x{2705}|` + + `\x{270A}|` + + `\x{270B}|` + + `\x{2728}|` + + `\x{274C}|` + + `\x{274E}|` + + `\x{2753}|` + + `\x{2754}|` + + `\x{2755}|` + + `\x{2757}|` + + `\x{2795}|` + + `\x{2796}|` + + `\x{2797}|` + + `\x{27B0}|` + + `\x{27BF}|` + + `\x{2B1B}|` + + `\x{2B1C}|` + + `\x{2B50}|` + + `\x{2B55}|` + + `\x{1F004}|` + + `\x{1F21A}|` + + `\x{1F22F}|` + + `\x{1F30D}|` + + `\x{1F30E}|` + + `\x{1F30F}|` + + `\x{1F315}|` + + `\x{1F31C}|` + + `\x{1F378}|` + + `\x{1F393}|` + + `\x{1F3A7}|` + + `\x{1F3AC}|` + + `\x{1F3AD}|` + + `\x{1F3AE}|` + + `\x{1F3C2}|` + + `\x{1F3C4}|` + + `\x{1F3C6}|` + + `\x{1F3CA}|` + + `\x{1F3E0}|` + + `\x{1F3ED}|` + + `\x{1F408}|` + + `\x{1F415}|` + + `\x{1F41F}|` + + `\x{1F426}|` + + `\x{1F442}|` + + `\x{1F446}|` + + `\x{1F447}|` + + `\x{1F448}|` + + `\x{1F449}|` + + `\x{1F44D}|` + + `\x{1F44E}|` + + `\x{1F453}|` + + `\x{1F46A}|` + + `\x{1F47D}|` + + `\x{1F4A3}|` + + `\x{1F4B0}|` + + `\x{1F4B3}|` + + `\x{1F4BB}|` + + `\x{1F4BF}|` + + `\x{1F4CB}|` + + `\x{1F4DA}|` + + `\x{1F4DF}|` + + `\x{1F4E4}|` + + `\x{1F4E5}|` + + `\x{1F4E6}|` + + `\x{1F4EA}|` + + `\x{1F4EB}|` + + `\x{1F4EC}|` + + `\x{1F4ED}|` + + `\x{1F4F7}|` + + `\x{1F4F9}|` + + `\x{1F4FA}|` + + `\x{1F4FB}|` + + `\x{1F508}|` + + `\x{1F50D}|` + + `\x{1F512}|` + + `\x{1F513}|` + + `\x{1F550}|` + + `\x{1F551}|` + + `\x{1F552}|` + + `\x{1F553}|` + + `\x{1F554}|` + + `\x{1F555}|` + + `\x{1F556}|` + + `\x{1F557}|` + + `\x{1F558}|` + + `\x{1F559}|` + + `\x{1F55A}|` + + `\x{1F55B}|` + + `\x{1F55C}|` + + `\x{1F55D}|` + + `\x{1F55E}|` + + `\x{1F55F}|` + + `\x{1F560}|` + + `\x{1F561}|` + + `\x{1F562}|` + + `\x{1F563}|` + + `\x{1F564}|` + + `\x{1F565}|` + + `\x{1F566}|` + + `\x{1F567}|` + + `\x{1F610}|` + + `\x{1F687}|` + + `\x{1F68D}|` + + `\x{1F691}|` + + `\x{1F694}|` + + `\x{1F698}|` + + `\x{1F6AD}|` + + `\x{1F6B2}|` + + `\x{1F6B9}|` + + `\x{1F6BA}|` + + `\x{1F6BC}` + + `)([^\x{FE0F}\x{FE0E}\x{200D}\x{1F3FB}\x{1F3FC}\x{1F3FD}\x{1F3FE}\x{1F3FF}]|$)`, + ) + var qualifiedEmojis = []string{ + "☺️", + "😶‍🌫️", + "🙂‍↔️", + "🙂‍↕️", + "☹️", + "☠️", + "❣️", + "❤️‍🔥", + "❤️‍🩹", + "❤️", + "🕳️", + "👁️‍🗨️", + "🗨️", + "🗯️", + "🖐️", + "✌️", + "☝️", + "✍️", + "👁️", + "🧔‍♂️", + "🧔🏻‍♂️", + "🧔🏼‍♂️", + "🧔🏽‍♂️", + "🧔🏾‍♂️", + "🧔🏿‍♂️", + "🧔‍♀️", + "🧔🏻‍♀️", + "🧔🏼‍♀️", + "🧔🏽‍♀️", + "🧔🏾‍♀️", + "🧔🏿‍♀️", + "👱‍♀️", + "👱🏻‍♀️", + "👱🏼‍♀️", + "👱🏽‍♀️", + "👱🏾‍♀️", + "👱🏿‍♀️", + "👱‍♂️", + "👱🏻‍♂️", + "👱🏼‍♂️", + "👱🏽‍♂️", + "👱🏾‍♂️", + "👱🏿‍♂️", + "🙍‍♂️", + "🙍🏻‍♂️", + "🙍🏼‍♂️", + "🙍🏽‍♂️", + "🙍🏾‍♂️", + "🙍🏿‍♂️", + "🙍‍♀️", + "🙍🏻‍♀️", + "🙍🏼‍♀️", + "🙍🏽‍♀️", + "🙍🏾‍♀️", + "🙍🏿‍♀️", + "🙎‍♂️", + "🙎🏻‍♂️", + "🙎🏼‍♂️", + "🙎🏽‍♂️", + "🙎🏾‍♂️", + "🙎🏿‍♂️", + "🙎‍♀️", + "🙎🏻‍♀️", + "🙎🏼‍♀️", + "🙎🏽‍♀️", + "🙎🏾‍♀️", + "🙎🏿‍♀️", + "🙅‍♂️", + "🙅🏻‍♂️", + "🙅🏼‍♂️", + "🙅🏽‍♂️", + "🙅🏾‍♂️", + "🙅🏿‍♂️", + "🙅‍♀️", + "🙅🏻‍♀️", + "🙅🏼‍♀️", + "🙅🏽‍♀️", + "🙅🏾‍♀️", + "🙅🏿‍♀️", + "🙆‍♂️", + "🙆🏻‍♂️", + "🙆🏼‍♂️", + "🙆🏽‍♂️", + "🙆🏾‍♂️", + "🙆🏿‍♂️", + "🙆‍♀️", + "🙆🏻‍♀️", + "🙆🏼‍♀️", + "🙆🏽‍♀️", + "🙆🏾‍♀️", + "🙆🏿‍♀️", + "💁‍♂️", + "💁🏻‍♂️", + "💁🏼‍♂️", + "💁🏽‍♂️", + "💁🏾‍♂️", + "💁🏿‍♂️", + "💁‍♀️", + "💁🏻‍♀️", + "💁🏼‍♀️", + "💁🏽‍♀️", + "💁🏾‍♀️", + "💁🏿‍♀️", + "🙋‍♂️", + "🙋🏻‍♂️", + "🙋🏼‍♂️", + "🙋🏽‍♂️", + "🙋🏾‍♂️", + "🙋🏿‍♂️", + "🙋‍♀️", + "🙋🏻‍♀️", + "🙋🏼‍♀️", + "🙋🏽‍♀️", + "🙋🏾‍♀️", + "🙋🏿‍♀️", + "🧏‍♂️", + "🧏🏻‍♂️", + "🧏🏼‍♂️", + "🧏🏽‍♂️", + "🧏🏾‍♂️", + "🧏🏿‍♂️", + "🧏‍♀️", + "🧏🏻‍♀️", + "🧏🏼‍♀️", + "🧏🏽‍♀️", + "🧏🏾‍♀️", + "🧏🏿‍♀️", + "🙇‍♂️", + "🙇🏻‍♂️", + "🙇🏼‍♂️", + "🙇🏽‍♂️", + "🙇🏾‍♂️", + "🙇🏿‍♂️", + "🙇‍♀️", + "🙇🏻‍♀️", + "🙇🏼‍♀️", + "🙇🏽‍♀️", + "🙇🏾‍♀️", + "🙇🏿‍♀️", + "🤦‍♂️", + "🤦🏻‍♂️", + "🤦🏼‍♂️", + "🤦🏽‍♂️", + "🤦🏾‍♂️", + "🤦🏿‍♂️", + "🤦‍♀️", + "🤦🏻‍♀️", + "🤦🏼‍♀️", + "🤦🏽‍♀️", + "🤦🏾‍♀️", + "🤦🏿‍♀️", + "🤷‍♂️", + "🤷🏻‍♂️", + "🤷🏼‍♂️", + "🤷🏽‍♂️", + "🤷🏾‍♂️", + "🤷🏿‍♂️", + "🤷‍♀️", + "🤷🏻‍♀️", + "🤷🏼‍♀️", + "🤷🏽‍♀️", + "🤷🏾‍♀️", + "🤷🏿‍♀️", + "🧑‍⚕️", + "🧑🏻‍⚕️", + "🧑🏼‍⚕️", + "🧑🏽‍⚕️", + "🧑🏾‍⚕️", + "🧑🏿‍⚕️", + "👨‍⚕️", + "👨🏻‍⚕️", + "👨🏼‍⚕️", + "👨🏽‍⚕️", + "👨🏾‍⚕️", + "👨🏿‍⚕️", + "👩‍⚕️", + "👩🏻‍⚕️", + "👩🏼‍⚕️", + "👩🏽‍⚕️", + "👩🏾‍⚕️", + "👩🏿‍⚕️", + "🧑‍⚖️", + "🧑🏻‍⚖️", + "🧑🏼‍⚖️", + "🧑🏽‍⚖️", + "🧑🏾‍⚖️", + "🧑🏿‍⚖️", + "👨‍⚖️", + "👨🏻‍⚖️", + "👨🏼‍⚖️", + "👨🏽‍⚖️", + "👨🏾‍⚖️", + "👨🏿‍⚖️", + "👩‍⚖️", + "👩🏻‍⚖️", + "👩🏼‍⚖️", + "👩🏽‍⚖️", + "👩🏾‍⚖️", + "👩🏿‍⚖️", + "🧑‍✈️", + "🧑🏻‍✈️", + "🧑🏼‍✈️", + "🧑🏽‍✈️", + "🧑🏾‍✈️", + "🧑🏿‍✈️", + "👨‍✈️", + "👨🏻‍✈️", + "👨🏼‍✈️", + "👨🏽‍✈️", + "👨🏾‍✈️", + "👨🏿‍✈️", + "👩‍✈️", + "👩🏻‍✈️", + "👩🏼‍✈️", + "👩🏽‍✈️", + "👩🏾‍✈️", + "👩🏿‍✈️", + "👮‍♂️", + "👮🏻‍♂️", + "👮🏼‍♂️", + "👮🏽‍♂️", + "👮🏾‍♂️", + "👮🏿‍♂️", + "👮‍♀️", + "👮🏻‍♀️", + "👮🏼‍♀️", + "👮🏽‍♀️", + "👮🏾‍♀️", + "👮🏿‍♀️", + "🕵️", + "🕵️‍♂️", + "🕵🏻‍♂️", + "🕵🏼‍♂️", + "🕵🏽‍♂️", + "🕵🏾‍♂️", + "🕵🏿‍♂️", + "🕵️‍♀️", + "🕵🏻‍♀️", + "🕵🏼‍♀️", + "🕵🏽‍♀️", + "🕵🏾‍♀️", + "🕵🏿‍♀️", + "💂‍♂️", + "💂🏻‍♂️", + "💂🏼‍♂️", + "💂🏽‍♂️", + "💂🏾‍♂️", + "💂🏿‍♂️", + "💂‍♀️", + "💂🏻‍♀️", + "💂🏼‍♀️", + "💂🏽‍♀️", + "💂🏾‍♀️", + "💂🏿‍♀️", + "👷‍♂️", + "👷🏻‍♂️", + "👷🏼‍♂️", + "👷🏽‍♂️", + "👷🏾‍♂️", + "👷🏿‍♂️", + "👷‍♀️", + "👷🏻‍♀️", + "👷🏼‍♀️", + "👷🏽‍♀️", + "👷🏾‍♀️", + "👷🏿‍♀️", + "👳‍♂️", + "👳🏻‍♂️", + "👳🏼‍♂️", + "👳🏽‍♂️", + "👳🏾‍♂️", + "👳🏿‍♂️", + "👳‍♀️", + "👳🏻‍♀️", + "👳🏼‍♀️", + "👳🏽‍♀️", + "👳🏾‍♀️", + "👳🏿‍♀️", + "🤵‍♂️", + "🤵🏻‍♂️", + "🤵🏼‍♂️", + "🤵🏽‍♂️", + "🤵🏾‍♂️", + "🤵🏿‍♂️", + "🤵‍♀️", + "🤵🏻‍♀️", + "🤵🏼‍♀️", + "🤵🏽‍♀️", + "🤵🏾‍♀️", + "🤵🏿‍♀️", + "👰‍♂️", + "👰🏻‍♂️", + "👰🏼‍♂️", + "👰🏽‍♂️", + "👰🏾‍♂️", + "👰🏿‍♂️", + "👰‍♀️", + "👰🏻‍♀️", + "👰🏼‍♀️", + "👰🏽‍♀️", + "👰🏾‍♀️", + "👰🏿‍♀️", + "🦸‍♂️", + "🦸🏻‍♂️", + "🦸🏼‍♂️", + "🦸🏽‍♂️", + "🦸🏾‍♂️", + "🦸🏿‍♂️", + "🦸‍♀️", + "🦸🏻‍♀️", + "🦸🏼‍♀️", + "🦸🏽‍♀️", + "🦸🏾‍♀️", + "🦸🏿‍♀️", + "🦹‍♂️", + "🦹🏻‍♂️", + "🦹🏼‍♂️", + "🦹🏽‍♂️", + "🦹🏾‍♂️", + "🦹🏿‍♂️", + "🦹‍♀️", + "🦹🏻‍♀️", + "🦹🏼‍♀️", + "🦹🏽‍♀️", + "🦹🏾‍♀️", + "🦹🏿‍♀️", + "🧙‍♂️", + "🧙🏻‍♂️", + "🧙🏼‍♂️", + "🧙🏽‍♂️", + "🧙🏾‍♂️", + "🧙🏿‍♂️", + "🧙‍♀️", + "🧙🏻‍♀️", + "🧙🏼‍♀️", + "🧙🏽‍♀️", + "🧙🏾‍♀️", + "🧙🏿‍♀️", + "🧚‍♂️", + "🧚🏻‍♂️", + "🧚🏼‍♂️", + "🧚🏽‍♂️", + "🧚🏾‍♂️", + "🧚🏿‍♂️", + "🧚‍♀️", + "🧚🏻‍♀️", + "🧚🏼‍♀️", + "🧚🏽‍♀️", + "🧚🏾‍♀️", + "🧚🏿‍♀️", + "🧛‍♂️", + "🧛🏻‍♂️", + "🧛🏼‍♂️", + "🧛🏽‍♂️", + "🧛🏾‍♂️", + "🧛🏿‍♂️", + "🧛‍♀️", + "🧛🏻‍♀️", + "🧛🏼‍♀️", + "🧛🏽‍♀️", + "🧛🏾‍♀️", + "🧛🏿‍♀️", + "🧜‍♂️", + "🧜🏻‍♂️", + "🧜🏼‍♂️", + "🧜🏽‍♂️", + "🧜🏾‍♂️", + "🧜🏿‍♂️", + "🧜‍♀️", + "🧜🏻‍♀️", + "🧜🏼‍♀️", + "🧜🏽‍♀️", + "🧜🏾‍♀️", + "🧜🏿‍♀️", + "🧝‍♂️", + "🧝🏻‍♂️", + "🧝🏼‍♂️", + "🧝🏽‍♂️", + "🧝🏾‍♂️", + "🧝🏿‍♂️", + "🧝‍♀️", + "🧝🏻‍♀️", + "🧝🏼‍♀️", + "🧝🏽‍♀️", + "🧝🏾‍♀️", + "🧝🏿‍♀️", + "🧞‍♂️", + "🧞‍♀️", + "🧟‍♂️", + "🧟‍♀️", + "💆‍♂️", + "💆🏻‍♂️", + "💆🏼‍♂️", + "💆🏽‍♂️", + "💆🏾‍♂️", + "💆🏿‍♂️", + "💆‍♀️", + "💆🏻‍♀️", + "💆🏼‍♀️", + "💆🏽‍♀️", + "💆🏾‍♀️", + "💆🏿‍♀️", + "💇‍♂️", + "💇🏻‍♂️", + "💇🏼‍♂️", + "💇🏽‍♂️", + "💇🏾‍♂️", + "💇🏿‍♂️", + "💇‍♀️", + "💇🏻‍♀️", + "💇🏼‍♀️", + "💇🏽‍♀️", + "💇🏾‍♀️", + "💇🏿‍♀️", + "🚶‍♂️", + "🚶🏻‍♂️", + "🚶🏼‍♂️", + "🚶🏽‍♂️", + "🚶🏾‍♂️", + "🚶🏿‍♂️", + "🚶‍♀️", + "🚶🏻‍♀️", + "🚶🏼‍♀️", + "🚶🏽‍♀️", + "🚶🏾‍♀️", + "🚶🏿‍♀️", + "🚶‍➡️", + "🚶🏻‍➡️", + "🚶🏼‍➡️", + "🚶🏽‍➡️", + "🚶🏾‍➡️", + "🚶🏿‍➡️", + "🚶‍♀️‍➡️", + "🚶🏻‍♀️‍➡️", + "🚶🏼‍♀️‍➡️", + "🚶🏽‍♀️‍➡️", + "🚶🏾‍♀️‍➡️", + "🚶🏿‍♀️‍➡️", + "🚶‍♂️‍➡️", + "🚶🏻‍♂️‍➡️", + "🚶🏼‍♂️‍➡️", + "🚶🏽‍♂️‍➡️", + "🚶🏾‍♂️‍➡️", + "🚶🏿‍♂️‍➡️", + "🧍‍♂️", + "🧍🏻‍♂️", + "🧍🏼‍♂️", + "🧍🏽‍♂️", + "🧍🏾‍♂️", + "🧍🏿‍♂️", + "🧍‍♀️", + "🧍🏻‍♀️", + "🧍🏼‍♀️", + "🧍🏽‍♀️", + "🧍🏾‍♀️", + "🧍🏿‍♀️", + "🧎‍♂️", + "🧎🏻‍♂️", + "🧎🏼‍♂️", + "🧎🏽‍♂️", + "🧎🏾‍♂️", + "🧎🏿‍♂️", + "🧎‍♀️", + "🧎🏻‍♀️", + "🧎🏼‍♀️", + "🧎🏽‍♀️", + "🧎🏾‍♀️", + "🧎🏿‍♀️", + "🧎‍➡️", + "🧎🏻‍➡️", + "🧎🏼‍➡️", + "🧎🏽‍➡️", + "🧎🏾‍➡️", + "🧎🏿‍➡️", + "🧎‍♀️‍➡️", + "🧎🏻‍♀️‍➡️", + "🧎🏼‍♀️‍➡️", + "🧎🏽‍♀️‍➡️", + "🧎🏾‍♀️‍➡️", + "🧎🏿‍♀️‍➡️", + "🧎‍♂️‍➡️", + "🧎🏻‍♂️‍➡️", + "🧎🏼‍♂️‍➡️", + "🧎🏽‍♂️‍➡️", + "🧎🏾‍♂️‍➡️", + "🧎🏿‍♂️‍➡️", + "🧑‍🦯‍➡️", + "🧑🏻‍🦯‍➡️", + "🧑🏼‍🦯‍➡️", + "🧑🏽‍🦯‍➡️", + "🧑🏾‍🦯‍➡️", + "🧑🏿‍🦯‍➡️", + "👨‍🦯‍➡️", + "👨🏻‍🦯‍➡️", + "👨🏼‍🦯‍➡️", + "👨🏽‍🦯‍➡️", + "👨🏾‍🦯‍➡️", + "👨🏿‍🦯‍➡️", + "👩‍🦯‍➡️", + "👩🏻‍🦯‍➡️", + "👩🏼‍🦯‍➡️", + "👩🏽‍🦯‍➡️", + "👩🏾‍🦯‍➡️", + "👩🏿‍🦯‍➡️", + "🧑‍🦼‍➡️", + "🧑🏻‍🦼‍➡️", + "🧑🏼‍🦼‍➡️", + "🧑🏽‍🦼‍➡️", + "🧑🏾‍🦼‍➡️", + "🧑🏿‍🦼‍➡️", + "👨‍🦼‍➡️", + "👨🏻‍🦼‍➡️", + "👨🏼‍🦼‍➡️", + "👨🏽‍🦼‍➡️", + "👨🏾‍🦼‍➡️", + "👨🏿‍🦼‍➡️", + "👩‍🦼‍➡️", + "👩🏻‍🦼‍➡️", + "👩🏼‍🦼‍➡️", + "👩🏽‍🦼‍➡️", + "👩🏾‍🦼‍➡️", + "👩🏿‍🦼‍➡️", + "🧑‍🦽‍➡️", + "🧑🏻‍🦽‍➡️", + "🧑🏼‍🦽‍➡️", + "🧑🏽‍🦽‍➡️", + "🧑🏾‍🦽‍➡️", + "🧑🏿‍🦽‍➡️", + "👨‍🦽‍➡️", + "👨🏻‍🦽‍➡️", + "👨🏼‍🦽‍➡️", + "👨🏽‍🦽‍➡️", + "👨🏾‍🦽‍➡️", + "👨🏿‍🦽‍➡️", + "👩‍🦽‍➡️", + "👩🏻‍🦽‍➡️", + "👩🏼‍🦽‍➡️", + "👩🏽‍🦽‍➡️", + "👩🏾‍🦽‍➡️", + "👩🏿‍🦽‍➡️", + "🏃‍♂️", + "🏃🏻‍♂️", + "🏃🏼‍♂️", + "🏃🏽‍♂️", + "🏃🏾‍♂️", + "🏃🏿‍♂️", + "🏃‍♀️", + "🏃🏻‍♀️", + "🏃🏼‍♀️", + "🏃🏽‍♀️", + "🏃🏾‍♀️", + "🏃🏿‍♀️", + "🏃‍➡️", + "🏃🏻‍➡️", + "🏃🏼‍➡️", + "🏃🏽‍➡️", + "🏃🏾‍➡️", + "🏃🏿‍➡️", + "🏃‍♀️‍➡️", + "🏃🏻‍♀️‍➡️", + "🏃🏼‍♀️‍➡️", + "🏃🏽‍♀️‍➡️", + "🏃🏾‍♀️‍➡️", + "🏃🏿‍♀️‍➡️", + "🏃‍♂️‍➡️", + "🏃🏻‍♂️‍➡️", + "🏃🏼‍♂️‍➡️", + "🏃🏽‍♂️‍➡️", + "🏃🏾‍♂️‍➡️", + "🏃🏿‍♂️‍➡️", + "🕴️", + "👯‍♂️", + "👯‍♀️", + "🧖‍♂️", + "🧖🏻‍♂️", + "🧖🏼‍♂️", + "🧖🏽‍♂️", + "🧖🏾‍♂️", + "🧖🏿‍♂️", + "🧖‍♀️", + "🧖🏻‍♀️", + "🧖🏼‍♀️", + "🧖🏽‍♀️", + "🧖🏾‍♀️", + "🧖🏿‍♀️", + "🧗‍♂️", + "🧗🏻‍♂️", + "🧗🏼‍♂️", + "🧗🏽‍♂️", + "🧗🏾‍♂️", + "🧗🏿‍♂️", + "🧗‍♀️", + "🧗🏻‍♀️", + "🧗🏼‍♀️", + "🧗🏽‍♀️", + "🧗🏾‍♀️", + "🧗🏿‍♀️", + "⛷️", + "🏌️", + "🏌️‍♂️", + "🏌🏻‍♂️", + "🏌🏼‍♂️", + "🏌🏽‍♂️", + "🏌🏾‍♂️", + "🏌🏿‍♂️", + "🏌️‍♀️", + "🏌🏻‍♀️", + "🏌🏼‍♀️", + "🏌🏽‍♀️", + "🏌🏾‍♀️", + "🏌🏿‍♀️", + "🏄‍♂️", + "🏄🏻‍♂️", + "🏄🏼‍♂️", + "🏄🏽‍♂️", + "🏄🏾‍♂️", + "🏄🏿‍♂️", + "🏄‍♀️", + "🏄🏻‍♀️", + "🏄🏼‍♀️", + "🏄🏽‍♀️", + "🏄🏾‍♀️", + "🏄🏿‍♀️", + "🚣‍♂️", + "🚣🏻‍♂️", + "🚣🏼‍♂️", + "🚣🏽‍♂️", + "🚣🏾‍♂️", + "🚣🏿‍♂️", + "🚣‍♀️", + "🚣🏻‍♀️", + "🚣🏼‍♀️", + "🚣🏽‍♀️", + "🚣🏾‍♀️", + "🚣🏿‍♀️", + "🏊‍♂️", + "🏊🏻‍♂️", + "🏊🏼‍♂️", + "🏊🏽‍♂️", + "🏊🏾‍♂️", + "🏊🏿‍♂️", + "🏊‍♀️", + "🏊🏻‍♀️", + "🏊🏼‍♀️", + "🏊🏽‍♀️", + "🏊🏾‍♀️", + "🏊🏿‍♀️", + "⛹️", + "⛹️‍♂️", + "⛹🏻‍♂️", + "⛹🏼‍♂️", + "⛹🏽‍♂️", + "⛹🏾‍♂️", + "⛹🏿‍♂️", + "⛹️‍♀️", + "⛹🏻‍♀️", + "⛹🏼‍♀️", + "⛹🏽‍♀️", + "⛹🏾‍♀️", + "⛹🏿‍♀️", + "🏋️", + "🏋️‍♂️", + "🏋🏻‍♂️", + "🏋🏼‍♂️", + "🏋🏽‍♂️", + "🏋🏾‍♂️", + "🏋🏿‍♂️", + "🏋️‍♀️", + "🏋🏻‍♀️", + "🏋🏼‍♀️", + "🏋🏽‍♀️", + "🏋🏾‍♀️", + "🏋🏿‍♀️", + "🚴‍♂️", + "🚴🏻‍♂️", + "🚴🏼‍♂️", + "🚴🏽‍♂️", + "🚴🏾‍♂️", + "🚴🏿‍♂️", + "🚴‍♀️", + "🚴🏻‍♀️", + "🚴🏼‍♀️", + "🚴🏽‍♀️", + "🚴🏾‍♀️", + "🚴🏿‍♀️", + "🚵‍♂️", + "🚵🏻‍♂️", + "🚵🏼‍♂️", + "🚵🏽‍♂️", + "🚵🏾‍♂️", + "🚵🏿‍♂️", + "🚵‍♀️", + "🚵🏻‍♀️", + "🚵🏼‍♀️", + "🚵🏽‍♀️", + "🚵🏾‍♀️", + "🚵🏿‍♀️", + "🤸‍♂️", + "🤸🏻‍♂️", + "🤸🏼‍♂️", + "🤸🏽‍♂️", + "🤸🏾‍♂️", + "🤸🏿‍♂️", + "🤸‍♀️", + "🤸🏻‍♀️", + "🤸🏼‍♀️", + "🤸🏽‍♀️", + "🤸🏾‍♀️", + "🤸🏿‍♀️", + "🤼‍♂️", + "🤼‍♀️", + "🤽‍♂️", + "🤽🏻‍♂️", + "🤽🏼‍♂️", + "🤽🏽‍♂️", + "🤽🏾‍♂️", + "🤽🏿‍♂️", + "🤽‍♀️", + "🤽🏻‍♀️", + "🤽🏼‍♀️", + "🤽🏽‍♀️", + "🤽🏾‍♀️", + "🤽🏿‍♀️", + "🤾‍♂️", + "🤾🏻‍♂️", + "🤾🏼‍♂️", + "🤾🏽‍♂️", + "🤾🏾‍♂️", + "🤾🏿‍♂️", + "🤾‍♀️", + "🤾🏻‍♀️", + "🤾🏼‍♀️", + "🤾🏽‍♀️", + "🤾🏾‍♀️", + "🤾🏿‍♀️", + "🤹‍♂️", + "🤹🏻‍♂️", + "🤹🏼‍♂️", + "🤹🏽‍♂️", + "🤹🏾‍♂️", + "🤹🏿‍♂️", + "🤹‍♀️", + "🤹🏻‍♀️", + "🤹🏼‍♀️", + "🤹🏽‍♀️", + "🤹🏾‍♀️", + "🤹🏿‍♀️", + "🧘‍♂️", + "🧘🏻‍♂️", + "🧘🏼‍♂️", + "🧘🏽‍♂️", + "🧘🏾‍♂️", + "🧘🏿‍♂️", + "🧘‍♀️", + "🧘🏻‍♀️", + "🧘🏼‍♀️", + "🧘🏽‍♀️", + "🧘🏾‍♀️", + "🧘🏿‍♀️", + "🧑🏻‍❤️‍💋‍🧑🏼", + "🧑🏻‍❤️‍💋‍🧑🏽", + "🧑🏻‍❤️‍💋‍🧑🏾", + "🧑🏻‍❤️‍💋‍🧑🏿", + "🧑🏼‍❤️‍💋‍🧑🏻", + "🧑🏼‍❤️‍💋‍🧑🏽", + "🧑🏼‍❤️‍💋‍🧑🏾", + "🧑🏼‍❤️‍💋‍🧑🏿", + "🧑🏽‍❤️‍💋‍🧑🏻", + "🧑🏽‍❤️‍💋‍🧑🏼", + "🧑🏽‍❤️‍💋‍🧑🏾", + "🧑🏽‍❤️‍💋‍🧑🏿", + "🧑🏾‍❤️‍💋‍🧑🏻", + "🧑🏾‍❤️‍💋‍🧑🏼", + "🧑🏾‍❤️‍💋‍🧑🏽", + "🧑🏾‍❤️‍💋‍🧑🏿", + "🧑🏿‍❤️‍💋‍🧑🏻", + "🧑🏿‍❤️‍💋‍🧑🏼", + "🧑🏿‍❤️‍💋‍🧑🏽", + "🧑🏿‍❤️‍💋‍🧑🏾", + "👩‍❤️‍💋‍👨", + "👩🏻‍❤️‍💋‍👨🏻", + "👩🏻‍❤️‍💋‍👨🏼", + "👩🏻‍❤️‍💋‍👨🏽", + "👩🏻‍❤️‍💋‍👨🏾", + "👩🏻‍❤️‍💋‍👨🏿", + "👩🏼‍❤️‍💋‍👨🏻", + "👩🏼‍❤️‍💋‍👨🏼", + "👩🏼‍❤️‍💋‍👨🏽", + "👩🏼‍❤️‍💋‍👨🏾", + "👩🏼‍❤️‍💋‍👨🏿", + "👩🏽‍❤️‍💋‍👨🏻", + "👩🏽‍❤️‍💋‍👨🏼", + "👩🏽‍❤️‍💋‍👨🏽", + "👩🏽‍❤️‍💋‍👨🏾", + "👩🏽‍❤️‍💋‍👨🏿", + "👩🏾‍❤️‍💋‍👨🏻", + "👩🏾‍❤️‍💋‍👨🏼", + "👩🏾‍❤️‍💋‍👨🏽", + "👩🏾‍❤️‍💋‍👨🏾", + "👩🏾‍❤️‍💋‍👨🏿", + "👩🏿‍❤️‍💋‍👨🏻", + "👩🏿‍❤️‍💋‍👨🏼", + "👩🏿‍❤️‍💋‍👨🏽", + "👩🏿‍❤️‍💋‍👨🏾", + "👩🏿‍❤️‍💋‍👨🏿", + "👨‍❤️‍💋‍👨", + "👨🏻‍❤️‍💋‍👨🏻", + "👨🏻‍❤️‍💋‍👨🏼", + "👨🏻‍❤️‍💋‍👨🏽", + "👨🏻‍❤️‍💋‍👨🏾", + "👨🏻‍❤️‍💋‍👨🏿", + "👨🏼‍❤️‍💋‍👨🏻", + "👨🏼‍❤️‍💋‍👨🏼", + "👨🏼‍❤️‍💋‍👨🏽", + "👨🏼‍❤️‍💋‍👨🏾", + "👨🏼‍❤️‍💋‍👨🏿", + "👨🏽‍❤️‍💋‍👨🏻", + "👨🏽‍❤️‍💋‍👨🏼", + "👨🏽‍❤️‍💋‍👨🏽", + "👨🏽‍❤️‍💋‍👨🏾", + "👨🏽‍❤️‍💋‍👨🏿", + "👨🏾‍❤️‍💋‍👨🏻", + "👨🏾‍❤️‍💋‍👨🏼", + "👨🏾‍❤️‍💋‍👨🏽", + "👨🏾‍❤️‍💋‍👨🏾", + "👨🏾‍❤️‍💋‍👨🏿", + "👨🏿‍❤️‍💋‍👨🏻", + "👨🏿‍❤️‍💋‍👨🏼", + "👨🏿‍❤️‍💋‍👨🏽", + "👨🏿‍❤️‍💋‍👨🏾", + "👨🏿‍❤️‍💋‍👨🏿", + "👩‍❤️‍💋‍👩", + "👩🏻‍❤️‍💋‍👩🏻", + "👩🏻‍❤️‍💋‍👩🏼", + "👩🏻‍❤️‍💋‍👩🏽", + "👩🏻‍❤️‍💋‍👩🏾", + "👩🏻‍❤️‍💋‍👩🏿", + "👩🏼‍❤️‍💋‍👩🏻", + "👩🏼‍❤️‍💋‍👩🏼", + "👩🏼‍❤️‍💋‍👩🏽", + "👩🏼‍❤️‍💋‍👩🏾", + "👩🏼‍❤️‍💋‍👩🏿", + "👩🏽‍❤️‍💋‍👩🏻", + "👩🏽‍❤️‍💋‍👩🏼", + "👩🏽‍❤️‍💋‍👩🏽", + "👩🏽‍❤️‍💋‍👩🏾", + "👩🏽‍❤️‍💋‍👩🏿", + "👩🏾‍❤️‍💋‍👩🏻", + "👩🏾‍❤️‍💋‍👩🏼", + "👩🏾‍❤️‍💋‍👩🏽", + "👩🏾‍❤️‍💋‍👩🏾", + "👩🏾‍❤️‍💋‍👩🏿", + "👩🏿‍❤️‍💋‍👩🏻", + "👩🏿‍❤️‍💋‍👩🏼", + "👩🏿‍❤️‍💋‍👩🏽", + "👩🏿‍❤️‍💋‍👩🏾", + "👩🏿‍❤️‍💋‍👩🏿", + "🧑🏻‍❤️‍🧑🏼", + "🧑🏻‍❤️‍🧑🏽", + "🧑🏻‍❤️‍🧑🏾", + "🧑🏻‍❤️‍🧑🏿", + "🧑🏼‍❤️‍🧑🏻", + "🧑🏼‍❤️‍🧑🏽", + "🧑🏼‍❤️‍🧑🏾", + "🧑🏼‍❤️‍🧑🏿", + "🧑🏽‍❤️‍🧑🏻", + "🧑🏽‍❤️‍🧑🏼", + "🧑🏽‍❤️‍🧑🏾", + "🧑🏽‍❤️‍🧑🏿", + "🧑🏾‍❤️‍🧑🏻", + "🧑🏾‍❤️‍🧑🏼", + "🧑🏾‍❤️‍🧑🏽", + "🧑🏾‍❤️‍🧑🏿", + "🧑🏿‍❤️‍🧑🏻", + "🧑🏿‍❤️‍🧑🏼", + "🧑🏿‍❤️‍🧑🏽", + "🧑🏿‍❤️‍🧑🏾", + "👩‍❤️‍👨", + "👩🏻‍❤️‍👨🏻", + "👩🏻‍❤️‍👨🏼", + "👩🏻‍❤️‍👨🏽", + "👩🏻‍❤️‍👨🏾", + "👩🏻‍❤️‍👨🏿", + "👩🏼‍❤️‍👨🏻", + "👩🏼‍❤️‍👨🏼", + "👩🏼‍❤️‍👨🏽", + "👩🏼‍❤️‍👨🏾", + "👩🏼‍❤️‍👨🏿", + "👩🏽‍❤️‍👨🏻", + "👩🏽‍❤️‍👨🏼", + "👩🏽‍❤️‍👨🏽", + "👩🏽‍❤️‍👨🏾", + "👩🏽‍❤️‍👨🏿", + "👩🏾‍❤️‍👨🏻", + "👩🏾‍❤️‍👨🏼", + "👩🏾‍❤️‍👨🏽", + "👩🏾‍❤️‍👨🏾", + "👩🏾‍❤️‍👨🏿", + "👩🏿‍❤️‍👨🏻", + "👩🏿‍❤️‍👨🏼", + "👩🏿‍❤️‍👨🏽", + "👩🏿‍❤️‍👨🏾", + "👩🏿‍❤️‍👨🏿", + "👨‍❤️‍👨", + "👨🏻‍❤️‍👨🏻", + "👨🏻‍❤️‍👨🏼", + "👨🏻‍❤️‍👨🏽", + "👨🏻‍❤️‍👨🏾", + "👨🏻‍❤️‍👨🏿", + "👨🏼‍❤️‍👨🏻", + "👨🏼‍❤️‍👨🏼", + "👨🏼‍❤️‍👨🏽", + "👨🏼‍❤️‍👨🏾", + "👨🏼‍❤️‍👨🏿", + "👨🏽‍❤️‍👨🏻", + "👨🏽‍❤️‍👨🏼", + "👨🏽‍❤️‍👨🏽", + "👨🏽‍❤️‍👨🏾", + "👨🏽‍❤️‍👨🏿", + "👨🏾‍❤️‍👨🏻", + "👨🏾‍❤️‍👨🏼", + "👨🏾‍❤️‍👨🏽", + "👨🏾‍❤️‍👨🏾", + "👨🏾‍❤️‍👨🏿", + "👨🏿‍❤️‍👨🏻", + "👨🏿‍❤️‍👨🏼", + "👨🏿‍❤️‍👨🏽", + "👨🏿‍❤️‍👨🏾", + "👨🏿‍❤️‍👨🏿", + "👩‍❤️‍👩", + "👩🏻‍❤️‍👩🏻", + "👩🏻‍❤️‍👩🏼", + "👩🏻‍❤️‍👩🏽", + "👩🏻‍❤️‍👩🏾", + "👩🏻‍❤️‍👩🏿", + "👩🏼‍❤️‍👩🏻", + "👩🏼‍❤️‍👩🏼", + "👩🏼‍❤️‍👩🏽", + "👩🏼‍❤️‍👩🏾", + "👩🏼‍❤️‍👩🏿", + "👩🏽‍❤️‍👩🏻", + "👩🏽‍❤️‍👩🏼", + "👩🏽‍❤️‍👩🏽", + "👩🏽‍❤️‍👩🏾", + "👩🏽‍❤️‍👩🏿", + "👩🏾‍❤️‍👩🏻", + "👩🏾‍❤️‍👩🏼", + "👩🏾‍❤️‍👩🏽", + "👩🏾‍❤️‍👩🏾", + "👩🏾‍❤️‍👩🏿", + "👩🏿‍❤️‍👩🏻", + "👩🏿‍❤️‍👩🏼", + "👩🏿‍❤️‍👩🏽", + "👩🏿‍❤️‍👩🏾", + "👩🏿‍❤️‍👩🏿", + "🗣️", + "🐿️", + "🐻‍❄️", + "🕊️", + "🕷️", + "🕸️", + "🏵️", + "☘️", + "🌶️", + "🍽️", + "🗺️", + "🏔️", + "⛰️", + "🏕️", + "🏖️", + "🏜️", + "🏝️", + "🏞️", + "🏟️", + "🏛️", + "🏗️", + "🏘️", + "🏚️", + "⛩️", + "🏙️", + "♨️", + "🏎️", + "🏍️", + "🛣️", + "🛤️", + "🛢️", + "🛳️", + "⛴️", + "🛥️", + "✈️", + "🛩️", + "🛰️", + "🛎️", + "⏱️", + "⏲️", + "🕰️", + "🌡️", + "☀️", + "☁️", + "⛈️", + "🌤️", + "🌥️", + "🌦️", + "🌧️", + "🌨️", + "🌩️", + "🌪️", + "🌫️", + "🌬️", + "☂️", + "⛱️", + "❄️", + "☃️", + "☄️", + "🎗️", + "🎟️", + "🎖️", + "⛸️", + "🕹️", + "♠️", + "♥️", + "♦️", + "♣️", + "♟️", + "🖼️", + "🕶️", + "🛍️", + "⛑️", + "🎙️", + "🎚️", + "🎛️", + "☎️", + "🖥️", + "🖨️", + "⌨️", + "🖱️", + "🖲️", + "🎞️", + "📽️", + "🕯️", + "🗞️", + "🏷️", + "✉️", + "🗳️", + "✏️", + "✒️", + "🖋️", + "🖊️", + "🖌️", + "🖍️", + "🗂️", + "🗒️", + "🗓️", + "🖇️", + "✂️", + "🗃️", + "🗄️", + "🗑️", + "🗝️", + "⛏️", + "⚒️", + "🛠️", + "🗡️", + "⚔️", + "🛡️", + "⚙️", + "🗜️", + "⚖️", + "⛓️‍💥", + "⛓️", + "⚗️", + "🛏️", + "🛋️", + "⚰️", + "⚱️", + "⚠️", + "☢️", + "☣️", + "⬆️", + "↗️", + "➡️", + "↘️", + "⬇️", + "↙️", + "⬅️", + "↖️", + "↕️", + "↔️", + "↩️", + "↪️", + "⤴️", + "⤵️", + "⚛️", + "🕉️", + "✡️", + "☸️", + "☯️", + "✝️", + "☦️", + "☪️", + "☮️", + "▶️", + "⏭️", + "⏯️", + "◀️", + "⏮️", + "⏸️", + "⏹️", + "⏺️", + "⏏️", + "♀️", + "♂️", + "⚧️", + "✖️", + "♾️", + "‼️", + "⁉️", + "〰️", + "⚕️", + "♻️", + "⚜️", + "☑️", + "✔️", + "〽️", + "✳️", + "✴️", + "❇️", + "©️", + "®️", + "™️", + "#️⃣", + "*️⃣", + "0️⃣", + "1️⃣", + "2️⃣", + "3️⃣", + "4️⃣", + "5️⃣", + "6️⃣", + "7️⃣", + "8️⃣", + "9️⃣", + "🅰️", + "🅱️", + "ℹ️", + "Ⓜ️", + "🅾️", + "🅿️", + "🈂️", + "🈷️", + "㊗️", + "㊙️", + "◼️", + "◻️", + "▪️", + "▫️", + "🏳️", + "🏳️‍🌈", + "🏳️‍⚧️", + "🏴‍☠️", + } + + replacerArgs := make([]string, len(qualifiedEmojis)*2) + for i, emoji := range qualifiedEmojis { + replacerArgs[i*2] = strings.ReplaceAll(emoji, "\ufe0f", "") + replacerArgs[(i*2)+1] = emoji + } + fullyQualifier = strings.NewReplacer(replacerArgs...) +} diff --git a/variationselector/fully-qualified-variations.json b/variationselector/fully-qualified-variations.json deleted file mode 100644 index a0d8063..0000000 --- a/variationselector/fully-qualified-variations.json +++ /dev/null @@ -1 +0,0 @@ -["☺️","😶‍🌫️","🙂‍↔️","🙂‍↕️","☹️","☠️","❣️","❤️‍🔥","❤️‍🩹","❤️","🕳️","👁️‍🗨️","🗨️","🗯️","🖐️","✌️","☝️","✍️","👁️","🧔‍♂️","🧔🏻‍♂️","🧔🏼‍♂️","🧔🏽‍♂️","🧔🏾‍♂️","🧔🏿‍♂️","🧔‍♀️","🧔🏻‍♀️","🧔🏼‍♀️","🧔🏽‍♀️","🧔🏾‍♀️","🧔🏿‍♀️","👱‍♀️","👱🏻‍♀️","👱🏼‍♀️","👱🏽‍♀️","👱🏾‍♀️","👱🏿‍♀️","👱‍♂️","👱🏻‍♂️","👱🏼‍♂️","👱🏽‍♂️","👱🏾‍♂️","👱🏿‍♂️","🙍‍♂️","🙍🏻‍♂️","🙍🏼‍♂️","🙍🏽‍♂️","🙍🏾‍♂️","🙍🏿‍♂️","🙍‍♀️","🙍🏻‍♀️","🙍🏼‍♀️","🙍🏽‍♀️","🙍🏾‍♀️","🙍🏿‍♀️","🙎‍♂️","🙎🏻‍♂️","🙎🏼‍♂️","🙎🏽‍♂️","🙎🏾‍♂️","🙎🏿‍♂️","🙎‍♀️","🙎🏻‍♀️","🙎🏼‍♀️","🙎🏽‍♀️","🙎🏾‍♀️","🙎🏿‍♀️","🙅‍♂️","🙅🏻‍♂️","🙅🏼‍♂️","🙅🏽‍♂️","🙅🏾‍♂️","🙅🏿‍♂️","🙅‍♀️","🙅🏻‍♀️","🙅🏼‍♀️","🙅🏽‍♀️","🙅🏾‍♀️","🙅🏿‍♀️","🙆‍♂️","🙆🏻‍♂️","🙆🏼‍♂️","🙆🏽‍♂️","🙆🏾‍♂️","🙆🏿‍♂️","🙆‍♀️","🙆🏻‍♀️","🙆🏼‍♀️","🙆🏽‍♀️","🙆🏾‍♀️","🙆🏿‍♀️","💁‍♂️","💁🏻‍♂️","💁🏼‍♂️","💁🏽‍♂️","💁🏾‍♂️","💁🏿‍♂️","💁‍♀️","💁🏻‍♀️","💁🏼‍♀️","💁🏽‍♀️","💁🏾‍♀️","💁🏿‍♀️","🙋‍♂️","🙋🏻‍♂️","🙋🏼‍♂️","🙋🏽‍♂️","🙋🏾‍♂️","🙋🏿‍♂️","🙋‍♀️","🙋🏻‍♀️","🙋🏼‍♀️","🙋🏽‍♀️","🙋🏾‍♀️","🙋🏿‍♀️","🧏‍♂️","🧏🏻‍♂️","🧏🏼‍♂️","🧏🏽‍♂️","🧏🏾‍♂️","🧏🏿‍♂️","🧏‍♀️","🧏🏻‍♀️","🧏🏼‍♀️","🧏🏽‍♀️","🧏🏾‍♀️","🧏🏿‍♀️","🙇‍♂️","🙇🏻‍♂️","🙇🏼‍♂️","🙇🏽‍♂️","🙇🏾‍♂️","🙇🏿‍♂️","🙇‍♀️","🙇🏻‍♀️","🙇🏼‍♀️","🙇🏽‍♀️","🙇🏾‍♀️","🙇🏿‍♀️","🤦‍♂️","🤦🏻‍♂️","🤦🏼‍♂️","🤦🏽‍♂️","🤦🏾‍♂️","🤦🏿‍♂️","🤦‍♀️","🤦🏻‍♀️","🤦🏼‍♀️","🤦🏽‍♀️","🤦🏾‍♀️","🤦🏿‍♀️","🤷‍♂️","🤷🏻‍♂️","🤷🏼‍♂️","🤷🏽‍♂️","🤷🏾‍♂️","🤷🏿‍♂️","🤷‍♀️","🤷🏻‍♀️","🤷🏼‍♀️","🤷🏽‍♀️","🤷🏾‍♀️","🤷🏿‍♀️","🧑‍⚕️","🧑🏻‍⚕️","🧑🏼‍⚕️","🧑🏽‍⚕️","🧑🏾‍⚕️","🧑🏿‍⚕️","👨‍⚕️","👨🏻‍⚕️","👨🏼‍⚕️","👨🏽‍⚕️","👨🏾‍⚕️","👨🏿‍⚕️","👩‍⚕️","👩🏻‍⚕️","👩🏼‍⚕️","👩🏽‍⚕️","👩🏾‍⚕️","👩🏿‍⚕️","🧑‍⚖️","🧑🏻‍⚖️","🧑🏼‍⚖️","🧑🏽‍⚖️","🧑🏾‍⚖️","🧑🏿‍⚖️","👨‍⚖️","👨🏻‍⚖️","👨🏼‍⚖️","👨🏽‍⚖️","👨🏾‍⚖️","👨🏿‍⚖️","👩‍⚖️","👩🏻‍⚖️","👩🏼‍⚖️","👩🏽‍⚖️","👩🏾‍⚖️","👩🏿‍⚖️","🧑‍✈️","🧑🏻‍✈️","🧑🏼‍✈️","🧑🏽‍✈️","🧑🏾‍✈️","🧑🏿‍✈️","👨‍✈️","👨🏻‍✈️","👨🏼‍✈️","👨🏽‍✈️","👨🏾‍✈️","👨🏿‍✈️","👩‍✈️","👩🏻‍✈️","👩🏼‍✈️","👩🏽‍✈️","👩🏾‍✈️","👩🏿‍✈️","👮‍♂️","👮🏻‍♂️","👮🏼‍♂️","👮🏽‍♂️","👮🏾‍♂️","👮🏿‍♂️","👮‍♀️","👮🏻‍♀️","👮🏼‍♀️","👮🏽‍♀️","👮🏾‍♀️","👮🏿‍♀️","🕵️","🕵️‍♂️","🕵🏻‍♂️","🕵🏼‍♂️","🕵🏽‍♂️","🕵🏾‍♂️","🕵🏿‍♂️","🕵️‍♀️","🕵🏻‍♀️","🕵🏼‍♀️","🕵🏽‍♀️","🕵🏾‍♀️","🕵🏿‍♀️","💂‍♂️","💂🏻‍♂️","💂🏼‍♂️","💂🏽‍♂️","💂🏾‍♂️","💂🏿‍♂️","💂‍♀️","💂🏻‍♀️","💂🏼‍♀️","💂🏽‍♀️","💂🏾‍♀️","💂🏿‍♀️","👷‍♂️","👷🏻‍♂️","👷🏼‍♂️","👷🏽‍♂️","👷🏾‍♂️","👷🏿‍♂️","👷‍♀️","👷🏻‍♀️","👷🏼‍♀️","👷🏽‍♀️","👷🏾‍♀️","👷🏿‍♀️","👳‍♂️","👳🏻‍♂️","👳🏼‍♂️","👳🏽‍♂️","👳🏾‍♂️","👳🏿‍♂️","👳‍♀️","👳🏻‍♀️","👳🏼‍♀️","👳🏽‍♀️","👳🏾‍♀️","👳🏿‍♀️","🤵‍♂️","🤵🏻‍♂️","🤵🏼‍♂️","🤵🏽‍♂️","🤵🏾‍♂️","🤵🏿‍♂️","🤵‍♀️","🤵🏻‍♀️","🤵🏼‍♀️","🤵🏽‍♀️","🤵🏾‍♀️","🤵🏿‍♀️","👰‍♂️","👰🏻‍♂️","👰🏼‍♂️","👰🏽‍♂️","👰🏾‍♂️","👰🏿‍♂️","👰‍♀️","👰🏻‍♀️","👰🏼‍♀️","👰🏽‍♀️","👰🏾‍♀️","👰🏿‍♀️","🦸‍♂️","🦸🏻‍♂️","🦸🏼‍♂️","🦸🏽‍♂️","🦸🏾‍♂️","🦸🏿‍♂️","🦸‍♀️","🦸🏻‍♀️","🦸🏼‍♀️","🦸🏽‍♀️","🦸🏾‍♀️","🦸🏿‍♀️","🦹‍♂️","🦹🏻‍♂️","🦹🏼‍♂️","🦹🏽‍♂️","🦹🏾‍♂️","🦹🏿‍♂️","🦹‍♀️","🦹🏻‍♀️","🦹🏼‍♀️","🦹🏽‍♀️","🦹🏾‍♀️","🦹🏿‍♀️","🧙‍♂️","🧙🏻‍♂️","🧙🏼‍♂️","🧙🏽‍♂️","🧙🏾‍♂️","🧙🏿‍♂️","🧙‍♀️","🧙🏻‍♀️","🧙🏼‍♀️","🧙🏽‍♀️","🧙🏾‍♀️","🧙🏿‍♀️","🧚‍♂️","🧚🏻‍♂️","🧚🏼‍♂️","🧚🏽‍♂️","🧚🏾‍♂️","🧚🏿‍♂️","🧚‍♀️","🧚🏻‍♀️","🧚🏼‍♀️","🧚🏽‍♀️","🧚🏾‍♀️","🧚🏿‍♀️","🧛‍♂️","🧛🏻‍♂️","🧛🏼‍♂️","🧛🏽‍♂️","🧛🏾‍♂️","🧛🏿‍♂️","🧛‍♀️","🧛🏻‍♀️","🧛🏼‍♀️","🧛🏽‍♀️","🧛🏾‍♀️","🧛🏿‍♀️","🧜‍♂️","🧜🏻‍♂️","🧜🏼‍♂️","🧜🏽‍♂️","🧜🏾‍♂️","🧜🏿‍♂️","🧜‍♀️","🧜🏻‍♀️","🧜🏼‍♀️","🧜🏽‍♀️","🧜🏾‍♀️","🧜🏿‍♀️","🧝‍♂️","🧝🏻‍♂️","🧝🏼‍♂️","🧝🏽‍♂️","🧝🏾‍♂️","🧝🏿‍♂️","🧝‍♀️","🧝🏻‍♀️","🧝🏼‍♀️","🧝🏽‍♀️","🧝🏾‍♀️","🧝🏿‍♀️","🧞‍♂️","🧞‍♀️","🧟‍♂️","🧟‍♀️","💆‍♂️","💆🏻‍♂️","💆🏼‍♂️","💆🏽‍♂️","💆🏾‍♂️","💆🏿‍♂️","💆‍♀️","💆🏻‍♀️","💆🏼‍♀️","💆🏽‍♀️","💆🏾‍♀️","💆🏿‍♀️","💇‍♂️","💇🏻‍♂️","💇🏼‍♂️","💇🏽‍♂️","💇🏾‍♂️","💇🏿‍♂️","💇‍♀️","💇🏻‍♀️","💇🏼‍♀️","💇🏽‍♀️","💇🏾‍♀️","💇🏿‍♀️","🚶‍♂️","🚶🏻‍♂️","🚶🏼‍♂️","🚶🏽‍♂️","🚶🏾‍♂️","🚶🏿‍♂️","🚶‍♀️","🚶🏻‍♀️","🚶🏼‍♀️","🚶🏽‍♀️","🚶🏾‍♀️","🚶🏿‍♀️","🚶‍➡️","🚶🏻‍➡️","🚶🏼‍➡️","🚶🏽‍➡️","🚶🏾‍➡️","🚶🏿‍➡️","🚶‍♀️‍➡️","🚶🏻‍♀️‍➡️","🚶🏼‍♀️‍➡️","🚶🏽‍♀️‍➡️","🚶🏾‍♀️‍➡️","🚶🏿‍♀️‍➡️","🚶‍♂️‍➡️","🚶🏻‍♂️‍➡️","🚶🏼‍♂️‍➡️","🚶🏽‍♂️‍➡️","🚶🏾‍♂️‍➡️","🚶🏿‍♂️‍➡️","🧍‍♂️","🧍🏻‍♂️","🧍🏼‍♂️","🧍🏽‍♂️","🧍🏾‍♂️","🧍🏿‍♂️","🧍‍♀️","🧍🏻‍♀️","🧍🏼‍♀️","🧍🏽‍♀️","🧍🏾‍♀️","🧍🏿‍♀️","🧎‍♂️","🧎🏻‍♂️","🧎🏼‍♂️","🧎🏽‍♂️","🧎🏾‍♂️","🧎🏿‍♂️","🧎‍♀️","🧎🏻‍♀️","🧎🏼‍♀️","🧎🏽‍♀️","🧎🏾‍♀️","🧎🏿‍♀️","🧎‍➡️","🧎🏻‍➡️","🧎🏼‍➡️","🧎🏽‍➡️","🧎🏾‍➡️","🧎🏿‍➡️","🧎‍♀️‍➡️","🧎🏻‍♀️‍➡️","🧎🏼‍♀️‍➡️","🧎🏽‍♀️‍➡️","🧎🏾‍♀️‍➡️","🧎🏿‍♀️‍➡️","🧎‍♂️‍➡️","🧎🏻‍♂️‍➡️","🧎🏼‍♂️‍➡️","🧎🏽‍♂️‍➡️","🧎🏾‍♂️‍➡️","🧎🏿‍♂️‍➡️","🧑‍🦯‍➡️","🧑🏻‍🦯‍➡️","🧑🏼‍🦯‍➡️","🧑🏽‍🦯‍➡️","🧑🏾‍🦯‍➡️","🧑🏿‍🦯‍➡️","👨‍🦯‍➡️","👨🏻‍🦯‍➡️","👨🏼‍🦯‍➡️","👨🏽‍🦯‍➡️","👨🏾‍🦯‍➡️","👨🏿‍🦯‍➡️","👩‍🦯‍➡️","👩🏻‍🦯‍➡️","👩🏼‍🦯‍➡️","👩🏽‍🦯‍➡️","👩🏾‍🦯‍➡️","👩🏿‍🦯‍➡️","🧑‍🦼‍➡️","🧑🏻‍🦼‍➡️","🧑🏼‍🦼‍➡️","🧑🏽‍🦼‍➡️","🧑🏾‍🦼‍➡️","🧑🏿‍🦼‍➡️","👨‍🦼‍➡️","👨🏻‍🦼‍➡️","👨🏼‍🦼‍➡️","👨🏽‍🦼‍➡️","👨🏾‍🦼‍➡️","👨🏿‍🦼‍➡️","👩‍🦼‍➡️","👩🏻‍🦼‍➡️","👩🏼‍🦼‍➡️","👩🏽‍🦼‍➡️","👩🏾‍🦼‍➡️","👩🏿‍🦼‍➡️","🧑‍🦽‍➡️","🧑🏻‍🦽‍➡️","🧑🏼‍🦽‍➡️","🧑🏽‍🦽‍➡️","🧑🏾‍🦽‍➡️","🧑🏿‍🦽‍➡️","👨‍🦽‍➡️","👨🏻‍🦽‍➡️","👨🏼‍🦽‍➡️","👨🏽‍🦽‍➡️","👨🏾‍🦽‍➡️","👨🏿‍🦽‍➡️","👩‍🦽‍➡️","👩🏻‍🦽‍➡️","👩🏼‍🦽‍➡️","👩🏽‍🦽‍➡️","👩🏾‍🦽‍➡️","👩🏿‍🦽‍➡️","🏃‍♂️","🏃🏻‍♂️","🏃🏼‍♂️","🏃🏽‍♂️","🏃🏾‍♂️","🏃🏿‍♂️","🏃‍♀️","🏃🏻‍♀️","🏃🏼‍♀️","🏃🏽‍♀️","🏃🏾‍♀️","🏃🏿‍♀️","🏃‍➡️","🏃🏻‍➡️","🏃🏼‍➡️","🏃🏽‍➡️","🏃🏾‍➡️","🏃🏿‍➡️","🏃‍♀️‍➡️","🏃🏻‍♀️‍➡️","🏃🏼‍♀️‍➡️","🏃🏽‍♀️‍➡️","🏃🏾‍♀️‍➡️","🏃🏿‍♀️‍➡️","🏃‍♂️‍➡️","🏃🏻‍♂️‍➡️","🏃🏼‍♂️‍➡️","🏃🏽‍♂️‍➡️","🏃🏾‍♂️‍➡️","🏃🏿‍♂️‍➡️","🕴️","👯‍♂️","👯‍♀️","🧖‍♂️","🧖🏻‍♂️","🧖🏼‍♂️","🧖🏽‍♂️","🧖🏾‍♂️","🧖🏿‍♂️","🧖‍♀️","🧖🏻‍♀️","🧖🏼‍♀️","🧖🏽‍♀️","🧖🏾‍♀️","🧖🏿‍♀️","🧗‍♂️","🧗🏻‍♂️","🧗🏼‍♂️","🧗🏽‍♂️","🧗🏾‍♂️","🧗🏿‍♂️","🧗‍♀️","🧗🏻‍♀️","🧗🏼‍♀️","🧗🏽‍♀️","🧗🏾‍♀️","🧗🏿‍♀️","⛷️","🏌️","🏌️‍♂️","🏌🏻‍♂️","🏌🏼‍♂️","🏌🏽‍♂️","🏌🏾‍♂️","🏌🏿‍♂️","🏌️‍♀️","🏌🏻‍♀️","🏌🏼‍♀️","🏌🏽‍♀️","🏌🏾‍♀️","🏌🏿‍♀️","🏄‍♂️","🏄🏻‍♂️","🏄🏼‍♂️","🏄🏽‍♂️","🏄🏾‍♂️","🏄🏿‍♂️","🏄‍♀️","🏄🏻‍♀️","🏄🏼‍♀️","🏄🏽‍♀️","🏄🏾‍♀️","🏄🏿‍♀️","🚣‍♂️","🚣🏻‍♂️","🚣🏼‍♂️","🚣🏽‍♂️","🚣🏾‍♂️","🚣🏿‍♂️","🚣‍♀️","🚣🏻‍♀️","🚣🏼‍♀️","🚣🏽‍♀️","🚣🏾‍♀️","🚣🏿‍♀️","🏊‍♂️","🏊🏻‍♂️","🏊🏼‍♂️","🏊🏽‍♂️","🏊🏾‍♂️","🏊🏿‍♂️","🏊‍♀️","🏊🏻‍♀️","🏊🏼‍♀️","🏊🏽‍♀️","🏊🏾‍♀️","🏊🏿‍♀️","⛹️","⛹️‍♂️","⛹🏻‍♂️","⛹🏼‍♂️","⛹🏽‍♂️","⛹🏾‍♂️","⛹🏿‍♂️","⛹️‍♀️","⛹🏻‍♀️","⛹🏼‍♀️","⛹🏽‍♀️","⛹🏾‍♀️","⛹🏿‍♀️","🏋️","🏋️‍♂️","🏋🏻‍♂️","🏋🏼‍♂️","🏋🏽‍♂️","🏋🏾‍♂️","🏋🏿‍♂️","🏋️‍♀️","🏋🏻‍♀️","🏋🏼‍♀️","🏋🏽‍♀️","🏋🏾‍♀️","🏋🏿‍♀️","🚴‍♂️","🚴🏻‍♂️","🚴🏼‍♂️","🚴🏽‍♂️","🚴🏾‍♂️","🚴🏿‍♂️","🚴‍♀️","🚴🏻‍♀️","🚴🏼‍♀️","🚴🏽‍♀️","🚴🏾‍♀️","🚴🏿‍♀️","🚵‍♂️","🚵🏻‍♂️","🚵🏼‍♂️","🚵🏽‍♂️","🚵🏾‍♂️","🚵🏿‍♂️","🚵‍♀️","🚵🏻‍♀️","🚵🏼‍♀️","🚵🏽‍♀️","🚵🏾‍♀️","🚵🏿‍♀️","🤸‍♂️","🤸🏻‍♂️","🤸🏼‍♂️","🤸🏽‍♂️","🤸🏾‍♂️","🤸🏿‍♂️","🤸‍♀️","🤸🏻‍♀️","🤸🏼‍♀️","🤸🏽‍♀️","🤸🏾‍♀️","🤸🏿‍♀️","🤼‍♂️","🤼‍♀️","🤽‍♂️","🤽🏻‍♂️","🤽🏼‍♂️","🤽🏽‍♂️","🤽🏾‍♂️","🤽🏿‍♂️","🤽‍♀️","🤽🏻‍♀️","🤽🏼‍♀️","🤽🏽‍♀️","🤽🏾‍♀️","🤽🏿‍♀️","🤾‍♂️","🤾🏻‍♂️","🤾🏼‍♂️","🤾🏽‍♂️","🤾🏾‍♂️","🤾🏿‍♂️","🤾‍♀️","🤾🏻‍♀️","🤾🏼‍♀️","🤾🏽‍♀️","🤾🏾‍♀️","🤾🏿‍♀️","🤹‍♂️","🤹🏻‍♂️","🤹🏼‍♂️","🤹🏽‍♂️","🤹🏾‍♂️","🤹🏿‍♂️","🤹‍♀️","🤹🏻‍♀️","🤹🏼‍♀️","🤹🏽‍♀️","🤹🏾‍♀️","🤹🏿‍♀️","🧘‍♂️","🧘🏻‍♂️","🧘🏼‍♂️","🧘🏽‍♂️","🧘🏾‍♂️","🧘🏿‍♂️","🧘‍♀️","🧘🏻‍♀️","🧘🏼‍♀️","🧘🏽‍♀️","🧘🏾‍♀️","🧘🏿‍♀️","🧑🏻‍❤️‍💋‍🧑🏼","🧑🏻‍❤️‍💋‍🧑🏽","🧑🏻‍❤️‍💋‍🧑🏾","🧑🏻‍❤️‍💋‍🧑🏿","🧑🏼‍❤️‍💋‍🧑🏻","🧑🏼‍❤️‍💋‍🧑🏽","🧑🏼‍❤️‍💋‍🧑🏾","🧑🏼‍❤️‍💋‍🧑🏿","🧑🏽‍❤️‍💋‍🧑🏻","🧑🏽‍❤️‍💋‍🧑🏼","🧑🏽‍❤️‍💋‍🧑🏾","🧑🏽‍❤️‍💋‍🧑🏿","🧑🏾‍❤️‍💋‍🧑🏻","🧑🏾‍❤️‍💋‍🧑🏼","🧑🏾‍❤️‍💋‍🧑🏽","🧑🏾‍❤️‍💋‍🧑🏿","🧑🏿‍❤️‍💋‍🧑🏻","🧑🏿‍❤️‍💋‍🧑🏼","🧑🏿‍❤️‍💋‍🧑🏽","🧑🏿‍❤️‍💋‍🧑🏾","👩‍❤️‍💋‍👨","👩🏻‍❤️‍💋‍👨🏻","👩🏻‍❤️‍💋‍👨🏼","👩🏻‍❤️‍💋‍👨🏽","👩🏻‍❤️‍💋‍👨🏾","👩🏻‍❤️‍💋‍👨🏿","👩🏼‍❤️‍💋‍👨🏻","👩🏼‍❤️‍💋‍👨🏼","👩🏼‍❤️‍💋‍👨🏽","👩🏼‍❤️‍💋‍👨🏾","👩🏼‍❤️‍💋‍👨🏿","👩🏽‍❤️‍💋‍👨🏻","👩🏽‍❤️‍💋‍👨🏼","👩🏽‍❤️‍💋‍👨🏽","👩🏽‍❤️‍💋‍👨🏾","👩🏽‍❤️‍💋‍👨🏿","👩🏾‍❤️‍💋‍👨🏻","👩🏾‍❤️‍💋‍👨🏼","👩🏾‍❤️‍💋‍👨🏽","👩🏾‍❤️‍💋‍👨🏾","👩🏾‍❤️‍💋‍👨🏿","👩🏿‍❤️‍💋‍👨🏻","👩🏿‍❤️‍💋‍👨🏼","👩🏿‍❤️‍💋‍👨🏽","👩🏿‍❤️‍💋‍👨🏾","👩🏿‍❤️‍💋‍👨🏿","👨‍❤️‍💋‍👨","👨🏻‍❤️‍💋‍👨🏻","👨🏻‍❤️‍💋‍👨🏼","👨🏻‍❤️‍💋‍👨🏽","👨🏻‍❤️‍💋‍👨🏾","👨🏻‍❤️‍💋‍👨🏿","👨🏼‍❤️‍💋‍👨🏻","👨🏼‍❤️‍💋‍👨🏼","👨🏼‍❤️‍💋‍👨🏽","👨🏼‍❤️‍💋‍👨🏾","👨🏼‍❤️‍💋‍👨🏿","👨🏽‍❤️‍💋‍👨🏻","👨🏽‍❤️‍💋‍👨🏼","👨🏽‍❤️‍💋‍👨🏽","👨🏽‍❤️‍💋‍👨🏾","👨🏽‍❤️‍💋‍👨🏿","👨🏾‍❤️‍💋‍👨🏻","👨🏾‍❤️‍💋‍👨🏼","👨🏾‍❤️‍💋‍👨🏽","👨🏾‍❤️‍💋‍👨🏾","👨🏾‍❤️‍💋‍👨🏿","👨🏿‍❤️‍💋‍👨🏻","👨🏿‍❤️‍💋‍👨🏼","👨🏿‍❤️‍💋‍👨🏽","👨🏿‍❤️‍💋‍👨🏾","👨🏿‍❤️‍💋‍👨🏿","👩‍❤️‍💋‍👩","👩🏻‍❤️‍💋‍👩🏻","👩🏻‍❤️‍💋‍👩🏼","👩🏻‍❤️‍💋‍👩🏽","👩🏻‍❤️‍💋‍👩🏾","👩🏻‍❤️‍💋‍👩🏿","👩🏼‍❤️‍💋‍👩🏻","👩🏼‍❤️‍💋‍👩🏼","👩🏼‍❤️‍💋‍👩🏽","👩🏼‍❤️‍💋‍👩🏾","👩🏼‍❤️‍💋‍👩🏿","👩🏽‍❤️‍💋‍👩🏻","👩🏽‍❤️‍💋‍👩🏼","👩🏽‍❤️‍💋‍👩🏽","👩🏽‍❤️‍💋‍👩🏾","👩🏽‍❤️‍💋‍👩🏿","👩🏾‍❤️‍💋‍👩🏻","👩🏾‍❤️‍💋‍👩🏼","👩🏾‍❤️‍💋‍👩🏽","👩🏾‍❤️‍💋‍👩🏾","👩🏾‍❤️‍💋‍👩🏿","👩🏿‍❤️‍💋‍👩🏻","👩🏿‍❤️‍💋‍👩🏼","👩🏿‍❤️‍💋‍👩🏽","👩🏿‍❤️‍💋‍👩🏾","👩🏿‍❤️‍💋‍👩🏿","🧑🏻‍❤️‍🧑🏼","🧑🏻‍❤️‍🧑🏽","🧑🏻‍❤️‍🧑🏾","🧑🏻‍❤️‍🧑🏿","🧑🏼‍❤️‍🧑🏻","🧑🏼‍❤️‍🧑🏽","🧑🏼‍❤️‍🧑🏾","🧑🏼‍❤️‍🧑🏿","🧑🏽‍❤️‍🧑🏻","🧑🏽‍❤️‍🧑🏼","🧑🏽‍❤️‍🧑🏾","🧑🏽‍❤️‍🧑🏿","🧑🏾‍❤️‍🧑🏻","🧑🏾‍❤️‍🧑🏼","🧑🏾‍❤️‍🧑🏽","🧑🏾‍❤️‍🧑🏿","🧑🏿‍❤️‍🧑🏻","🧑🏿‍❤️‍🧑🏼","🧑🏿‍❤️‍🧑🏽","🧑🏿‍❤️‍🧑🏾","👩‍❤️‍👨","👩🏻‍❤️‍👨🏻","👩🏻‍❤️‍👨🏼","👩🏻‍❤️‍👨🏽","👩🏻‍❤️‍👨🏾","👩🏻‍❤️‍👨🏿","👩🏼‍❤️‍👨🏻","👩🏼‍❤️‍👨🏼","👩🏼‍❤️‍👨🏽","👩🏼‍❤️‍👨🏾","👩🏼‍❤️‍👨🏿","👩🏽‍❤️‍👨🏻","👩🏽‍❤️‍👨🏼","👩🏽‍❤️‍👨🏽","👩🏽‍❤️‍👨🏾","👩🏽‍❤️‍👨🏿","👩🏾‍❤️‍👨🏻","👩🏾‍❤️‍👨🏼","👩🏾‍❤️‍👨🏽","👩🏾‍❤️‍👨🏾","👩🏾‍❤️‍👨🏿","👩🏿‍❤️‍👨🏻","👩🏿‍❤️‍👨🏼","👩🏿‍❤️‍👨🏽","👩🏿‍❤️‍👨🏾","👩🏿‍❤️‍👨🏿","👨‍❤️‍👨","👨🏻‍❤️‍👨🏻","👨🏻‍❤️‍👨🏼","👨🏻‍❤️‍👨🏽","👨🏻‍❤️‍👨🏾","👨🏻‍❤️‍👨🏿","👨🏼‍❤️‍👨🏻","👨🏼‍❤️‍👨🏼","👨🏼‍❤️‍👨🏽","👨🏼‍❤️‍👨🏾","👨🏼‍❤️‍👨🏿","👨🏽‍❤️‍👨🏻","👨🏽‍❤️‍👨🏼","👨🏽‍❤️‍👨🏽","👨🏽‍❤️‍👨🏾","👨🏽‍❤️‍👨🏿","👨🏾‍❤️‍👨🏻","👨🏾‍❤️‍👨🏼","👨🏾‍❤️‍👨🏽","👨🏾‍❤️‍👨🏾","👨🏾‍❤️‍👨🏿","👨🏿‍❤️‍👨🏻","👨🏿‍❤️‍👨🏼","👨🏿‍❤️‍👨🏽","👨🏿‍❤️‍👨🏾","👨🏿‍❤️‍👨🏿","👩‍❤️‍👩","👩🏻‍❤️‍👩🏻","👩🏻‍❤️‍👩🏼","👩🏻‍❤️‍👩🏽","👩🏻‍❤️‍👩🏾","👩🏻‍❤️‍👩🏿","👩🏼‍❤️‍👩🏻","👩🏼‍❤️‍👩🏼","👩🏼‍❤️‍👩🏽","👩🏼‍❤️‍👩🏾","👩🏼‍❤️‍👩🏿","👩🏽‍❤️‍👩🏻","👩🏽‍❤️‍👩🏼","👩🏽‍❤️‍👩🏽","👩🏽‍❤️‍👩🏾","👩🏽‍❤️‍👩🏿","👩🏾‍❤️‍👩🏻","👩🏾‍❤️‍👩🏼","👩🏾‍❤️‍👩🏽","👩🏾‍❤️‍👩🏾","👩🏾‍❤️‍👩🏿","👩🏿‍❤️‍👩🏻","👩🏿‍❤️‍👩🏼","👩🏿‍❤️‍👩🏽","👩🏿‍❤️‍👩🏾","👩🏿‍❤️‍👩🏿","🗣️","🐿️","🐻‍❄️","🕊️","🕷️","🕸️","🏵️","☘️","🌶️","🍽️","🗺️","🏔️","⛰️","🏕️","🏖️","🏜️","🏝️","🏞️","🏟️","🏛️","🏗️","🏘️","🏚️","⛩️","🏙️","♨️","🏎️","🏍️","🛣️","🛤️","🛢️","🛳️","⛴️","🛥️","✈️","🛩️","🛰️","🛎️","⏱️","⏲️","🕰️","🌡️","☀️","☁️","⛈️","🌤️","🌥️","🌦️","🌧️","🌨️","🌩️","🌪️","🌫️","🌬️","☂️","⛱️","❄️","☃️","☄️","🎗️","🎟️","🎖️","⛸️","🕹️","♠️","♥️","♦️","♣️","♟️","🖼️","🕶️","🛍️","⛑️","🎙️","🎚️","🎛️","☎️","🖥️","🖨️","⌨️","🖱️","🖲️","🎞️","📽️","🕯️","🗞️","🏷️","✉️","🗳️","✏️","✒️","🖋️","🖊️","🖌️","🖍️","🗂️","🗒️","🗓️","🖇️","✂️","🗃️","🗄️","🗑️","🗝️","⛏️","⚒️","🛠️","🗡️","⚔️","🛡️","⚙️","🗜️","⚖️","⛓️‍💥","⛓️","⚗️","🛏️","🛋️","⚰️","⚱️","⚠️","☢️","☣️","⬆️","↗️","➡️","↘️","⬇️","↙️","⬅️","↖️","↕️","↔️","↩️","↪️","⤴️","⤵️","⚛️","🕉️","✡️","☸️","☯️","✝️","☦️","☪️","☮️","▶️","⏭️","⏯️","◀️","⏮️","⏸️","⏹️","⏺️","⏏️","♀️","♂️","⚧️","✖️","♾️","‼️","⁉️","〰️","⚕️","♻️","⚜️","☑️","✔️","〽️","✳️","✴️","❇️","©️","®️","™️","#️⃣","*️⃣","0️⃣","1️⃣","2️⃣","3️⃣","4️⃣","5️⃣","6️⃣","7️⃣","8️⃣","9️⃣","🅰️","🅱️","ℹ️","Ⓜ️","🅾️","🅿️","🈂️","🈷️","㊗️","㊙️","◼️","◻️","▪️","▫️","🏳️","🏳️‍🌈","🏳️‍⚧️","🏴‍☠️"] diff --git a/variationselector/generate.go b/variationselector/generate.go new file mode 100644 index 0000000..a70678a --- /dev/null +++ b/variationselector/generate.go @@ -0,0 +1,100 @@ +//go:build ignore + +// Copyright (c) 2024 Tulir Asokan +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package main + +import ( + "bufio" + "errors" + "fmt" + "io" + "net/http" + "os" + "strconv" + "strings" + + "golang.org/x/exp/slices" + + "go.mau.fi/util/exerrors" +) + +const UnicodeVersion = "15.1" + +func readEmojiLines(url, filter string) (output []string) { + resp := exerrors.Must(http.Get(url)) + buf := bufio.NewReader(resp.Body) + for { + line, err := buf.ReadString('\n') + if errors.Is(err, io.EOF) { + break + } else if err != nil { + panic(err) + } + parts := strings.Split(line, "; ") + if len(parts) < 2 || !strings.HasPrefix(parts[1], filter) { + continue + } + output = append(output, strings.TrimSpace(parts[0])) + } + return +} + +func unifiedToUnicode(input string) string { + parts := strings.Split(input, " ") + output := make([]rune, len(parts)) + for i, part := range parts { + output[i] = rune(exerrors.Must(strconv.ParseInt(part, 16, 32))) + } + return string(output) +} + +func main() { + variationSequences := readEmojiLines("https://www.unicode.org/Public/"+UnicodeVersion+".0/ucd/emoji/emoji-variation-sequences.txt", "emoji style") + fullyQualifiedSequences := readEmojiLines("https://unicode.org/Public/emoji/"+UnicodeVersion+"/emoji-test.txt", "fully-qualified") + var extraVariations []string + for _, seq := range variationSequences { + if !slices.Contains(fullyQualifiedSequences, seq) { + unifiedWithoutVS := strings.Split(seq, " ")[0] + extraVariations = append(extraVariations, fmt.Sprintf(`\x{%s}`, unifiedWithoutVS)) + } + } + file := exerrors.Must(os.OpenFile("emojis.go", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)) + exerrors.Must(file.WriteString(`// Code generated by go generate; DO NOT EDIT. + +package variationselector + +import ( + "regexp" + "strings" +) + +func doInit() { +`)) + exerrors.Must(file.WriteString("\tvariationRegex = regexp.MustCompile(\n")) + exerrors.Must(file.WriteString("\t\t`(^|[^\\x{200D}])(` +\n\t\t\t`")) + exerrors.Must(file.WriteString(strings.Join(extraVariations, "|` +\n\t\t\t`"))) + exerrors.Must(file.WriteString("` +\n\t\t\t`)([^\\x{FE0F}\\x{FE0E}\\x{200D}\\x{1F3FB}\\x{1F3FC}\\x{1F3FD}\\x{1F3FE}\\x{1F3FF}]|$)`,\n\t)\n")) + exerrors.Must(file.WriteString("\tvar qualifiedEmojis = []string{\n")) + for _, unified := range fullyQualifiedSequences { + if !strings.Contains(unified, "FE0F") { + continue + } + unicode := unifiedToUnicode(unified) + exerrors.Must(fmt.Fprintf(file, "\t\t\"%s\",\n", unicode)) + } + exerrors.Must(file.WriteString("\t}\n")) + exerrors.Must(file.WriteString(` + replacerArgs := make([]string, len(qualifiedEmojis)*2) + for i, emoji := range qualifiedEmojis { + replacerArgs[i*2] = strings.ReplaceAll(emoji, "\ufe0f", "") + replacerArgs[(i*2)+1] = emoji + } +`)) + exerrors.Must(file.WriteString("\tfullyQualifier = strings.NewReplacer(replacerArgs...)\n")) + exerrors.Must(file.WriteString("}\n")) +} diff --git a/variationselector/generate.sh b/variationselector/generate.sh deleted file mode 100755 index 160052c..0000000 --- a/variationselector/generate.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -echo -e "$( - curl -s https://www.unicode.org/Public/15.1.0/ucd/emoji/emoji-variation-sequences.txt \ - | grep FE0F \ - | awk '{ printf("\\U%8s\n", $1) }' \ - | sed 's/ /0/g' -)" | jq -RcM '[inputs]' > emojis-with-variations.json - -# Why does this need a \n at the beginning to avoid eating the first emoji?!?! -echo -e "\n$( - curl -s https://unicode.org/Public/emoji/15.1/emoji-test.txt \ - | grep '; fully-qualified' \ - | grep FE0F \ - | sed -E 's/\s+;.*//g' \ - | awk '{ for (i = 1; i <= NF; i++) {printf("\\U%8s", $i) }; printf("\n") }' \ - | sed 's/ /0/g' -)" | jq -RcM '[inputs]' > fully-qualified-variations.json - -python < 1 { - panic(fmt.Sprintf("emoji %s is more than one rune long", emoji)) - } - emojisWithExtraVariations[i] = fmt.Sprintf(`\x{%X}`, emojiRunes[0]) - } - variationPattern := fmt.Sprintf(`(^|[^\x{200D}])(%s)([^\x{FE0F}\x{FE0E}\x{200D}\x{1F3FB}\x{1F3FC}\x{1F3FD}\x{1F3FE}\x{1F3FF}]|$)`, strings.Join(emojisWithExtraVariations, "|")) - variationRegex = regexp.MustCompile(variationPattern) - - var fullyQualifiedVariations []string - err = json.Unmarshal(fullyQualifiedVariationsJSON, &fullyQualifiedVariations) - if err != nil { - panic(err) - } - replaceInput := make([]string, 2*len(fullyQualifiedVariations)) - for i, emoji := range fullyQualifiedVariations { - replaceInput[i*2] = strings.ReplaceAll(emoji, VS16, "") - replaceInput[(i*2)+1] = emoji - } - fullyQualifier = strings.NewReplacer(replaceInput...) -} - const VS16 = "\ufe0f" // Add adds emoji variation selectors to all emojis that have multiple forms in the given string. diff --git a/variationselector/variationselector_test.go b/variationselector/variationselector_test.go index 250838e..912497f 100644 --- a/variationselector/variationselector_test.go +++ b/variationselector/variationselector_test.go @@ -98,6 +98,8 @@ func TestAdd(t *testing.T) { assert.Equal(t, "4\ufe0f\u20e3", variationselector.Add("4\ufe0f\u20e3")) assert.Equal(t, "\U0001f914", variationselector.Add("\U0001f914")) assert.Equal(t, "\U0001f408\u200d\u2b1b", variationselector.Add("\U0001f408\u200d\u2b1b")) + assert.Equal(t, "\u2122\ufe0f", variationselector.Add("\u2122")) + assert.Equal(t, "\u2122\ufe0e", variationselector.Add("\u2122\ufe0e")) } func TestFullyQualify(t *testing.T) { @@ -110,7 +112,9 @@ func TestFullyQualify(t *testing.T) { assert.Equal(t, "\u263a\ufe0f", variationselector.FullyQualify("\u263a")) assert.Equal(t, "\U0001f3f3\ufe0f\u200D\U0001f308", variationselector.FullyQualify("\U0001f3f3\u200D\U0001f308")) assert.Equal(t, "\U0001f3f3\ufe0f\u200D\U0001f308", variationselector.FullyQualify("\U0001f3f3\ufe0f\u200D\U0001f308")) - assert.Equal(t, "\U0001f408\u200d\u2b1b", variationselector.Add("\U0001f408\u200d\u2b1b")) + assert.Equal(t, "\U0001f408\u200d\u2b1b", variationselector.FullyQualify("\U0001f408\u200d\u2b1b")) + assert.Equal(t, "\u2122\ufe0f", variationselector.FullyQualify("\u2122")) + assert.Equal(t, "\u2122\ufe0e", variationselector.FullyQualify("\u2122\ufe0e")) } func TestRemove(t *testing.T) { @@ -157,26 +161,62 @@ func ExampleRemove() { // "\U0001f44d" } -func BenchmarkAdd(b *testing.B) { +func doBenchmarkAdd(b *testing.B, input string) { for i := 0; i < b.N; i++ { - variationselector.Add("\U0001f44d\U0001f3fd") - variationselector.Add("\U0001f44d") - variationselector.Add("\U0001f44d\ufe0f") - variationselector.Add("4\u20e3") - variationselector.Add("4\ufe0f\u20e3") - variationselector.Add("\U0001f914") - variationselector.Add("\U0001f408\u200d\u2b1b") + variationselector.Add(input) } } -func BenchmarkFullyQualify(b *testing.B) { +func BenchmarkAddNumber4(b *testing.B) { + doBenchmarkAdd(b, "4️\u20e3") +} + +func BenchmarkAddBlackCat(b *testing.B) { + doBenchmarkAdd(b, "\U0001f408\u200d\u2b1b") +} + +func BenchmarkAddString(b *testing.B) { + doBenchmarkAdd(b, "This is a slightly longer 🤔 string 🐈️ that contains a few emojis 👍️") +} + +func BenchmarkAddLongString(b *testing.B) { + doBenchmarkAdd(b, strings.Repeat("This is a slightly longer 🤔 string 🐈️ that contains a few emojis 👍️", 1000)) +} + +func BenchmarkAddNoEmojis(b *testing.B) { + doBenchmarkAdd(b, "This is a slightly longer string that does not contain any emojis") +} + +func BenchmarkAddNoEmojisLong(b *testing.B) { + doBenchmarkAdd(b, strings.Repeat("This is a slightly longer string that does not contain any emojis", 1000)) +} + +func doBenchmarkFullyQualify(b *testing.B, input string) { for i := 0; i < b.N; i++ { - variationselector.FullyQualify("\U0001f44d\U0001f3fd") - variationselector.FullyQualify("\U0001f44d") - variationselector.FullyQualify("\U0001f44d\ufe0f") - variationselector.FullyQualify("4\u20e3") - variationselector.FullyQualify("4\ufe0f\u20e3") - variationselector.FullyQualify("\U0001f914") - variationselector.FullyQualify("\U0001f408\u200d\u2b1b") + variationselector.FullyQualify(input) } } + +func BenchmarkFullyQualifyNumber4(b *testing.B) { + doBenchmarkFullyQualify(b, "4\ufe0f\u20e3") +} + +func BenchmarkFullyQualifyBlackCat(b *testing.B) { + doBenchmarkFullyQualify(b, "\U0001f408\u200d\u2b1b") +} + +func BenchmarkFullyQualifyString(b *testing.B) { + doBenchmarkFullyQualify(b, "This is a slightly longer 🤔 string 🐈️ that contains a few emojis 👍️") +} + +func BenchmarkFullyQualifyLongString(b *testing.B) { + doBenchmarkFullyQualify(b, strings.Repeat("This is a slightly longer 🤔 string 🐈️ that contains a few emojis 👍️", 1000)) +} + +func BenchmarkFullyQualifyNoEmojis(b *testing.B) { + doBenchmarkFullyQualify(b, "This is a slightly longer string that does not contain any emojis") +} + +func BenchmarkFullyQualifyNoEmojisLong(b *testing.B) { + doBenchmarkFullyQualify(b, strings.Repeat("This is a slightly longer string that does not contain any emojis", 1000)) +}