diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 8ddcc22..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 aspizu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100644 index cfba980..0000000 --- a/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# `std` is the goboscript standard library - -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/goboscript/std) - -## Installation - -Add the following to your `goboscript.toml` file: - -```toml -std = "2.1.0" -``` diff --git a/base64.gs b/base64.gs new file mode 100644 index 0000000..93fcff8 --- /dev/null +++ b/base64.gs @@ -0,0 +1,108 @@ +list base64_buffer; +list base64_strbuf; +list base64_lut; # lookup table: ASCII costume_number -> base64 value (0-63), 255=invalid/pad + +%define BASE64_CHARSET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" +%define BASE64_URLSAFE "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=" + +# Build LUT from a charset string into base64_lut. +# base64_lut[costume_number_of_char] = base64 value (0-63), or 255 for '=' +proc base64_build_lut charset { + delete base64_lut; + # Fill 256 slots with 255 (invalid) + local j = 0; + repeat 256 { + add 255 to base64_lut; + j++; + } + # Map each charset char to its index (0-63), slot 65 (index 64) is '=' -> 255 already + local idx = 0; + repeat 64 { + switch_costume $charset[1 + idx]; + base64_lut[costume_number()] = idx; + idx++; + } +} + +func base64_encode(charset) { + delete base64_strbuf; + local i = 1; + until i > length(base64_buffer) { + local a6 = base64_buffer[i] // 0b100; + local a2 = base64_buffer[i] % 0b100; + add $charset[1 + a6] to base64_strbuf; + i++; + if i <= length(base64_buffer) { + local b4hi = base64_buffer[i] // 0x10; + local b4lo = base64_buffer[i] % 0x10; + add $charset[1 + a2 * 0x10 + b4hi] to base64_strbuf; + i++; + if i <= length(base64_buffer) { + local c2 = base64_buffer[i] // 0b1000000; + local c6 = base64_buffer[i] % 0b1000000; + add $charset[1 + b4lo * 4 + c2] to base64_strbuf; + add $charset[1 + c6] to base64_strbuf; + i++; + } else { + add $charset[1 + b4lo * 4] to base64_strbuf; + add $charset[65] to base64_strbuf; + } + } else { + add $charset[1 + a2 * 0x10] to base64_strbuf; + add $charset[65] & $charset[65] to base64_strbuf; + } + } + return base64_strbuf; +} + +# Decode base64 string $data into base64_buffer. +# Call base64_build_lut with the appropriate charset before calling this. +# Appends decoded bytes to base64_buffer (clear it first if needed). +proc base64_decode data { + local len = length($data); + local i = 1; + until i > len { + # Read up to 4 base64 chars, get their 6-bit values via LUT + switch_costume $data[i]; + local v0 = base64_lut[costume_number()]; + i++; + + switch_costume $data[i]; + local v1 = base64_lut[costume_number()]; + i++; + + # Byte 1: high 6 bits from v0, low 2 bits from v1 high + add v0 * 4 + v1 // 16 to base64_buffer; + + # Check for padding or end: if 3rd char is '=' or beyond end, stop + if i > len { + stop_this_script; + } + switch_costume $data[i]; + local v2 = base64_lut[costume_number()]; + i++; + + if v2 == 255 { + # Padding '=' — only 2 encoded chars, 1 decoded byte (already added) + stop_this_script; + } + + # Byte 2: low 4 bits of v1, high 4 bits of v2 + add (v1 % 16) * 16 + v2 // 4 to base64_buffer; + + if i > len { + stop_this_script; + } + switch_costume $data[i]; + local v3 = base64_lut[costume_number()]; + i++; + + if v3 == 255 { + # Padding '=' — only 3 encoded chars, 2 decoded bytes + stop_this_script; + } + + # Byte 3: low 2 bits of v2, all 6 bits of v3 + add (v2 % 4) * 64 + v3 to base64_buffer; + } +} diff --git a/bitwise.gs b/bitwise.gs new file mode 100644 index 0000000..aa4e67f --- /dev/null +++ b/bitwise.gs @@ -0,0 +1,72 @@ +list xor4 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13, 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11, 5, 4, 7, 6, 1, 0, 3, 2, 13, 12, 15, 14, 9, 8, 11, 10, 6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 9, 8, 11, 10, 13, 12, 15, 14, 1, 0, 3, 2, 5, 4, 7, 6, 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5, 11, 10, 9, 8, 15, 14, 13, 12, 3, 2, 1, 0, 7, 6, 5, 4, 12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3, 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]; +list and4 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4, 0, 1, 0, 1, 4, 5, 4, 5, 0, 1, 0, 1, 4, 5, 4, 5, 0, 0, 2, 2, 4, 4, 6, 6, 0, 0, 2, 2, 4, 4, 6, 6, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 0, 1, 0, 1, 0, 1, 8, 9, 8, 9, 8, 9, 8, 9, 0, 0, 2, 2, 0, 0, 2, 2, 8, 8, 10, 10, 8, 8, 10, 10, 0, 1, 2, 3, 0, 1, 2, 3, 8, 9, 10, 11, 8, 9, 10, 11, 0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12, 0, 1, 0, 1, 4, 5, 4, 5, 8, 9, 8, 9, 12, 13, 12, 13, 0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; +list or4 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15, 2, 3, 2, 3, 6, 7, 6, 7, 10, 11, 10, 11, 14, 15, 14, 15, 3, 3, 3, 3, 7, 7, 7, 7, 11, 11, 11, 11, 15, 15, 15, 15, 4, 5, 6, 7, 4, 5, 6, 7, 12, 13, 14, 15, 12, 13, 14, 15, 5, 5, 7, 7, 5, 5, 7, 7, 13, 13, 15, 15, 13, 13, 15, 15, 6, 7, 6, 7, 6, 7, 6, 7, 14, 15, 14, 15, 14, 15, 14, 15, 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, 8, 9, 10, 11, 12, 13, 14, 15, 8, 9, 10, 11, 12, 13, 14, 15, 9, 9, 11, 11, 13, 13, 15, 15, 9, 9, 11, 11, 13, 13, 15, 15, 10, 11, 10, 11, 14, 15, 14, 15, 10, 11, 10, 11, 14, 15, 14, 15, 11, 11, 11, 11, 15, 15, 15, 15, 11, 11, 11, 11, 15, 15, 15, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 13, 13, 15, 15, 13, 13, 15, 15, 13, 13, 15, 15, 13, 13, 15, 15, 14, 15, 14, 15, 14, 15, 14, 15, 14, 15, 14, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15]; + +%define XOR4(A, B) xor4[1+(A)*0x10+(B)] + +func xor8(a, b) { + return XOR4($a//0x10, $b//0x10)*0x10 + XOR4($a%0x10, $b%0x10); +} + +func xor16(a, b) { + return xor8($a//0x100, $b//0x100)*0x100 + xor8($a%0x100, $b%0x100); +} + +func xor32(a, b) { + return xor16($a//0x10000, $b//0x10000)*0x10000 + xor16($a%0x10000, $b%0x10000); +} + +%define AND4(A, B) and4[1+(A)*0x10+(B)] +%define OR4(A, B) or4[1+(A)*0x10+(B)] + +func and8(a, b) { + return AND4($a//0x10, $b//0x10)*0x10 + AND4($a%0x10, $b%0x10); +} + +func and16(a, b) { + return and8($a//0x100, $b//0x100)*0x100 + and8($a%0x100, $b%0x100); +} + +func and32(a, b) { + return and16($a//0x10000, $b//0x10000)*0x10000 + and16($a%0x10000, $b%0x10000); +} + +func or8(a, b) { + return OR4($a//0x10, $b//0x10)*0x10 + OR4($a%0x10, $b%0x10); +} + +func or16(a, b) { + return or8($a//0x100, $b//0x100)*0x100 + or8($a%0x100, $b%0x100); +} + +func or32(a, b) { + return or16($a//0x10000, $b//0x10000)*0x10000 + or16($a%0x10000, $b%0x10000); +} + +%define NOT4(A) XOR4((A), 0xF) + +func not8(a) { + return xor8($a, 0xFF); +} + +func not16(a) { + return xor16($a, 0xFFFF); +} + +func not32(a) { + return xor32($a, 0xFFFFFFFF); +} + +%define ADD32(A,B) (((A)+(B))%0x100000000) + +func add32(a, b) { + return ($a + $b) % 0x100000000; +} + +%define ROL32(A) ((((A)*2)%0x100000000)+((A) > 0x7FFFFFFF)) + +func rol32(a, b) { + local a = $a; + repeat $b % 32 { a = ROL32(a); } + return a; +} diff --git a/bytes.gs b/bytes.gs new file mode 100644 index 0000000..7574877 --- /dev/null +++ b/bytes.gs @@ -0,0 +1,54 @@ +list bytes_strbuf; + +list bytes_hex_table = ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"]; + +%define BYTES_ENCODE_ASCII(LIST) \ + local i = 1; \ + repeat length($text) { \ + switch_costume $text[i]; \ + add costume_number()+31 to LIST; \ + i++; \ + } + +%define BYTES_DECODE_ASCII(LIST) \ + delete bytes_strbuf; \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end < 0 { \ + end = length(LIST) + end + 1; \ + } \ + local i = start; \ + repeat end - start + 1 { \ + switch_costume LIST[i]-31; \ + add costume_name() to bytes_strbuf; \ + i++; \ + } \ + return bytes_strbuf; + +%define BYTES_ENCODE_HEX(LIST) \ + local i = 1; \ + repeat length($text)//2 { \ + add ("0x"&$text[i]&$text[i+1]) to LIST; \ + i+=2; \ + } + +%define BYTES_DECODE_HEX(LIST) \ + delete bytes_strbuf; \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end < 0 { \ + end = length(LIST) + end + 1; \ + } \ + local i = start; \ + repeat end - start + 1 { \ + add bytes_hex_table[1+LIST[i]][1] to bytes_strbuf; \ + add bytes_hex_table[1+LIST[i]][2] to bytes_strbuf; \ + i++; \ + } \ + return bytes_strbuf; diff --git a/cmd.gs b/cmd.gs deleted file mode 100644 index fc596ad..0000000 --- a/cmd.gs +++ /dev/null @@ -1,65 +0,0 @@ -list cmd_args; - -func cmd_next(start, cmd) { - delete cmd_args; - local key = ""; - local single_quote = false; - local double_quote = false; - local i = $start; - until i > length($cmd) { - if single_quote { - if $cmd[i] == "'" and $cmd[i-1] != "\\" { - single_quote = false; - add key to cmd_args; - key = ""; - } - else { - key &= $cmd[i]; - } - } - elif double_quote { - if $cmd[i] == "\"" { - double_quote = false; - add key to cmd_args; - key = ""; - } - elif $cmd[i] == "\\" { - i++; - key &= $cmd[i]; - } - else { - key &= $cmd[i]; - } - } - elif $cmd[i] == "\"" { - double_quote = true; - } - elif $cmd[i] == "'" { - single_quote = true; - } - elif $cmd[i] == " " { - if key != "" { - add key to cmd_args; - key = ""; - } - } - elif $cmd[i] == ";" { - if key != "" { - add key to cmd_args; - } - return i+1; - } - elif $cmd[i] == "\\" { - i++; - key &= $cmd[i]; - } - else { - key &= $cmd[i]; - } - i++; - } - if key != "" { - add key to cmd_args; - } - return 0; -} diff --git a/cskv.gs b/cskv.gs deleted file mode 100644 index ec3f72d..0000000 --- a/cskv.gs +++ /dev/null @@ -1,74 +0,0 @@ -list cskv; -list cskv_keys; -list cskv_key_map; - -%define CSKV_GET_INDEX(key) cskv_key_map[(key) in cskv_keys] -%define CSKV_GET(key) cskv[cskv_key_map[(key) in cskv_keys]] - -proc cskv_unpack text { - delete cskv; - local token = ""; - local i = 0; - until i > length($text) { - if $text[i] == "\\" { - if $text[i+1] in ",:\\" { - token &= $text[i+1]; - i++; - } else { - token &= "\\"; - } - } elif $text[i] == "," { - add token to cskv; - token = ""; - } elif $text[i] == ":" { - add token to cskv_keys; - add 1+length(cskv) to cskv_key_map; - token = ""; - } else { - token &= $text[i]; - } - i++; - } - add token to cskv; -} - -func cskv_pack() { - local result = ""; - local i = 1; - until i > length(cskv_keys) { - result &= cskv_keys[i] & ":"; - if (cskv_key_map[i+1] - cskv_key_map[i]) > 2 { - result &= cskv[cskv_key_map[i]] & ","; - local j = 1; - until j > cskv[cskv_key_map[i]] { - local element = cskv[cskv_key_map[i] + j]; - local k = 1; - until k > length(element) { - if element[k] in "\\,:" { - result &= "\\"; - } - result &= element[k]; - k++; - } - j++; - if i < length(cskv_keys) or j < cskv[cskv_key_map[i]] { - result &= ","; - } - } - } else { - local j = 1; - until j > length(cskv[cskv_key_map[i]]) { - if cskv[cskv_key_map[i]][j] in "\\,:" { - result &= "\\"; - } - result &= cskv[cskv_key_map[i]][j]; - j++; - } - if i < length(cskv_keys) { - result &= ","; - } - } - i++; - } - return result; -} diff --git a/emoji.gs b/emoji.gs deleted file mode 100644 index 524a82f..0000000 --- a/emoji.gs +++ /dev/null @@ -1,11452 +0,0 @@ -# Return the emoji for the shortcode `NAME`. -%define EMOJI(NAME) emoji_values[(NAME) in emoji_names] - -# List of all emoji shortcodes. -list emoji_names = [ - "100", - "1234", - "soccer", - "soccer_ball", - "basketball", - "football", - "baseball", - "softball", - "tennis", - "volleyball", - "rugby_football", - "flying_disc", - "8ball", - "yo_yo", - "ping_pong", - "table_tennis", - "badminton", - "hockey", - "ice_hockey", - "field_hockey", - "lacrosse", - "cricket_game", - "cricket_bat_ball", - "boomerang", - "goal", - "goal_net", - "golf", - "flag_in_hole", - "kite", - "playground_slide", - "bow_and_arrow", - "archery", - "fishing_pole_and_fish", - "fishing_pole", - "diving_mask", - "boxing_glove", - "boxing_gloves", - "martial_arts_uniform", - "karate_uniform", - "running_shirt_with_sash", - "running_shirt", - "skateboard", - "roller_skate", - "sled", - "ice_skate", - "curling_stone", - "ski", - "skis", - "skier", - "snowboarder", - "snowboarder_tone1", - "snowboarder_light_skin_tone", - "snowboarder_tone2", - "snowboarder_medium_light_skin_tone", - "snowboarder_tone3", - "snowboarder_medium_skin_tone", - "snowboarder_tone4", - "snowboarder_medium_dark_skin_tone", - "snowboarder_tone5", - "snowboarder_dark_skin_tone", - "parachute", - "person_lifting_weights", - "lifter", - "weight_lifter", - "person_lifting_weights_tone1", - "lifter_tone1", - "weight_lifter_tone1", - "person_lifting_weights_tone2", - "lifter_tone2", - "weight_lifter_tone2", - "person_lifting_weights_tone3", - "lifter_tone3", - "weight_lifter_tone3", - "person_lifting_weights_tone4", - "lifter_tone4", - "weight_lifter_tone4", - "person_lifting_weights_tone5", - "lifter_tone5", - "weight_lifter_tone5", - "woman_lifting_weights", - "woman_lifting_weights_tone1", - "woman_lifting_weights_light_skin_tone", - "woman_lifting_weights_tone2", - "woman_lifting_weights_medium_light_skin_tone", - "woman_lifting_weights_tone3", - "woman_lifting_weights_medium_skin_tone", - "woman_lifting_weights_tone4", - "woman_lifting_weights_medium_dark_skin_tone", - "woman_lifting_weights_tone5", - "woman_lifting_weights_dark_skin_tone", - "man_lifting_weights", - "man_lifting_weights_tone1", - "man_lifting_weights_light_skin_tone", - "man_lifting_weights_tone2", - "man_lifting_weights_medium_light_skin_tone", - "man_lifting_weights_tone3", - "man_lifting_weights_medium_skin_tone", - "man_lifting_weights_tone4", - "man_lifting_weights_medium_dark_skin_tone", - "man_lifting_weights_tone5", - "man_lifting_weights_dark_skin_tone", - "people_wrestling", - "wrestlers", - "wrestling", - "women_wrestling", - "men_wrestling", - "person_doing_cartwheel", - "cartwheel", - "person_doing_cartwheel_tone1", - "cartwheel_tone1", - "person_doing_cartwheel_tone2", - "cartwheel_tone2", - "person_doing_cartwheel_tone3", - "cartwheel_tone3", - "person_doing_cartwheel_tone4", - "cartwheel_tone4", - "person_doing_cartwheel_tone5", - "cartwheel_tone5", - "woman_cartwheeling", - "woman_cartwheeling_tone1", - "woman_cartwheeling_light_skin_tone", - "woman_cartwheeling_tone2", - "woman_cartwheeling_medium_light_skin_tone", - "woman_cartwheeling_tone3", - "woman_cartwheeling_medium_skin_tone", - "woman_cartwheeling_tone4", - "woman_cartwheeling_medium_dark_skin_tone", - "woman_cartwheeling_tone5", - "woman_cartwheeling_dark_skin_tone", - "man_cartwheeling", - "man_cartwheeling_tone1", - "man_cartwheeling_light_skin_tone", - "man_cartwheeling_tone2", - "man_cartwheeling_medium_light_skin_tone", - "man_cartwheeling_tone3", - "man_cartwheeling_medium_skin_tone", - "man_cartwheeling_tone4", - "man_cartwheeling_medium_dark_skin_tone", - "man_cartwheeling_tone5", - "man_cartwheeling_dark_skin_tone", - "person_bouncing_ball", - "basketball_player", - "person_with_ball", - "person_bouncing_ball_tone1", - "basketball_player_tone1", - "person_with_ball_tone1", - "person_bouncing_ball_tone2", - "basketball_player_tone2", - "person_with_ball_tone2", - "person_bouncing_ball_tone3", - "basketball_player_tone3", - "person_with_ball_tone3", - "person_bouncing_ball_tone4", - "basketball_player_tone4", - "person_with_ball_tone4", - "person_bouncing_ball_tone5", - "basketball_player_tone5", - "person_with_ball_tone5", - "woman_bouncing_ball", - "woman_bouncing_ball_tone1", - "woman_bouncing_ball_light_skin_tone", - "woman_bouncing_ball_tone2", - "woman_bouncing_ball_medium_light_skin_tone", - "woman_bouncing_ball_tone3", - "woman_bouncing_ball_medium_skin_tone", - "woman_bouncing_ball_tone4", - "woman_bouncing_ball_medium_dark_skin_tone", - "woman_bouncing_ball_tone5", - "woman_bouncing_ball_dark_skin_tone", - "man_bouncing_ball", - "man_bouncing_ball_tone1", - "man_bouncing_ball_light_skin_tone", - "man_bouncing_ball_tone2", - "man_bouncing_ball_medium_light_skin_tone", - "man_bouncing_ball_tone3", - "man_bouncing_ball_medium_skin_tone", - "man_bouncing_ball_tone4", - "man_bouncing_ball_medium_dark_skin_tone", - "man_bouncing_ball_tone5", - "man_bouncing_ball_dark_skin_tone", - "person_fencing", - "fencer", - "fencing", - "person_playing_handball", - "handball", - "person_playing_handball_tone1", - "handball_tone1", - "person_playing_handball_tone2", - "handball_tone2", - "person_playing_handball_tone3", - "handball_tone3", - "person_playing_handball_tone4", - "handball_tone4", - "person_playing_handball_tone5", - "handball_tone5", - "woman_playing_handball", - "woman_playing_handball_tone1", - "woman_playing_handball_light_skin_tone", - "woman_playing_handball_tone2", - "woman_playing_handball_medium_light_skin_tone", - "woman_playing_handball_tone3", - "woman_playing_handball_medium_skin_tone", - "woman_playing_handball_tone4", - "woman_playing_handball_medium_dark_skin_tone", - "woman_playing_handball_tone5", - "woman_playing_handball_dark_skin_tone", - "man_playing_handball", - "man_playing_handball_tone1", - "man_playing_handball_light_skin_tone", - "man_playing_handball_tone2", - "man_playing_handball_medium_light_skin_tone", - "man_playing_handball_tone3", - "man_playing_handball_medium_skin_tone", - "man_playing_handball_tone4", - "man_playing_handball_medium_dark_skin_tone", - "man_playing_handball_tone5", - "man_playing_handball_dark_skin_tone", - "person_golfing", - "golfer", - "person_golfing_tone1", - "person_golfing_light_skin_tone", - "person_golfing_tone2", - "person_golfing_medium_light_skin_tone", - "person_golfing_tone3", - "person_golfing_medium_skin_tone", - "person_golfing_tone4", - "person_golfing_medium_dark_skin_tone", - "person_golfing_tone5", - "person_golfing_dark_skin_tone", - "woman_golfing", - "woman_golfing_tone1", - "woman_golfing_light_skin_tone", - "woman_golfing_tone2", - "woman_golfing_medium_light_skin_tone", - "woman_golfing_tone3", - "woman_golfing_medium_skin_tone", - "woman_golfing_tone4", - "woman_golfing_medium_dark_skin_tone", - "woman_golfing_tone5", - "woman_golfing_dark_skin_tone", - "man_golfing", - "man_golfing_tone1", - "man_golfing_light_skin_tone", - "man_golfing_tone2", - "man_golfing_medium_light_skin_tone", - "man_golfing_tone3", - "man_golfing_medium_skin_tone", - "man_golfing_tone4", - "man_golfing_medium_dark_skin_tone", - "man_golfing_tone5", - "man_golfing_dark_skin_tone", - "horse_racing", - "horse_racing_tone1", - "horse_racing_tone2", - "horse_racing_tone3", - "horse_racing_tone4", - "horse_racing_tone5", - "person_in_lotus_position", - "person_in_lotus_position_tone1", - "person_in_lotus_position_light_skin_tone", - "person_in_lotus_position_tone2", - "person_in_lotus_position_medium_light_skin_tone", - "person_in_lotus_position_tone3", - "person_in_lotus_position_medium_skin_tone", - "person_in_lotus_position_tone4", - "person_in_lotus_position_medium_dark_skin_tone", - "person_in_lotus_position_tone5", - "person_in_lotus_position_dark_skin_tone", - "woman_in_lotus_position", - "woman_in_lotus_position_tone1", - "woman_in_lotus_position_light_skin_tone", - "woman_in_lotus_position_tone2", - "woman_in_lotus_position_medium_light_skin_tone", - "woman_in_lotus_position_tone3", - "woman_in_lotus_position_medium_skin_tone", - "woman_in_lotus_position_tone4", - "woman_in_lotus_position_medium_dark_skin_tone", - "woman_in_lotus_position_tone5", - "woman_in_lotus_position_dark_skin_tone", - "man_in_lotus_position", - "man_in_lotus_position_tone1", - "man_in_lotus_position_light_skin_tone", - "man_in_lotus_position_tone2", - "man_in_lotus_position_medium_light_skin_tone", - "man_in_lotus_position_tone3", - "man_in_lotus_position_medium_skin_tone", - "man_in_lotus_position_tone4", - "man_in_lotus_position_medium_dark_skin_tone", - "man_in_lotus_position_tone5", - "man_in_lotus_position_dark_skin_tone", - "person_surfing", - "surfer", - "person_surfing_tone1", - "surfer_tone1", - "person_surfing_tone2", - "surfer_tone2", - "person_surfing_tone3", - "surfer_tone3", - "person_surfing_tone4", - "surfer_tone4", - "person_surfing_tone5", - "surfer_tone5", - "woman_surfing", - "woman_surfing_tone1", - "woman_surfing_light_skin_tone", - "woman_surfing_tone2", - "woman_surfing_medium_light_skin_tone", - "woman_surfing_tone3", - "woman_surfing_medium_skin_tone", - "woman_surfing_tone4", - "woman_surfing_medium_dark_skin_tone", - "woman_surfing_tone5", - "woman_surfing_dark_skin_tone", - "man_surfing", - "man_surfing_tone1", - "man_surfing_light_skin_tone", - "man_surfing_tone2", - "man_surfing_medium_light_skin_tone", - "man_surfing_tone3", - "man_surfing_medium_skin_tone", - "man_surfing_tone4", - "man_surfing_medium_dark_skin_tone", - "man_surfing_tone5", - "man_surfing_dark_skin_tone", - "person_swimming", - "swimmer", - "person_swimming_tone1", - "swimmer_tone1", - "person_swimming_tone2", - "swimmer_tone2", - "person_swimming_tone3", - "swimmer_tone3", - "person_swimming_tone4", - "swimmer_tone4", - "person_swimming_tone5", - "swimmer_tone5", - "woman_swimming", - "woman_swimming_tone1", - "woman_swimming_light_skin_tone", - "woman_swimming_tone2", - "woman_swimming_medium_light_skin_tone", - "woman_swimming_tone3", - "woman_swimming_medium_skin_tone", - "woman_swimming_tone4", - "woman_swimming_medium_dark_skin_tone", - "woman_swimming_tone5", - "woman_swimming_dark_skin_tone", - "man_swimming", - "man_swimming_tone1", - "man_swimming_light_skin_tone", - "man_swimming_tone2", - "man_swimming_medium_light_skin_tone", - "man_swimming_tone3", - "man_swimming_medium_skin_tone", - "man_swimming_tone4", - "man_swimming_medium_dark_skin_tone", - "man_swimming_tone5", - "man_swimming_dark_skin_tone", - "person_playing_water_polo", - "water_polo", - "person_playing_water_polo_tone1", - "water_polo_tone1", - "person_playing_water_polo_tone2", - "water_polo_tone2", - "person_playing_water_polo_tone3", - "water_polo_tone3", - "person_playing_water_polo_tone4", - "water_polo_tone4", - "person_playing_water_polo_tone5", - "water_polo_tone5", - "woman_playing_water_polo", - "woman_playing_water_polo_tone1", - "woman_playing_water_polo_light_skin_tone", - "woman_playing_water_polo_tone2", - "woman_playing_water_polo_medium_light_skin_tone", - "woman_playing_water_polo_tone3", - "woman_playing_water_polo_medium_skin_tone", - "woman_playing_water_polo_tone4", - "woman_playing_water_polo_medium_dark_skin_tone", - "woman_playing_water_polo_tone5", - "woman_playing_water_polo_dark_skin_tone", - "man_playing_water_polo", - "man_playing_water_polo_tone1", - "man_playing_water_polo_light_skin_tone", - "man_playing_water_polo_tone2", - "man_playing_water_polo_medium_light_skin_tone", - "man_playing_water_polo_tone3", - "man_playing_water_polo_medium_skin_tone", - "man_playing_water_polo_tone4", - "man_playing_water_polo_medium_dark_skin_tone", - "man_playing_water_polo_tone5", - "man_playing_water_polo_dark_skin_tone", - "person_rowing_boat", - "rowboat", - "person_rowing_boat_tone1", - "rowboat_tone1", - "person_rowing_boat_tone2", - "rowboat_tone2", - "person_rowing_boat_tone3", - "rowboat_tone3", - "person_rowing_boat_tone4", - "rowboat_tone4", - "person_rowing_boat_tone5", - "rowboat_tone5", - "woman_rowing_boat", - "woman_rowing_boat_tone1", - "woman_rowing_boat_light_skin_tone", - "woman_rowing_boat_tone2", - "woman_rowing_boat_medium_light_skin_tone", - "woman_rowing_boat_tone3", - "woman_rowing_boat_medium_skin_tone", - "woman_rowing_boat_tone4", - "woman_rowing_boat_medium_dark_skin_tone", - "woman_rowing_boat_tone5", - "woman_rowing_boat_dark_skin_tone", - "man_rowing_boat", - "man_rowing_boat_tone1", - "man_rowing_boat_light_skin_tone", - "man_rowing_boat_tone2", - "man_rowing_boat_medium_light_skin_tone", - "man_rowing_boat_tone3", - "man_rowing_boat_medium_skin_tone", - "man_rowing_boat_tone4", - "man_rowing_boat_medium_dark_skin_tone", - "man_rowing_boat_tone5", - "man_rowing_boat_dark_skin_tone", - "person_climbing", - "person_climbing_tone1", - "person_climbing_light_skin_tone", - "person_climbing_tone2", - "person_climbing_medium_light_skin_tone", - "person_climbing_tone3", - "person_climbing_medium_skin_tone", - "person_climbing_tone4", - "person_climbing_medium_dark_skin_tone", - "person_climbing_tone5", - "person_climbing_dark_skin_tone", - "woman_climbing", - "woman_climbing_tone1", - "woman_climbing_light_skin_tone", - "woman_climbing_tone2", - "woman_climbing_medium_light_skin_tone", - "woman_climbing_tone3", - "woman_climbing_medium_skin_tone", - "woman_climbing_tone4", - "woman_climbing_medium_dark_skin_tone", - "woman_climbing_tone5", - "woman_climbing_dark_skin_tone", - "man_climbing", - "man_climbing_tone1", - "man_climbing_light_skin_tone", - "man_climbing_tone2", - "man_climbing_medium_light_skin_tone", - "man_climbing_tone3", - "man_climbing_medium_skin_tone", - "man_climbing_tone4", - "man_climbing_medium_dark_skin_tone", - "man_climbing_tone5", - "man_climbing_dark_skin_tone", - "person_mountain_biking", - "mountain_bicyclist", - "person_mountain_biking_tone1", - "mountain_bicyclist_tone1", - "person_mountain_biking_tone2", - "mountain_bicyclist_tone2", - "person_mountain_biking_tone3", - "mountain_bicyclist_tone3", - "person_mountain_biking_tone4", - "mountain_bicyclist_tone4", - "person_mountain_biking_tone5", - "mountain_bicyclist_tone5", - "woman_mountain_biking", - "woman_mountain_biking_tone1", - "woman_mountain_biking_light_skin_tone", - "woman_mountain_biking_tone2", - "woman_mountain_biking_medium_light_skin_tone", - "woman_mountain_biking_tone3", - "woman_mountain_biking_medium_skin_tone", - "woman_mountain_biking_tone4", - "woman_mountain_biking_medium_dark_skin_tone", - "woman_mountain_biking_tone5", - "woman_mountain_biking_dark_skin_tone", - "man_mountain_biking", - "man_mountain_biking_tone1", - "man_mountain_biking_light_skin_tone", - "man_mountain_biking_tone2", - "man_mountain_biking_medium_light_skin_tone", - "man_mountain_biking_tone3", - "man_mountain_biking_medium_skin_tone", - "man_mountain_biking_tone4", - "man_mountain_biking_medium_dark_skin_tone", - "man_mountain_biking_tone5", - "man_mountain_biking_dark_skin_tone", - "person_biking", - "bicyclist", - "person_biking_tone1", - "bicyclist_tone1", - "person_biking_tone2", - "bicyclist_tone2", - "person_biking_tone3", - "bicyclist_tone3", - "person_biking_tone4", - "bicyclist_tone4", - "person_biking_tone5", - "bicyclist_tone5", - "woman_biking", - "woman_biking_tone1", - "woman_biking_light_skin_tone", - "woman_biking_tone2", - "woman_biking_medium_light_skin_tone", - "woman_biking_tone3", - "woman_biking_medium_skin_tone", - "woman_biking_tone4", - "woman_biking_medium_dark_skin_tone", - "woman_biking_tone5", - "woman_biking_dark_skin_tone", - "man_biking", - "man_biking_tone1", - "man_biking_light_skin_tone", - "man_biking_tone2", - "man_biking_medium_light_skin_tone", - "man_biking_tone3", - "man_biking_medium_skin_tone", - "man_biking_tone4", - "man_biking_medium_dark_skin_tone", - "man_biking_tone5", - "man_biking_dark_skin_tone", - "trophy", - "first_place", - "first_place_medal", - "second_place", - "second_place_medal", - "third_place", - "third_place_medal", - "medal", - "sports_medal", - "military_medal", - "rosette", - "reminder_ribbon", - "ticket", - "tickets", - "admission_tickets", - "circus_tent", - "person_juggling", - "juggling", - "juggler", - "person_juggling_tone1", - "juggling_tone1", - "juggler_tone1", - "person_juggling_tone2", - "juggling_tone2", - "juggler_tone2", - "person_juggling_tone3", - "juggling_tone3", - "juggler_tone3", - "person_juggling_tone4", - "juggling_tone4", - "juggler_tone4", - "person_juggling_tone5", - "juggling_tone5", - "juggler_tone5", - "woman_juggling", - "woman_juggling_tone1", - "woman_juggling_light_skin_tone", - "woman_juggling_tone2", - "woman_juggling_medium_light_skin_tone", - "woman_juggling_tone3", - "woman_juggling_medium_skin_tone", - "woman_juggling_tone4", - "woman_juggling_medium_dark_skin_tone", - "woman_juggling_tone5", - "woman_juggling_dark_skin_tone", - "man_juggling", - "man_juggling_tone1", - "man_juggling_light_skin_tone", - "man_juggling_tone2", - "man_juggling_medium_light_skin_tone", - "man_juggling_tone3", - "man_juggling_medium_skin_tone", - "man_juggling_tone4", - "man_juggling_medium_dark_skin_tone", - "man_juggling_tone5", - "man_juggling_dark_skin_tone", - "performing_arts", - "ballet_shoes", - "art", - "clapper", - "clapper_board", - "microphone", - "headphones", - "headphone", - "musical_score", - "musical_keyboard", - "maracas", - "drum", - "drum_with_drumsticks", - "long_drum", - "saxophone", - "trumpet", - "accordion", - "guitar", - "banjo", - "violin", - "flute", - "game_die", - "chess_pawn", - "dart", - "direct_hit", - "bowling", - "video_game", - "slot_machine", - "jigsaw", - "puzzle_piece", - "flag_white", - "flag_black", - "pirate_flag", - "checkered_flag", - "triangular_flag_on_post", - "rainbow_flag", - "gay_pride_flag", - "transgender_flag", - "united_nations", - "flag_af", - "flag_ax", - "flag_al", - "flag_dz", - "flag_as", - "flag_ad", - "flag_ao", - "flag_ai", - "flag_aq", - "flag_ag", - "flag_ar", - "flag_am", - "flag_aw", - "flag_au", - "flag_at", - "flag_az", - "flag_bs", - "flag_bh", - "flag_bd", - "flag_bb", - "flag_by", - "flag_be", - "flag_bz", - "flag_bj", - "flag_bm", - "flag_bt", - "flag_bo", - "flag_ba", - "flag_bw", - "flag_br", - "flag_io", - "flag_vg", - "flag_bn", - "flag_bg", - "flag_bf", - "flag_bi", - "flag_kh", - "flag_cm", - "flag_ca", - "flag_ic", - "flag_cv", - "flag_bq", - "flag_ky", - "flag_cf", - "flag_td", - "flag_cl", - "flag_cn", - "flag_cx", - "flag_cc", - "flag_co", - "flag_km", - "flag_cg", - "flag_cd", - "flag_ck", - "flag_cr", - "flag_ci", - "flag_hr", - "flag_cu", - "flag_cw", - "flag_cy", - "flag_cz", - "flag_dk", - "flag_dj", - "flag_dm", - "flag_do", - "flag_ec", - "flag_eg", - "flag_sv", - "flag_gq", - "flag_er", - "flag_ee", - "flag_et", - "flag_eu", - "flag_fk", - "flag_fo", - "flag_fj", - "flag_fi", - "flag_fr", - "flag_gf", - "flag_pf", - "flag_tf", - "flag_ga", - "flag_gm", - "flag_ge", - "flag_de", - "flag_gh", - "flag_gi", - "flag_gr", - "flag_gl", - "flag_gd", - "flag_gp", - "flag_gu", - "flag_gt", - "flag_gg", - "flag_gn", - "flag_gw", - "flag_gy", - "flag_ht", - "flag_hn", - "flag_hk", - "flag_hu", - "flag_is", - "flag_in", - "flag_id", - "flag_ir", - "flag_iq", - "flag_ie", - "flag_im", - "flag_il", - "flag_it", - "flag_jm", - "flag_jp", - "crossed_flags", - "flag_je", - "flag_jo", - "flag_kz", - "flag_ke", - "flag_ki", - "flag_xk", - "flag_kw", - "flag_kg", - "flag_la", - "flag_lv", - "flag_lb", - "flag_ls", - "flag_lr", - "flag_ly", - "flag_li", - "flag_lt", - "flag_lu", - "flag_mo", - "flag_mk", - "flag_mg", - "flag_mw", - "flag_my", - "flag_mv", - "flag_ml", - "flag_mt", - "flag_mh", - "flag_mq", - "flag_mr", - "flag_mu", - "flag_yt", - "flag_mx", - "flag_fm", - "flag_md", - "flag_mc", - "flag_mn", - "flag_me", - "flag_ms", - "flag_ma", - "flag_mz", - "flag_mm", - "flag_na", - "flag_nr", - "flag_np", - "flag_nl", - "flag_nc", - "flag_nz", - "flag_ni", - "flag_ne", - "flag_ng", - "flag_nu", - "flag_nf", - "flag_kp", - "flag_mp", - "flag_no", - "flag_om", - "flag_pk", - "flag_pw", - "flag_ps", - "flag_pa", - "flag_pg", - "flag_py", - "flag_pe", - "flag_ph", - "flag_pn", - "flag_pl", - "flag_pt", - "flag_pr", - "flag_qa", - "flag_re", - "flag_ro", - "flag_ru", - "flag_rw", - "flag_ws", - "flag_sm", - "flag_st", - "flag_sa", - "flag_sn", - "flag_rs", - "flag_sc", - "flag_sl", - "flag_sg", - "flag_sx", - "flag_sk", - "flag_si", - "flag_gs", - "flag_sb", - "flag_so", - "flag_za", - "flag_kr", - "flag_ss", - "flag_es", - "flag_lk", - "flag_bl", - "flag_sh", - "flag_kn", - "flag_lc", - "flag_pm", - "flag_vc", - "flag_sd", - "flag_sr", - "flag_sz", - "flag_se", - "flag_ch", - "flag_sy", - "flag_tw", - "flag_tj", - "flag_tz", - "flag_th", - "flag_tl", - "flag_tg", - "flag_tk", - "flag_to", - "flag_tt", - "flag_tn", - "flag_tr", - "flag_tm", - "flag_tc", - "flag_vi", - "flag_tv", - "flag_ug", - "flag_ua", - "flag_ae", - "flag_gb", - "england", - "scotland", - "wales", - "flag_us", - "flag_uy", - "flag_uz", - "flag_vu", - "flag_va", - "flag_ve", - "flag_vn", - "flag_wf", - "flag_eh", - "flag_ye", - "flag_zm", - "flag_zw", - "flag_ac", - "flag_bv", - "flag_cp", - "flag_ea", - "flag_dg", - "flag_hm", - "flag_mf", - "flag_sj", - "flag_ta", - "flag_um", - "green_apple", - "apple", - "red_apple", - "pear", - "tangerine", - "lemon", - "banana", - "watermelon", - "grapes", - "strawberry", - "blueberries", - "melon", - "cherries", - "peach", - "mango", - "pineapple", - "coconut", - "kiwi", - "kiwifruit", - "kiwi_fruit", - "tomato", - "eggplant", - "avocado", - "pea_pod", - "broccoli", - "leafy_green", - "cucumber", - "hot_pepper", - "bell_pepper", - "corn", - "ear_of_corn", - "carrot", - "olive", - "garlic", - "onion", - "potato", - "sweet_potato", - "ginger_root", - "croissant", - "bagel", - "bread", - "french_bread", - "baguette_bread", - "pretzel", - "cheese", - "cheese_wedge", - "egg", - "cooking", - "butter", - "pancakes", - "waffle", - "bacon", - "cut_of_meat", - "poultry_leg", - "meat_on_bone", - "bone", - "hotdog", - "hot_dog", - "hamburger", - "fries", - "french_fries", - "pizza", - "flatbread", - "sandwich", - "stuffed_flatbread", - "stuffed_pita", - "falafel", - "taco", - "burrito", - "tamale", - "salad", - "green_salad", - "shallow_pan_of_food", - "paella", - "fondue", - "canned_food", - "jar", - "spaghetti", - "ramen", - "steaming_bowl", - "stew", - "pot_of_food", - "curry", - "curry_rice", - "sushi", - "bento", - "bento_box", - "dumpling", - "oyster", - "fried_shrimp", - "rice_ball", - "rice", - "cooked_rice", - "rice_cracker", - "fish_cake", - "fortune_cookie", - "moon_cake", - "oden", - "dango", - "shaved_ice", - "ice_cream", - "icecream", - "pie", - "cupcake", - "cake", - "shortcake", - "birthday", - "birthday_cake", - "custard", - "pudding", - "flan", - "lollipop", - "candy", - "chocolate_bar", - "popcorn", - "doughnut", - "cookie", - "chestnut", - "peanuts", - "shelled_peanut", - "beans", - "honey_pot", - "milk", - "glass_of_milk", - "pouring_liquid", - "baby_bottle", - "teapot", - "coffee", - "hot_beverage", - "tea", - "mate", - "beverage_box", - "cup_with_straw", - "bubble_tea", - "sake", - "beer", - "beer_mug", - "beers", - "champagne_glass", - "clinking_glass", - "wine_glass", - "tumbler_glass", - "whisky", - "cocktail", - "tropical_drink", - "champagne", - "bottle_with_popping_cork", - "ice_cube", - "spoon", - "fork_and_knife", - "fork_knife_plate", - "fork_and_knife_with_plate", - "bowl_with_spoon", - "takeout_box", - "chopsticks", - "salt", - "dog", - "dog_face", - "cat", - "cat_face", - "mouse", - "mouse_face", - "hamster", - "rabbit", - "rabbit_face", - "fox", - "fox_face", - "bear", - "panda_face", - "panda", - "polar_bear", - "koala", - "tiger", - "tiger_face", - "lion_face", - "lion", - "cow", - "cow_face", - "pig", - "pig_face", - "pig_nose", - "frog", - "monkey_face", - "see_no_evil", - "hear_no_evil", - "speak_no_evil", - "monkey", - "chicken", - "penguin", - "bird", - "baby_chick", - "hatching_chick", - "hatched_chick", - "goose", - "duck", - "black_bird", - "eagle", - "owl", - "bat", - "wolf", - "boar", - "horse", - "horse_face", - "unicorn", - "unicorn_face", - "moose", - "bee", - "honeybee", - "worm", - "bug", - "butterfly", - "snail", - "lady_beetle", - "ant", - "fly", - "beetle", - "cockroach", - "mosquito", - "cricket", - "spider", - "spider_web", - "scorpion", - "turtle", - "snake", - "lizard", - "t_rex", - "sauropod", - "octopus", - "squid", - "jellyfish", - "shrimp", - "lobster", - "crab", - "blowfish", - "tropical_fish", - "fish", - "dolphin", - "whale", - "whale2", - "shark", - "seal", - "crocodile", - "tiger2", - "leopard", - "zebra", - "gorilla", - "orangutan", - "mammoth", - "elephant", - "hippopotamus", - "rhino", - "rhinoceros", - "dromedary_camel", - "camel", - "giraffe", - "kangaroo", - "bison", - "water_buffalo", - "ox", - "cow2", - "donkey", - "racehorse", - "pig2", - "ram", - "sheep", - "ewe", - "llama", - "goat", - "deer", - "dog2", - "poodle", - "guide_dog", - "service_dog", - "cat2", - "black_cat", - "feather", - "wing", - "rooster", - "turkey", - "dodo", - "peacock", - "parrot", - "swan", - "flamingo", - "dove", - "dove_of_peace", - "rabbit2", - "raccoon", - "skunk", - "badger", - "beaver", - "otter", - "sloth", - "mouse2", - "rat", - "chipmunk", - "hedgehog", - "feet", - "paw_prints", - "dragon", - "dragon_face", - "cactus", - "christmas_tree", - "evergreen_tree", - "deciduous_tree", - "palm_tree", - "wood", - "seedling", - "herb", - "shamrock", - "four_leaf_clover", - "bamboo", - "potted_plant", - "tanabata_tree", - "leaves", - "fallen_leaf", - "maple_leaf", - "nest_with_eggs", - "empty_nest", - "mushroom", - "shell", - "spiral_shell", - "coral", - "rock", - "ear_of_rice", - "sheaf_of_rice", - "bouquet", - "tulip", - "rose", - "wilted_rose", - "wilted_flower", - "hyacinth", - "lotus", - "hibiscus", - "cherry_blossom", - "blossom", - "sunflower", - "sun_with_face", - "full_moon_with_face", - "first_quarter_moon_with_face", - "last_quarter_moon_with_face", - "new_moon_with_face", - "new_moon_face", - "full_moon", - "waning_gibbous_moon", - "last_quarter_moon", - "waning_crescent_moon", - "new_moon", - "waxing_crescent_moon", - "first_quarter_moon", - "waxing_gibbous_moon", - "crescent_moon", - "earth_americas", - "earth_africa", - "earth_asia", - "ringed_planet", - "dizzy", - "star", - "star2", - "glowing_star", - "sparkles", - "zap", - "high_voltage", - "comet", - "boom", - "collision", - "fire", - "flame", - "cloud_tornado", - "cloud_with_tornado", - "tornado", - "rainbow", - "sunny", - "sun", - "white_sun_small_cloud", - "white_sun_with_small_cloud", - "partly_sunny", - "white_sun_cloud", - "white_sun_behind_cloud", - "cloud", - "white_sun_rain_cloud", - "white_sun_behind_cloud_with_rain", - "cloud_rain", - "cloud_with_rain", - "thunder_cloud_rain", - "thunder_cloud_and_rain", - "cloud_lightning", - "cloud_with_lightning", - "cloud_snow", - "cloud_with_snow", - "snowflake", - "snowman2", - "snowman", - "wind_blowing_face", - "wind_face", - "dash", - "dashing_away", - "droplet", - "sweat_drops", - "bubbles", - "umbrella", - "umbrella2", - "ocean", - "water_wave", - "fog", - "watch", - "mobile_phone", - "iphone", - "calling", - "computer", - "keyboard", - "desktop", - "desktop_computer", - "printer", - "mouse_three_button", - "three_button_mouse", - "trackball", - "joystick", - "compression", - "clamp", - "minidisc", - "computer_disk", - "floppy_disk", - "cd", - "optical_disk", - "dvd", - "vhs", - "videocassette", - "camera", - "camera_with_flash", - "video_camera", - "movie_camera", - "projector", - "film_projector", - "film_frames", - "telephone_receiver", - "telephone", - "pager", - "fax", - "fax_machine", - "tv", - "television", - "radio", - "microphone2", - "studio_microphone", - "level_slider", - "control_knobs", - "compass", - "stopwatch", - "timer", - "timer_clock", - "alarm_clock", - "clock", - "mantlepiece_clock", - "hourglass", - "hourglass_flowing_sand", - "satellite", - "battery", - "low_battery", - "electric_plug", - "bulb", - "light_bulb", - "flashlight", - "candle", - "diya_lamp", - "fire_extinguisher", - "oil", - "oil_drum", - "money_with_wings", - "dollar", - "yen", - "yen_banknote", - "euro", - "euro_banknote", - "pound", - "coin", - "moneybag", - "money_bag", - "credit_card", - "identification_card", - "gem", - "gem_stone", - "scales", - "balance_scale", - "ladder", - "toolbox", - "screwdriver", - "wrench", - "hammer", - "hammer_pick", - "hammer_and_pick", - "tools", - "hammer_and_wrench", - "pick", - "carpentry_saw", - "nut_and_bolt", - "gear", - "mouse_trap", - "bricks", - "brick", - "chains", - "magnet", - "gun", - "pistol", - "bomb", - "firecracker", - "axe", - "knife", - "kitchen_knife", - "dagger", - "dagger_knife", - "crossed_swords", - "shield", - "smoking", - "cigarette", - "coffin", - "headstone", - "urn", - "funeral_urn", - "amphora", - "crystal_ball", - "prayer_beads", - "nazar_amulet", - "hamsa", - "barber", - "barber_pole", - "alembic", - "telescope", - "microscope", - "hole", - "x_ray", - "adhesive_bandage", - "stethoscope", - "pill", - "syringe", - "drop_of_blood", - "dna", - "microbe", - "petri_dish", - "test_tube", - "thermometer", - "broom", - "plunger", - "basket", - "roll_of_paper", - "toilet", - "potable_water", - "shower", - "bathtub", - "bath", - "bath_tone1", - "bath_tone2", - "bath_tone3", - "bath_tone4", - "bath_tone5", - "soap", - "toothbrush", - "razor", - "hair_pick", - "sponge", - "bucket", - "squeeze_bottle", - "lotion_bottle", - "bellhop", - "bellhop_bell", - "key", - "key2", - "old_key", - "door", - "chair", - "couch", - "couch_and_lamp", - "bed", - "sleeping_accommodation", - "person_in_bed", - "person_in_bed_tone1", - "person_in_bed_light_skin_tone", - "person_in_bed_tone2", - "person_in_bed_medium_light_skin_tone", - "person_in_bed_tone3", - "person_in_bed_medium_skin_tone", - "person_in_bed_tone4", - "person_in_bed_medium_dark_skin_tone", - "person_in_bed_tone5", - "person_in_bed_dark_skin_tone", - "teddy_bear", - "nesting_dolls", - "frame_photo", - "frame_with_picture", - "mirror", - "window", - "shopping_bags", - "shopping_cart", - "shopping_trolley", - "gift", - "wrapped_gift", - "balloon", - "flags", - "carp_streamer", - "ribbon", - "magic_wand", - "piñata", - "confetti_ball", - "tada", - "party_popper", - "dolls", - "folding_hand_fan", - "izakaya_lantern", - "wind_chime", - "mirror_ball", - "red_envelope", - "envelope", - "envelope_with_arrow", - "incoming_envelope", - "e_mail", - "email", - "love_letter", - "inbox_tray", - "outbox_tray", - "package", - "label", - "placard", - "mailbox_closed", - "mailbox", - "mailbox_with_mail", - "mailbox_with_no_mail", - "postbox", - "postal_horn", - "scroll", - "page_with_curl", - "page_facing_up", - "bookmark_tabs", - "receipt", - "bar_chart", - "chart_with_upwards_trend", - "chart_with_downwards_trend", - "notepad_spiral", - "spiral_note_pad", - "calendar_spiral", - "spiral_calendar_pad", - "calendar", - "date", - "wastebasket", - "card_index", - "card_box", - "card_file_box", - "ballot_box", - "ballot_box_with_ballot", - "file_cabinet", - "clipboard", - "file_folder", - "open_file_folder", - "dividers", - "card_index_dividers", - "newspaper2", - "rolled_up_newspaper", - "newspaper", - "notebook", - "notebook_with_decorative_cover", - "ledger", - "closed_book", - "green_book", - "blue_book", - "orange_book", - "books", - "book", - "open_book", - "bookmark", - "safety_pin", - "link", - "paperclip", - "paperclips", - "linked_paperclips", - "triangular_ruler", - "straight_ruler", - "abacus", - "pushpin", - "round_pushpin", - "scissors", - "pen_ballpoint", - "lower_left_ballpoint_pen", - "pen", - "pen_fountain", - "lower_left_fountain_pen", - "fountain_pen", - "black_nib", - "paintbrush", - "lower_left_paintbrush", - "crayon", - "lower_left_crayon", - "pencil", - "memo", - "pencil2", - "mag", - "mag_right", - "lock_with_ink_pen", - "closed_lock_with_key", - "lock", - "locked", - "unlock", - "unlocked", - "grinning", - "grinning_face", - "smiley", - "smile", - "grin", - "laughing", - "satisfied", - "face_holding_back_tears", - "sweat_smile", - "joy", - "rofl", - "rolling_on_the_floor_laughing", - "smiling_face_with_tear", - "relaxed", - "smiling_face", - "blush", - "innocent", - "slight_smile", - "slightly_smiling_face", - "upside_down", - "upside_down_face", - "wink", - "winking_face", - "relieved", - "relieved_face", - "heart_eyes", - "smiling_face_with_3_hearts", - "kissing_heart", - "kissing", - "kissing_face", - "kissing_smiling_eyes", - "kissing_closed_eyes", - "yum", - "stuck_out_tongue", - "stuck_out_tongue_closed_eyes", - "stuck_out_tongue_winking_eye", - "zany_face", - "face_with_raised_eyebrow", - "face_with_monocle", - "nerd", - "nerd_face", - "sunglasses", - "disguised_face", - "star_struck", - "partying_face", - "smirk", - "smirking_face", - "unamused", - "unamused_face", - "disappointed", - "pensive", - "pensive_face", - "worried", - "worried_face", - "confused", - "confused_face", - "slight_frown", - "slightly_frowning_face", - "frowning2", - "white_frowning_face", - "frowning_face", - "persevere", - "confounded", - "tired_face", - "weary", - "weary_face", - "pleading_face", - "cry", - "crying_face", - "sob", - "triumph", - "angry", - "angry_face", - "rage", - "pouting_face", - "face_with_symbols_over_mouth", - "exploding_head", - "flushed", - "flushed_face", - "hot_face", - "cold_face", - "face_in_clouds", - "scream", - "fearful", - "fearful_face", - "cold_sweat", - "disappointed_relieved", - "sweat", - "hugging", - "hugging_face", - "thinking", - "thinking_face", - "face_with_peeking_eye", - "face_with_hand_over_mouth", - "face_with_open_eyes_and_hand_over_mouth", - "saluting_face", - "shushing_face", - "melting_face", - "lying_face", - "liar", - "no_mouth", - "dotted_line_face", - "neutral_face", - "face_with_diagonal_mouth", - "expressionless", - "shaking_face", - "grimacing", - "rolling_eyes", - "face_with_rolling_eyes", - "hushed", - "hushed_face", - "frowning", - "anguished", - "open_mouth", - "astonished", - "yawning_face", - "sleeping", - "sleeping_face", - "drooling_face", - "drool", - "sleepy", - "sleepy_face", - "face_exhaling", - "dizzy_face", - "face_with_spiral_eyes", - "zipper_mouth", - "zipper_mouth_face", - "woozy_face", - "nauseated_face", - "sick", - "face_vomiting", - "sneezing_face", - "sneeze", - "mask", - "thermometer_face", - "face_with_thermometer", - "head_bandage", - "face_with_head_bandage", - "money_mouth", - "money_mouth_face", - "cowboy", - "face_with_cowboy_hat", - "smiling_imp", - "imp", - "japanese_ogre", - "ogre", - "japanese_goblin", - "goblin", - "clown", - "clown_face", - "poop", - "shit", - "hankey", - "poo", - "pile_of_poo", - "ghost", - "skull", - "skeleton", - "skull_crossbones", - "skull_and_crossbones", - "alien", - "space_invader", - "alien_monster", - "robot", - "robot_face", - "jack_o_lantern", - "smiley_cat", - "grinning_cat", - "smile_cat", - "joy_cat", - "heart_eyes_cat", - "smirk_cat", - "kissing_cat", - "scream_cat", - "weary_cat", - "crying_cat_face", - "crying_cat", - "pouting_cat", - "heart_hands", - "heart_hands_tone1", - "heart_hands_light_skin_tone", - "heart_hands_tone2", - "heart_hands_medium_light_skin_tone", - "heart_hands_tone3", - "heart_hands_medium_skin_tone", - "heart_hands_tone4", - "heart_hands_medium_dark_skin_tone", - "heart_hands_tone5", - "heart_hands_dark_skin_tone", - "palms_up_together", - "palms_up_together_tone1", - "palms_up_together_light_skin_tone", - "palms_up_together_tone2", - "palms_up_together_medium_light_skin_tone", - "palms_up_together_tone3", - "palms_up_together_medium_skin_tone", - "palms_up_together_tone4", - "palms_up_together_medium_dark_skin_tone", - "palms_up_together_tone5", - "palms_up_together_dark_skin_tone", - "open_hands", - "open_hands_tone1", - "open_hands_tone2", - "open_hands_tone3", - "open_hands_tone4", - "open_hands_tone5", - "raised_hands", - "raising_hands", - "raised_hands_tone1", - "raised_hands_tone2", - "raised_hands_tone3", - "raised_hands_tone4", - "raised_hands_tone5", - "clap", - "clap_tone1", - "clap_tone2", - "clap_tone3", - "clap_tone4", - "clap_tone5", - "handshake", - "shaking_hands", - "handshake_tone1", - "handshake_light_skin_tone", - "handshake_tone1_tone2", - "handshake_light_skin_tone_medium_light_skin_tone", - "handshake_tone1_tone3", - "handshake_light_skin_tone_medium_skin_tone", - "handshake_tone1_tone4", - "handshake_light_skin_tone_medium_dark_skin_tone", - "handshake_tone1_tone5", - "handshake_light_skin_tone_dark_skin_tone", - "handshake_tone2_tone1", - "handshake_medium_light_skin_tone_light_skin_tone", - "handshake_tone2", - "handshake_medium_light_skin_tone", - "handshake_tone2_tone3", - "handshake_medium_light_skin_tone_medium_skin_tone", - "handshake_tone2_tone4", - "handshake_medium_light_skin_tone_medium_dark_skin_tone", - "handshake_tone2_tone5", - "handshake_medium_light_skin_tone_dark_skin_tone", - "handshake_tone3_tone1", - "handshake_medium_skin_tone_light_skin_tone", - "handshake_tone3_tone2", - "handshake_medium_skin_tone_medium_light_skin_tone", - "handshake_tone3", - "handshake_medium_skin_tone", - "handshake_tone3_tone4", - "handshake_medium_skin_tone_medium_dark_skin_tone", - "handshake_tone3_tone5", - "handshake_medium_skin_tone_dark_skin_tone", - "handshake_tone4_tone1", - "handshake_medium_dark_skin_tone_light_skin_tone", - "handshake_tone4_tone2", - "handshake_medium_dark_skin_tone_medium_light_skin_tone", - "handshake_tone4_tone3", - "handshake_medium_dark_skin_tone_medium_skin_tone", - "handshake_tone4", - "handshake_medium_dark_skin_tone", - "handshake_tone4_tone5", - "handshake_medium_dark_skin_tone_dark_skin_tone", - "handshake_tone5_tone1", - "handshake_dark_skin_tone_light_skin_tone", - "handshake_tone5_tone2", - "handshake_dark_skin_tone_medium_light_skin_tone", - "handshake_tone5_tone3", - "handshake_dark_skin_tone_medium_skin_tone", - "handshake_tone5_tone4", - "handshake_dark_skin_tone_medium_dark_skin_tone", - "handshake_tone5", - "handshake_dark_skin_tone", - "thumbsup", - "+1", - "thumbup", - "thumbs_up", - "thumbsup_tone1", - "+1_tone1", - "thumbup_tone1", - "thumbsup_tone2", - "+1_tone2", - "thumbup_tone2", - "thumbsup_tone3", - "+1_tone3", - "thumbup_tone3", - "thumbsup_tone4", - "+1_tone4", - "thumbup_tone4", - "thumbsup_tone5", - "+1_tone5", - "thumbup_tone5", - "thumbsdown", - "-1", - "thumbdown", - "thumbs_down", - "thumbsdown_tone1", - "_1_tone1", - "thumbdown_tone1", - "thumbsdown_tone2", - "_1_tone2", - "thumbdown_tone2", - "thumbsdown_tone3", - "_1_tone3", - "thumbdown_tone3", - "thumbsdown_tone4", - "_1_tone4", - "thumbdown_tone4", - "thumbsdown_tone5", - "_1_tone5", - "thumbdown_tone5", - "punch", - "oncoming_fist", - "punch_tone1", - "punch_tone2", - "punch_tone3", - "punch_tone4", - "punch_tone5", - "fist", - "raised_fist", - "fist_tone1", - "fist_tone2", - "fist_tone3", - "fist_tone4", - "fist_tone5", - "left_facing_fist", - "left_fist", - "left_facing_fist_tone1", - "left_fist_tone1", - "left_facing_fist_tone2", - "left_fist_tone2", - "left_facing_fist_tone3", - "left_fist_tone3", - "left_facing_fist_tone4", - "left_fist_tone4", - "left_facing_fist_tone5", - "left_fist_tone5", - "right_facing_fist", - "right_fist", - "right_facing_fist_tone1", - "right_fist_tone1", - "right_facing_fist_tone2", - "right_fist_tone2", - "right_facing_fist_tone3", - "right_fist_tone3", - "right_facing_fist_tone4", - "right_fist_tone4", - "right_facing_fist_tone5", - "right_fist_tone5", - "leftwards_pushing_hand", - "leftwards_pushing_hand_tone1", - "leftwards_pushing_hand_light_skin_tone", - "leftwards_pushing_hand_tone2", - "leftwards_pushing_hand_medium_light_skin_tone", - "leftwards_pushing_hand_tone3", - "leftwards_pushing_hand_medium_skin_tone", - "leftwards_pushing_hand_tone4", - "leftwards_pushing_hand_medium_dark_skin_tone", - "leftwards_pushing_hand_tone5", - "leftwards_pushing_hand_dark_skin_tone", - "rightwards_pushing_hand", - "rightwards_pushing_hand_tone1", - "rightwards_pushing_hand_light_skin_tone", - "rightwards_pushing_hand_tone2", - "rightwards_pushing_hand_medium_light_skin_tone", - "rightwards_pushing_hand_tone3", - "rightwards_pushing_hand_medium_skin_tone", - "rightwards_pushing_hand_tone4", - "rightwards_pushing_hand_medium_dark_skin_tone", - "rightwards_pushing_hand_tone5", - "rightwards_pushing_hand_dark_skin_tone", - "fingers_crossed", - "hand_with_index_and_middle_finger_crossed", - "fingers_crossed_tone1", - "hand_with_index_and_middle_fingers_crossed_tone1", - "fingers_crossed_tone2", - "hand_with_index_and_middle_fingers_crossed_tone2", - "fingers_crossed_tone3", - "hand_with_index_and_middle_fingers_crossed_tone3", - "fingers_crossed_tone4", - "hand_with_index_and_middle_fingers_crossed_tone4", - "fingers_crossed_tone5", - "hand_with_index_and_middle_fingers_crossed_tone5", - "v", - "victory_hand", - "v_tone1", - "v_tone2", - "v_tone3", - "v_tone4", - "v_tone5", - "hand_with_index_finger_and_thumb_crossed", - "hand_with_index_finger_and_thumb_crossed_tone1", - "hand_with_index_finger_and_thumb_crossed_light_skin_tone", - "hand_with_index_finger_and_thumb_crossed_tone2", - "hand_with_index_finger_and_thumb_crossed_medium_light_skin_tone", - "hand_with_index_finger_and_thumb_crossed_tone3", - "hand_with_index_finger_and_thumb_crossed_medium_skin_tone", - "hand_with_index_finger_and_thumb_crossed_tone4", - "hand_with_index_finger_and_thumb_crossed_medium_dark_skin_tone", - "hand_with_index_finger_and_thumb_crossed_tone5", - "hand_with_index_finger_and_thumb_crossed_dark_skin_tone", - "love_you_gesture", - "love_you_gesture_tone1", - "love_you_gesture_light_skin_tone", - "love_you_gesture_tone2", - "love_you_gesture_medium_light_skin_tone", - "love_you_gesture_tone3", - "love_you_gesture_medium_skin_tone", - "love_you_gesture_tone4", - "love_you_gesture_medium_dark_skin_tone", - "love_you_gesture_tone5", - "love_you_gesture_dark_skin_tone", - "metal", - "sign_of_the_horns", - "metal_tone1", - "sign_of_the_horns_tone1", - "metal_tone2", - "sign_of_the_horns_tone2", - "metal_tone3", - "sign_of_the_horns_tone3", - "metal_tone4", - "sign_of_the_horns_tone4", - "metal_tone5", - "sign_of_the_horns_tone5", - "ok_hand", - "ok_hand_tone1", - "ok_hand_tone2", - "ok_hand_tone3", - "ok_hand_tone4", - "ok_hand_tone5", - "pinched_fingers", - "pinched_fingers_tone2", - "pinched_fingers_medium_light_skin_tone", - "pinched_fingers_tone1", - "pinched_fingers_light_skin_tone", - "pinched_fingers_tone3", - "pinched_fingers_medium_skin_tone", - "pinched_fingers_tone4", - "pinched_fingers_medium_dark_skin_tone", - "pinched_fingers_tone5", - "pinched_fingers_dark_skin_tone", - "pinching_hand", - "pinching_hand_tone1", - "pinching_hand_light_skin_tone", - "pinching_hand_tone2", - "pinching_hand_medium_light_skin_tone", - "pinching_hand_tone3", - "pinching_hand_medium_skin_tone", - "pinching_hand_tone4", - "pinching_hand_medium_dark_skin_tone", - "pinching_hand_tone5", - "pinching_hand_dark_skin_tone", - "palm_down_hand", - "palm_down_hand_tone1", - "palm_down_hand_light_skin_tone", - "palm_down_hand_tone2", - "palm_down_hand_medium_light_skin_tone", - "palm_down_hand_tone3", - "palm_down_hand_medium_skin_tone", - "palm_down_hand_tone4", - "palm_down_hand_medium_dark_skin_tone", - "palm_down_hand_tone5", - "palm_down_hand_dark_skin_tone", - "palm_up_hand", - "palm_up_hand_tone1", - "palm_up_hand_light_skin_tone", - "palm_up_hand_tone2", - "palm_up_hand_medium_light_skin_tone", - "palm_up_hand_tone3", - "palm_up_hand_medium_skin_tone", - "palm_up_hand_tone4", - "palm_up_hand_medium_dark_skin_tone", - "palm_up_hand_tone5", - "palm_up_hand_dark_skin_tone", - "point_left", - "point_left_tone1", - "point_left_tone2", - "point_left_tone3", - "point_left_tone4", - "point_left_tone5", - "point_right", - "point_right_tone1", - "point_right_tone2", - "point_right_tone3", - "point_right_tone4", - "point_right_tone5", - "point_up_2", - "point_up_2_tone1", - "point_up_2_tone2", - "point_up_2_tone3", - "point_up_2_tone4", - "point_up_2_tone5", - "point_down", - "point_down_tone1", - "point_down_tone2", - "point_down_tone3", - "point_down_tone4", - "point_down_tone5", - "point_up", - "point_up_tone1", - "point_up_tone2", - "point_up_tone3", - "point_up_tone4", - "point_up_tone5", - "raised_hand", - "raised_hand_tone1", - "raised_hand_tone2", - "raised_hand_tone3", - "raised_hand_tone4", - "raised_hand_tone5", - "raised_back_of_hand", - "back_of_hand", - "raised_back_of_hand_tone1", - "back_of_hand_tone1", - "raised_back_of_hand_tone2", - "back_of_hand_tone2", - "raised_back_of_hand_tone3", - "back_of_hand_tone3", - "raised_back_of_hand_tone4", - "back_of_hand_tone4", - "raised_back_of_hand_tone5", - "back_of_hand_tone5", - "hand_splayed", - "raised_hand_with_fingers_splayed", - "hand_splayed_tone1", - "raised_hand_with_fingers_splayed_tone1", - "hand_splayed_tone2", - "raised_hand_with_fingers_splayed_tone2", - "hand_splayed_tone3", - "raised_hand_with_fingers_splayed_tone3", - "hand_splayed_tone4", - "raised_hand_with_fingers_splayed_tone4", - "hand_splayed_tone5", - "raised_hand_with_fingers_splayed_tone5", - "vulcan", - "raised_hand_with_part_between_middle_and_ring_fingers", - "vulcan_salute", - "vulcan_tone1", - "raised_hand_with_part_between_middle_and_ring_fingers_tone1", - "vulcan_tone2", - "raised_hand_with_part_between_middle_and_ring_fingers_tone2", - "vulcan_tone3", - "raised_hand_with_part_between_middle_and_ring_fingers_tone3", - "vulcan_tone4", - "raised_hand_with_part_between_middle_and_ring_fingers_tone4", - "vulcan_tone5", - "raised_hand_with_part_between_middle_and_ring_fingers_tone5", - "wave", - "waving_hand", - "wave_tone1", - "wave_tone2", - "wave_tone3", - "wave_tone4", - "wave_tone5", - "call_me", - "call_me_hand", - "call_me_tone1", - "call_me_hand_tone1", - "call_me_tone2", - "call_me_hand_tone2", - "call_me_tone3", - "call_me_hand_tone3", - "call_me_tone4", - "call_me_hand_tone4", - "call_me_tone5", - "call_me_hand_tone5", - "leftwards_hand", - "leftwards_hand_tone1", - "leftwards_hand_light_skin_tone", - "leftwards_hand_tone2", - "leftwards_hand_medium_light_skin_tone", - "leftwards_hand_tone3", - "leftwards_hand_medium_skin_tone", - "leftwards_hand_tone4", - "leftwards_hand_medium_dark_skin_tone", - "leftwards_hand_tone5", - "leftwards_hand_dark_skin_tone", - "rightwards_hand", - "rightwards_hand_tone1", - "rightwards_hand_light_skin_tone", - "rightwards_hand_tone2", - "rightwards_hand_medium_light_skin_tone", - "rightwards_hand_tone3", - "rightwards_hand_medium_skin_tone", - "rightwards_hand_tone4", - "rightwards_hand_medium_dark_skin_tone", - "rightwards_hand_tone5", - "rightwards_hand_dark_skin_tone", - "muscle", - "flexed_biceps", - "muscle_tone1", - "muscle_tone2", - "muscle_tone3", - "muscle_tone4", - "muscle_tone5", - "mechanical_arm", - "middle_finger", - "reversed_hand_with_middle_finger_extended", - "middle_finger_tone1", - "reversed_hand_with_middle_finger_extended_tone1", - "middle_finger_tone2", - "reversed_hand_with_middle_finger_extended_tone2", - "middle_finger_tone3", - "reversed_hand_with_middle_finger_extended_tone3", - "middle_finger_tone4", - "reversed_hand_with_middle_finger_extended_tone4", - "middle_finger_tone5", - "reversed_hand_with_middle_finger_extended_tone5", - "writing_hand", - "writing_hand_tone1", - "writing_hand_tone2", - "writing_hand_tone3", - "writing_hand_tone4", - "writing_hand_tone5", - "pray", - "folded_hands", - "pray_tone1", - "pray_tone2", - "pray_tone3", - "pray_tone4", - "pray_tone5", - "index_pointing_at_the_viewer", - "index_pointing_at_the_viewer_tone1", - "index_pointing_at_the_viewer_light_skin_tone", - "index_pointing_at_the_viewer_tone2", - "index_pointing_at_the_viewer_medium_light_skin_tone", - "index_pointing_at_the_viewer_tone3", - "index_pointing_at_the_viewer_medium_skin_tone", - "index_pointing_at_the_viewer_tone4", - "index_pointing_at_the_viewer_medium_dark_skin_tone", - "index_pointing_at_the_viewer_tone5", - "index_pointing_at_the_viewer_dark_skin_tone", - "foot", - "foot_tone1", - "foot_light_skin_tone", - "foot_tone2", - "foot_medium_light_skin_tone", - "foot_tone3", - "foot_medium_skin_tone", - "foot_tone4", - "foot_medium_dark_skin_tone", - "foot_tone5", - "foot_dark_skin_tone", - "leg", - "leg_tone1", - "leg_light_skin_tone", - "leg_tone2", - "leg_medium_light_skin_tone", - "leg_tone3", - "leg_medium_skin_tone", - "leg_tone4", - "leg_medium_dark_skin_tone", - "leg_tone5", - "leg_dark_skin_tone", - "mechanical_leg", - "lipstick", - "kiss", - "kiss_mark", - "lips", - "mouth", - "biting_lip", - "tooth", - "tongue", - "ear", - "ear_tone1", - "ear_tone2", - "ear_tone3", - "ear_tone4", - "ear_tone5", - "ear_with_hearing_aid", - "ear_with_hearing_aid_tone1", - "ear_with_hearing_aid_light_skin_tone", - "ear_with_hearing_aid_tone2", - "ear_with_hearing_aid_medium_light_skin_tone", - "ear_with_hearing_aid_tone3", - "ear_with_hearing_aid_medium_skin_tone", - "ear_with_hearing_aid_tone4", - "ear_with_hearing_aid_medium_dark_skin_tone", - "ear_with_hearing_aid_tone5", - "ear_with_hearing_aid_dark_skin_tone", - "nose", - "nose_tone1", - "nose_tone2", - "nose_tone3", - "nose_tone4", - "nose_tone5", - "footprints", - "eye", - "eyes", - "anatomical_heart", - "lungs", - "brain", - "speaking_head", - "speaking_head_in_silhouette", - "bust_in_silhouette", - "busts_in_silhouette", - "people_hugging", - "baby", - "baby_tone1", - "baby_tone2", - "baby_tone3", - "baby_tone4", - "baby_tone5", - "child", - "child_tone1", - "child_light_skin_tone", - "child_tone2", - "child_medium_light_skin_tone", - "child_tone3", - "child_medium_skin_tone", - "child_tone4", - "child_medium_dark_skin_tone", - "child_tone5", - "child_dark_skin_tone", - "girl", - "girl_tone1", - "girl_tone2", - "girl_tone3", - "girl_tone4", - "girl_tone5", - "boy", - "boy_tone1", - "boy_tone2", - "boy_tone3", - "boy_tone4", - "boy_tone5", - "adult", - "person", - "adult_tone1", - "adult_light_skin_tone", - "adult_tone2", - "adult_medium_light_skin_tone", - "adult_tone3", - "adult_medium_skin_tone", - "adult_tone4", - "adult_medium_dark_skin_tone", - "adult_tone5", - "adult_dark_skin_tone", - "woman", - "woman_tone1", - "woman_tone2", - "woman_tone3", - "woman_tone4", - "woman_tone5", - "man", - "man_tone1", - "man_tone2", - "man_tone3", - "man_tone4", - "man_tone5", - "person_curly_hair", - "person_tone1_curly_hair", - "person_light_skin_tone_curly_hair", - "person_tone2_curly_hair", - "person_medium_light_skin_tone_curly_hair", - "person_tone3_curly_hair", - "person_medium_skin_tone_curly_hair", - "person_tone4_curly_hair", - "person_medium_dark_skin_tone_curly_hair", - "person_tone5_curly_hair", - "person_dark_skin_tone_curly_hair", - "woman_curly_haired", - "woman_curly_haired_tone1", - "woman_curly_haired_light_skin_tone", - "woman_curly_haired_tone2", - "woman_curly_haired_medium_light_skin_tone", - "woman_curly_haired_tone3", - "woman_curly_haired_medium_skin_tone", - "woman_curly_haired_tone4", - "woman_curly_haired_medium_dark_skin_tone", - "woman_curly_haired_tone5", - "woman_curly_haired_dark_skin_tone", - "man_curly_haired", - "man_curly_haired_tone1", - "man_curly_haired_light_skin_tone", - "man_curly_haired_tone2", - "man_curly_haired_medium_light_skin_tone", - "man_curly_haired_tone3", - "man_curly_haired_medium_skin_tone", - "man_curly_haired_tone4", - "man_curly_haired_medium_dark_skin_tone", - "man_curly_haired_tone5", - "man_curly_haired_dark_skin_tone", - "person_red_hair", - "person_tone1_red_hair", - "person_light_skin_tone_red_hair", - "person_tone2_red_hair", - "person_medium_light_skin_tone_red_hair", - "person_tone3_red_hair", - "person_medium_skin_tone_red_hair", - "person_tone4_red_hair", - "person_medium_dark_skin_tone_red_hair", - "person_tone5_red_hair", - "person_dark_skin_tone_red_hair", - "woman_red_haired", - "woman_red_haired_tone1", - "woman_red_haired_light_skin_tone", - "woman_red_haired_tone2", - "woman_red_haired_medium_light_skin_tone", - "woman_red_haired_tone3", - "woman_red_haired_medium_skin_tone", - "woman_red_haired_tone4", - "woman_red_haired_medium_dark_skin_tone", - "woman_red_haired_tone5", - "woman_red_haired_dark_skin_tone", - "man_red_haired", - "man_red_hair", - "man_red_haired_tone1", - "man_red_haired_light_skin_tone", - "man_red_haired_tone2", - "man_red_haired_medium_light_skin_tone", - "man_red_haired_tone3", - "man_red_haired_medium_skin_tone", - "man_red_haired_tone4", - "man_red_haired_medium_dark_skin_tone", - "man_red_haired_tone5", - "man_red_haired_dark_skin_tone", - "blond_haired_person", - "person_with_blond_hair", - "blond_haired_person_tone1", - "person_with_blond_hair_tone1", - "blond_haired_person_tone2", - "person_with_blond_hair_tone2", - "blond_haired_person_tone3", - "person_with_blond_hair_tone3", - "blond_haired_person_tone4", - "person_with_blond_hair_tone4", - "blond_haired_person_tone5", - "person_with_blond_hair_tone5", - "blond_haired_woman", - "blond_haired_woman_tone1", - "blond_haired_woman_light_skin_tone", - "blond_haired_woman_tone2", - "blond_haired_woman_medium_light_skin_tone", - "blond_haired_woman_tone3", - "blond_haired_woman_medium_skin_tone", - "blond_haired_woman_tone4", - "blond_haired_woman_medium_dark_skin_tone", - "blond_haired_woman_tone5", - "blond_haired_woman_dark_skin_tone", - "blond_haired_man", - "blond_haired_man_tone1", - "blond_haired_man_light_skin_tone", - "blond_haired_man_tone2", - "blond_haired_man_medium_light_skin_tone", - "blond_haired_man_tone3", - "blond_haired_man_medium_skin_tone", - "blond_haired_man_tone4", - "blond_haired_man_medium_dark_skin_tone", - "blond_haired_man_tone5", - "blond_haired_man_dark_skin_tone", - "person_white_hair", - "person_tone1_white_hair", - "person_light_skin_tone_white_hair", - "person_tone2_white_hair", - "person_medium_light_skin_tone_white_hair", - "person_tone3_white_hair", - "person_medium_skin_tone_white_hair", - "person_tone4_white_hair", - "person_medium_dark_skin_tone_white_hair", - "person_tone5_white_hair", - "person_dark_skin_tone_white_hair", - "woman_white_haired", - "woman_white_haired_tone1", - "woman_white_haired_light_skin_tone", - "woman_white_haired_tone2", - "woman_white_haired_medium_light_skin_tone", - "woman_white_haired_tone3", - "woman_white_haired_medium_skin_tone", - "woman_white_haired_tone4", - "woman_white_haired_medium_dark_skin_tone", - "woman_white_haired_tone5", - "woman_white_haired_dark_skin_tone", - "man_white_haired", - "man_white_haired_tone1", - "man_white_haired_light_skin_tone", - "man_white_haired_tone2", - "man_white_haired_medium_light_skin_tone", - "man_white_haired_tone3", - "man_white_haired_medium_skin_tone", - "man_white_haired_tone4", - "man_white_haired_medium_dark_skin_tone", - "man_white_haired_tone5", - "man_white_haired_dark_skin_tone", - "person_bald", - "person_tone1_bald", - "person_light_skin_tone_bald", - "person_tone2_bald", - "person_medium_light_skin_tone_bald", - "person_tone3_bald", - "person_medium_skin_tone_bald", - "person_tone4_bald", - "person_medium_dark_skin_tone_bald", - "person_tone5_bald", - "person_dark_skin_tone_bald", - "woman_bald", - "woman_bald_tone1", - "woman_bald_light_skin_tone", - "woman_bald_tone2", - "woman_bald_medium_light_skin_tone", - "woman_bald_tone3", - "woman_bald_medium_skin_tone", - "woman_bald_tone4", - "woman_bald_medium_dark_skin_tone", - "woman_bald_tone5", - "woman_bald_dark_skin_tone", - "man_bald", - "man_bald_tone1", - "man_bald_light_skin_tone", - "man_bald_tone2", - "man_bald_medium_light_skin_tone", - "man_bald_tone3", - "man_bald_medium_skin_tone", - "man_bald_tone4", - "man_bald_medium_dark_skin_tone", - "man_bald_tone5", - "man_bald_dark_skin_tone", - "bearded_person", - "person_beard", - "bearded_person_tone1", - "bearded_person_light_skin_tone", - "bearded_person_tone2", - "bearded_person_medium_light_skin_tone", - "bearded_person_tone3", - "bearded_person_medium_skin_tone", - "bearded_person_tone4", - "bearded_person_medium_dark_skin_tone", - "bearded_person_tone5", - "bearded_person_dark_skin_tone", - "woman_beard", - "woman_tone1_beard", - "woman_light_skin_tone_beard", - "woman_tone2_beard", - "woman_medium_light_skin_tone_beard", - "woman_tone3_beard", - "woman_medium_skin_tone_beard", - "woman_tone4_beard", - "woman_medium_dark_skin_tone_beard", - "woman_tone5_beard", - "woman_dark_skin_tone_beard", - "man_beard", - "man_tone1_beard", - "man_light_skin_tone_beard", - "man_tone2_beard", - "man_medium_light_skin_tone_beard", - "man_tone3_beard", - "man_medium_skin_tone_beard", - "man_tone4_beard", - "man_medium_dark_skin_tone_beard", - "man_tone5_beard", - "man_dark_skin_tone_beard", - "older_adult", - "older_person", - "older_adult_tone1", - "older_adult_light_skin_tone", - "older_adult_tone2", - "older_adult_medium_light_skin_tone", - "older_adult_tone3", - "older_adult_medium_skin_tone", - "older_adult_tone4", - "older_adult_medium_dark_skin_tone", - "older_adult_tone5", - "older_adult_dark_skin_tone", - "older_woman", - "grandma", - "old_woman", - "older_woman_tone1", - "grandma_tone1", - "older_woman_tone2", - "grandma_tone2", - "older_woman_tone3", - "grandma_tone3", - "older_woman_tone4", - "grandma_tone4", - "older_woman_tone5", - "grandma_tone5", - "older_man", - "old_man", - "older_man_tone1", - "older_man_tone2", - "older_man_tone3", - "older_man_tone4", - "older_man_tone5", - "man_with_chinese_cap", - "man_with_gua_pi_mao", - "man_with_chinese_cap_tone1", - "man_with_gua_pi_mao_tone1", - "man_with_chinese_cap_tone2", - "man_with_gua_pi_mao_tone2", - "man_with_chinese_cap_tone3", - "man_with_gua_pi_mao_tone3", - "man_with_chinese_cap_tone4", - "man_with_gua_pi_mao_tone4", - "man_with_chinese_cap_tone5", - "man_with_gua_pi_mao_tone5", - "person_wearing_turban", - "man_with_turban", - "person_wearing_turban_tone1", - "man_with_turban_tone1", - "person_wearing_turban_tone2", - "man_with_turban_tone2", - "person_wearing_turban_tone3", - "man_with_turban_tone3", - "person_wearing_turban_tone4", - "man_with_turban_tone4", - "person_wearing_turban_tone5", - "man_with_turban_tone5", - "woman_wearing_turban", - "woman_wearing_turban_tone1", - "woman_wearing_turban_light_skin_tone", - "woman_wearing_turban_tone2", - "woman_wearing_turban_medium_light_skin_tone", - "woman_wearing_turban_tone3", - "woman_wearing_turban_medium_skin_tone", - "woman_wearing_turban_tone4", - "woman_wearing_turban_medium_dark_skin_tone", - "woman_wearing_turban_tone5", - "woman_wearing_turban_dark_skin_tone", - "man_wearing_turban", - "man_wearing_turban_tone1", - "man_wearing_turban_light_skin_tone", - "man_wearing_turban_tone2", - "man_wearing_turban_medium_light_skin_tone", - "man_wearing_turban_tone3", - "man_wearing_turban_medium_skin_tone", - "man_wearing_turban_tone4", - "man_wearing_turban_medium_dark_skin_tone", - "man_wearing_turban_tone5", - "man_wearing_turban_dark_skin_tone", - "woman_with_headscarf", - "woman_with_headscarf_tone1", - "woman_with_headscarf_light_skin_tone", - "woman_with_headscarf_tone2", - "woman_with_headscarf_medium_light_skin_tone", - "woman_with_headscarf_tone3", - "woman_with_headscarf_medium_skin_tone", - "woman_with_headscarf_tone4", - "woman_with_headscarf_medium_dark_skin_tone", - "woman_with_headscarf_tone5", - "woman_with_headscarf_dark_skin_tone", - "police_officer", - "cop", - "police_officer_tone1", - "cop_tone1", - "police_officer_tone2", - "cop_tone2", - "police_officer_tone3", - "cop_tone3", - "police_officer_tone4", - "cop_tone4", - "police_officer_tone5", - "cop_tone5", - "woman_police_officer", - "woman_police_officer_tone1", - "woman_police_officer_light_skin_tone", - "woman_police_officer_tone2", - "woman_police_officer_medium_light_skin_tone", - "woman_police_officer_tone3", - "woman_police_officer_medium_skin_tone", - "woman_police_officer_tone4", - "woman_police_officer_medium_dark_skin_tone", - "woman_police_officer_tone5", - "woman_police_officer_dark_skin_tone", - "man_police_officer", - "man_police_officer_tone1", - "man_police_officer_light_skin_tone", - "man_police_officer_tone2", - "man_police_officer_medium_light_skin_tone", - "man_police_officer_tone3", - "man_police_officer_medium_skin_tone", - "man_police_officer_tone4", - "man_police_officer_medium_dark_skin_tone", - "man_police_officer_tone5", - "man_police_officer_dark_skin_tone", - "construction_worker", - "construction_worker_tone1", - "construction_worker_tone2", - "construction_worker_tone3", - "construction_worker_tone4", - "construction_worker_tone5", - "woman_construction_worker", - "woman_construction_worker_tone1", - "woman_construction_worker_light_skin_tone", - "woman_construction_worker_tone2", - "woman_construction_worker_medium_light_skin_tone", - "woman_construction_worker_tone3", - "woman_construction_worker_medium_skin_tone", - "woman_construction_worker_tone4", - "woman_construction_worker_medium_dark_skin_tone", - "woman_construction_worker_tone5", - "woman_construction_worker_dark_skin_tone", - "man_construction_worker", - "man_construction_worker_tone1", - "man_construction_worker_light_skin_tone", - "man_construction_worker_tone2", - "man_construction_worker_medium_light_skin_tone", - "man_construction_worker_tone3", - "man_construction_worker_medium_skin_tone", - "man_construction_worker_tone4", - "man_construction_worker_medium_dark_skin_tone", - "man_construction_worker_tone5", - "man_construction_worker_dark_skin_tone", - "guard", - "guardsman", - "guard_tone1", - "guardsman_tone1", - "guard_tone2", - "guardsman_tone2", - "guard_tone3", - "guardsman_tone3", - "guard_tone4", - "guardsman_tone4", - "guard_tone5", - "guardsman_tone5", - "woman_guard", - "woman_guard_tone1", - "woman_guard_light_skin_tone", - "woman_guard_tone2", - "woman_guard_medium_light_skin_tone", - "woman_guard_tone3", - "woman_guard_medium_skin_tone", - "woman_guard_tone4", - "woman_guard_medium_dark_skin_tone", - "woman_guard_tone5", - "woman_guard_dark_skin_tone", - "man_guard", - "man_guard_tone1", - "man_guard_light_skin_tone", - "man_guard_tone2", - "man_guard_medium_light_skin_tone", - "man_guard_tone3", - "man_guard_medium_skin_tone", - "man_guard_tone4", - "man_guard_medium_dark_skin_tone", - "man_guard_tone5", - "man_guard_dark_skin_tone", - "detective", - "spy", - "sleuth_or_spy", - "detective_tone1", - "spy_tone1", - "sleuth_or_spy_tone1", - "detective_tone2", - "spy_tone2", - "sleuth_or_spy_tone2", - "detective_tone3", - "spy_tone3", - "sleuth_or_spy_tone3", - "detective_tone4", - "spy_tone4", - "sleuth_or_spy_tone4", - "detective_tone5", - "spy_tone5", - "sleuth_or_spy_tone5", - "woman_detective", - "woman_detective_tone1", - "woman_detective_light_skin_tone", - "woman_detective_tone2", - "woman_detective_medium_light_skin_tone", - "woman_detective_tone3", - "woman_detective_medium_skin_tone", - "woman_detective_tone4", - "woman_detective_medium_dark_skin_tone", - "woman_detective_tone5", - "woman_detective_dark_skin_tone", - "man_detective", - "man_detective_tone1", - "man_detective_light_skin_tone", - "man_detective_tone2", - "man_detective_medium_light_skin_tone", - "man_detective_tone3", - "man_detective_medium_skin_tone", - "man_detective_tone4", - "man_detective_medium_dark_skin_tone", - "man_detective_tone5", - "man_detective_dark_skin_tone", - "health_worker", - "health_worker_tone1", - "health_worker_light_skin_tone", - "health_worker_tone2", - "health_worker_medium_light_skin_tone", - "health_worker_tone3", - "health_worker_medium_skin_tone", - "health_worker_tone4", - "health_worker_medium_dark_skin_tone", - "health_worker_tone5", - "health_worker_dark_skin_tone", - "woman_health_worker", - "woman_health_worker_tone1", - "woman_health_worker_light_skin_tone", - "woman_health_worker_tone2", - "woman_health_worker_medium_light_skin_tone", - "woman_health_worker_tone3", - "woman_health_worker_medium_skin_tone", - "woman_health_worker_tone4", - "woman_health_worker_medium_dark_skin_tone", - "woman_health_worker_tone5", - "woman_health_worker_dark_skin_tone", - "man_health_worker", - "man_health_worker_tone1", - "man_health_worker_light_skin_tone", - "man_health_worker_tone2", - "man_health_worker_medium_light_skin_tone", - "man_health_worker_tone3", - "man_health_worker_medium_skin_tone", - "man_health_worker_tone4", - "man_health_worker_medium_dark_skin_tone", - "man_health_worker_tone5", - "man_health_worker_dark_skin_tone", - "farmer", - "farmer_tone1", - "farmer_light_skin_tone", - "farmer_tone2", - "farmer_medium_light_skin_tone", - "farmer_tone3", - "farmer_medium_skin_tone", - "farmer_tone4", - "farmer_medium_dark_skin_tone", - "farmer_tone5", - "farmer_dark_skin_tone", - "woman_farmer", - "woman_farmer_tone1", - "woman_farmer_light_skin_tone", - "woman_farmer_tone2", - "woman_farmer_medium_light_skin_tone", - "woman_farmer_tone3", - "woman_farmer_medium_skin_tone", - "woman_farmer_tone4", - "woman_farmer_medium_dark_skin_tone", - "woman_farmer_tone5", - "woman_farmer_dark_skin_tone", - "man_farmer", - "man_farmer_tone1", - "man_farmer_light_skin_tone", - "man_farmer_tone2", - "man_farmer_medium_light_skin_tone", - "man_farmer_tone3", - "man_farmer_medium_skin_tone", - "man_farmer_tone4", - "man_farmer_medium_dark_skin_tone", - "man_farmer_tone5", - "man_farmer_dark_skin_tone", - "cook", - "cook_tone1", - "cook_light_skin_tone", - "cook_tone2", - "cook_medium_light_skin_tone", - "cook_tone3", - "cook_medium_skin_tone", - "cook_tone4", - "cook_medium_dark_skin_tone", - "cook_tone5", - "cook_dark_skin_tone", - "woman_cook", - "woman_cook_tone1", - "woman_cook_light_skin_tone", - "woman_cook_tone2", - "woman_cook_medium_light_skin_tone", - "woman_cook_tone3", - "woman_cook_medium_skin_tone", - "woman_cook_tone4", - "woman_cook_medium_dark_skin_tone", - "woman_cook_tone5", - "woman_cook_dark_skin_tone", - "man_cook", - "man_cook_tone1", - "man_cook_light_skin_tone", - "man_cook_tone2", - "man_cook_medium_light_skin_tone", - "man_cook_tone3", - "man_cook_medium_skin_tone", - "man_cook_tone4", - "man_cook_medium_dark_skin_tone", - "man_cook_tone5", - "man_cook_dark_skin_tone", - "student", - "student_tone1", - "student_light_skin_tone", - "student_tone2", - "student_medium_light_skin_tone", - "student_tone3", - "student_medium_skin_tone", - "student_tone4", - "student_medium_dark_skin_tone", - "student_tone5", - "student_dark_skin_tone", - "woman_student", - "woman_student_tone1", - "woman_student_light_skin_tone", - "woman_student_tone2", - "woman_student_medium_light_skin_tone", - "woman_student_tone3", - "woman_student_medium_skin_tone", - "woman_student_tone4", - "woman_student_medium_dark_skin_tone", - "woman_student_tone5", - "woman_student_dark_skin_tone", - "man_student", - "man_student_tone1", - "man_student_light_skin_tone", - "man_student_tone2", - "man_student_medium_light_skin_tone", - "man_student_tone3", - "man_student_medium_skin_tone", - "man_student_tone4", - "man_student_medium_dark_skin_tone", - "man_student_tone5", - "man_student_dark_skin_tone", - "singer", - "singer_tone1", - "singer_light_skin_tone", - "singer_tone2", - "singer_medium_light_skin_tone", - "singer_tone3", - "singer_medium_skin_tone", - "singer_tone4", - "singer_medium_dark_skin_tone", - "singer_tone5", - "singer_dark_skin_tone", - "woman_singer", - "woman_singer_tone1", - "woman_singer_light_skin_tone", - "woman_singer_tone2", - "woman_singer_medium_light_skin_tone", - "woman_singer_tone3", - "woman_singer_medium_skin_tone", - "woman_singer_tone4", - "woman_singer_medium_dark_skin_tone", - "woman_singer_tone5", - "woman_singer_dark_skin_tone", - "man_singer", - "man_singer_tone1", - "man_singer_light_skin_tone", - "man_singer_tone2", - "man_singer_medium_light_skin_tone", - "man_singer_tone3", - "man_singer_medium_skin_tone", - "man_singer_tone4", - "man_singer_medium_dark_skin_tone", - "man_singer_tone5", - "man_singer_dark_skin_tone", - "teacher", - "teacher_tone1", - "teacher_light_skin_tone", - "teacher_tone2", - "teacher_medium_light_skin_tone", - "teacher_tone3", - "teacher_medium_skin_tone", - "teacher_tone4", - "teacher_medium_dark_skin_tone", - "teacher_tone5", - "teacher_dark_skin_tone", - "woman_teacher", - "woman_teacher_tone1", - "woman_teacher_light_skin_tone", - "woman_teacher_tone2", - "woman_teacher_medium_light_skin_tone", - "woman_teacher_tone3", - "woman_teacher_medium_skin_tone", - "woman_teacher_tone4", - "woman_teacher_medium_dark_skin_tone", - "woman_teacher_tone5", - "woman_teacher_dark_skin_tone", - "man_teacher", - "man_teacher_tone1", - "man_teacher_light_skin_tone", - "man_teacher_tone2", - "man_teacher_medium_light_skin_tone", - "man_teacher_tone3", - "man_teacher_medium_skin_tone", - "man_teacher_tone4", - "man_teacher_medium_dark_skin_tone", - "man_teacher_tone5", - "man_teacher_dark_skin_tone", - "factory_worker", - "factory_worker_tone1", - "factory_worker_light_skin_tone", - "factory_worker_tone2", - "factory_worker_medium_light_skin_tone", - "factory_worker_tone3", - "factory_worker_medium_skin_tone", - "factory_worker_tone4", - "factory_worker_medium_dark_skin_tone", - "factory_worker_tone5", - "factory_worker_dark_skin_tone", - "woman_factory_worker", - "woman_factory_worker_tone1", - "woman_factory_worker_light_skin_tone", - "woman_factory_worker_tone2", - "woman_factory_worker_medium_light_skin_tone", - "woman_factory_worker_tone3", - "woman_factory_worker_medium_skin_tone", - "woman_factory_worker_tone4", - "woman_factory_worker_medium_dark_skin_tone", - "woman_factory_worker_tone5", - "woman_factory_worker_dark_skin_tone", - "man_factory_worker", - "man_factory_worker_tone1", - "man_factory_worker_light_skin_tone", - "man_factory_worker_tone2", - "man_factory_worker_medium_light_skin_tone", - "man_factory_worker_tone3", - "man_factory_worker_medium_skin_tone", - "man_factory_worker_tone4", - "man_factory_worker_medium_dark_skin_tone", - "man_factory_worker_tone5", - "man_factory_worker_dark_skin_tone", - "technologist", - "technologist_tone1", - "technologist_light_skin_tone", - "technologist_tone2", - "technologist_medium_light_skin_tone", - "technologist_tone3", - "technologist_medium_skin_tone", - "technologist_tone4", - "technologist_medium_dark_skin_tone", - "technologist_tone5", - "technologist_dark_skin_tone", - "woman_technologist", - "woman_technologist_tone1", - "woman_technologist_light_skin_tone", - "woman_technologist_tone2", - "woman_technologist_medium_light_skin_tone", - "woman_technologist_tone3", - "woman_technologist_medium_skin_tone", - "woman_technologist_tone4", - "woman_technologist_medium_dark_skin_tone", - "woman_technologist_tone5", - "woman_technologist_dark_skin_tone", - "man_technologist", - "man_technologist_tone1", - "man_technologist_light_skin_tone", - "man_technologist_tone2", - "man_technologist_medium_light_skin_tone", - "man_technologist_tone3", - "man_technologist_medium_skin_tone", - "man_technologist_tone4", - "man_technologist_medium_dark_skin_tone", - "man_technologist_tone5", - "man_technologist_dark_skin_tone", - "office_worker", - "office_worker_tone1", - "office_worker_light_skin_tone", - "office_worker_tone2", - "office_worker_medium_light_skin_tone", - "office_worker_tone3", - "office_worker_medium_skin_tone", - "office_worker_tone4", - "office_worker_medium_dark_skin_tone", - "office_worker_tone5", - "office_worker_dark_skin_tone", - "woman_office_worker", - "woman_office_worker_tone1", - "woman_office_worker_light_skin_tone", - "woman_office_worker_tone2", - "woman_office_worker_medium_light_skin_tone", - "woman_office_worker_tone3", - "woman_office_worker_medium_skin_tone", - "woman_office_worker_tone4", - "woman_office_worker_medium_dark_skin_tone", - "woman_office_worker_tone5", - "woman_office_worker_dark_skin_tone", - "man_office_worker", - "man_office_worker_tone1", - "man_office_worker_light_skin_tone", - "man_office_worker_tone2", - "man_office_worker_medium_light_skin_tone", - "man_office_worker_tone3", - "man_office_worker_medium_skin_tone", - "man_office_worker_tone4", - "man_office_worker_medium_dark_skin_tone", - "man_office_worker_tone5", - "man_office_worker_dark_skin_tone", - "mechanic", - "mechanic_tone1", - "mechanic_light_skin_tone", - "mechanic_tone2", - "mechanic_medium_light_skin_tone", - "mechanic_tone3", - "mechanic_medium_skin_tone", - "mechanic_tone4", - "mechanic_medium_dark_skin_tone", - "mechanic_tone5", - "mechanic_dark_skin_tone", - "woman_mechanic", - "woman_mechanic_tone1", - "woman_mechanic_light_skin_tone", - "woman_mechanic_tone2", - "woman_mechanic_medium_light_skin_tone", - "woman_mechanic_tone3", - "woman_mechanic_medium_skin_tone", - "woman_mechanic_tone4", - "woman_mechanic_medium_dark_skin_tone", - "woman_mechanic_tone5", - "woman_mechanic_dark_skin_tone", - "man_mechanic", - "man_mechanic_tone1", - "man_mechanic_light_skin_tone", - "man_mechanic_tone2", - "man_mechanic_medium_light_skin_tone", - "man_mechanic_tone3", - "man_mechanic_medium_skin_tone", - "man_mechanic_tone4", - "man_mechanic_medium_dark_skin_tone", - "man_mechanic_tone5", - "man_mechanic_dark_skin_tone", - "scientist", - "scientist_tone1", - "scientist_light_skin_tone", - "scientist_tone2", - "scientist_medium_light_skin_tone", - "scientist_tone3", - "scientist_medium_skin_tone", - "scientist_tone4", - "scientist_medium_dark_skin_tone", - "scientist_tone5", - "scientist_dark_skin_tone", - "woman_scientist", - "woman_scientist_tone1", - "woman_scientist_light_skin_tone", - "woman_scientist_tone2", - "woman_scientist_medium_light_skin_tone", - "woman_scientist_tone3", - "woman_scientist_medium_skin_tone", - "woman_scientist_tone4", - "woman_scientist_medium_dark_skin_tone", - "woman_scientist_tone5", - "woman_scientist_dark_skin_tone", - "man_scientist", - "man_scientist_tone1", - "man_scientist_light_skin_tone", - "man_scientist_tone2", - "man_scientist_medium_light_skin_tone", - "man_scientist_tone3", - "man_scientist_medium_skin_tone", - "man_scientist_tone4", - "man_scientist_medium_dark_skin_tone", - "man_scientist_tone5", - "man_scientist_dark_skin_tone", - "artist", - "artist_tone1", - "artist_light_skin_tone", - "artist_tone2", - "artist_medium_light_skin_tone", - "artist_tone3", - "artist_medium_skin_tone", - "artist_tone4", - "artist_medium_dark_skin_tone", - "artist_tone5", - "artist_dark_skin_tone", - "woman_artist", - "woman_artist_tone1", - "woman_artist_light_skin_tone", - "woman_artist_tone2", - "woman_artist_medium_light_skin_tone", - "woman_artist_tone3", - "woman_artist_medium_skin_tone", - "woman_artist_tone4", - "woman_artist_medium_dark_skin_tone", - "woman_artist_tone5", - "woman_artist_dark_skin_tone", - "man_artist", - "man_artist_tone1", - "man_artist_light_skin_tone", - "man_artist_tone2", - "man_artist_medium_light_skin_tone", - "man_artist_tone3", - "man_artist_medium_skin_tone", - "man_artist_tone4", - "man_artist_medium_dark_skin_tone", - "man_artist_tone5", - "man_artist_dark_skin_tone", - "firefighter", - "firefighter_tone1", - "firefighter_light_skin_tone", - "firefighter_tone2", - "firefighter_medium_light_skin_tone", - "firefighter_tone3", - "firefighter_medium_skin_tone", - "firefighter_tone4", - "firefighter_medium_dark_skin_tone", - "firefighter_tone5", - "firefighter_dark_skin_tone", - "woman_firefighter", - "woman_firefighter_tone1", - "woman_firefighter_light_skin_tone", - "woman_firefighter_tone2", - "woman_firefighter_medium_light_skin_tone", - "woman_firefighter_tone3", - "woman_firefighter_medium_skin_tone", - "woman_firefighter_tone4", - "woman_firefighter_medium_dark_skin_tone", - "woman_firefighter_tone5", - "woman_firefighter_dark_skin_tone", - "man_firefighter", - "man_firefighter_tone1", - "man_firefighter_light_skin_tone", - "man_firefighter_tone2", - "man_firefighter_medium_light_skin_tone", - "man_firefighter_tone3", - "man_firefighter_medium_skin_tone", - "man_firefighter_tone4", - "man_firefighter_medium_dark_skin_tone", - "man_firefighter_tone5", - "man_firefighter_dark_skin_tone", - "pilot", - "pilot_tone1", - "pilot_light_skin_tone", - "pilot_tone2", - "pilot_medium_light_skin_tone", - "pilot_tone3", - "pilot_medium_skin_tone", - "pilot_tone4", - "pilot_medium_dark_skin_tone", - "pilot_tone5", - "pilot_dark_skin_tone", - "woman_pilot", - "woman_pilot_tone1", - "woman_pilot_light_skin_tone", - "woman_pilot_tone2", - "woman_pilot_medium_light_skin_tone", - "woman_pilot_tone3", - "woman_pilot_medium_skin_tone", - "woman_pilot_tone4", - "woman_pilot_medium_dark_skin_tone", - "woman_pilot_tone5", - "woman_pilot_dark_skin_tone", - "man_pilot", - "man_pilot_tone1", - "man_pilot_light_skin_tone", - "man_pilot_tone2", - "man_pilot_medium_light_skin_tone", - "man_pilot_tone3", - "man_pilot_medium_skin_tone", - "man_pilot_tone4", - "man_pilot_medium_dark_skin_tone", - "man_pilot_tone5", - "man_pilot_dark_skin_tone", - "astronaut", - "astronaut_tone1", - "astronaut_light_skin_tone", - "astronaut_tone2", - "astronaut_medium_light_skin_tone", - "astronaut_tone3", - "astronaut_medium_skin_tone", - "astronaut_tone4", - "astronaut_medium_dark_skin_tone", - "astronaut_tone5", - "astronaut_dark_skin_tone", - "woman_astronaut", - "woman_astronaut_tone1", - "woman_astronaut_light_skin_tone", - "woman_astronaut_tone2", - "woman_astronaut_medium_light_skin_tone", - "woman_astronaut_tone3", - "woman_astronaut_medium_skin_tone", - "woman_astronaut_tone4", - "woman_astronaut_medium_dark_skin_tone", - "woman_astronaut_tone5", - "woman_astronaut_dark_skin_tone", - "man_astronaut", - "man_astronaut_tone1", - "man_astronaut_light_skin_tone", - "man_astronaut_tone2", - "man_astronaut_medium_light_skin_tone", - "man_astronaut_tone3", - "man_astronaut_medium_skin_tone", - "man_astronaut_tone4", - "man_astronaut_medium_dark_skin_tone", - "man_astronaut_tone5", - "man_astronaut_dark_skin_tone", - "judge", - "judge_tone1", - "judge_light_skin_tone", - "judge_tone2", - "judge_medium_light_skin_tone", - "judge_tone3", - "judge_medium_skin_tone", - "judge_tone4", - "judge_medium_dark_skin_tone", - "judge_tone5", - "judge_dark_skin_tone", - "woman_judge", - "woman_judge_tone1", - "woman_judge_light_skin_tone", - "woman_judge_tone2", - "woman_judge_medium_light_skin_tone", - "woman_judge_tone3", - "woman_judge_medium_skin_tone", - "woman_judge_tone4", - "woman_judge_medium_dark_skin_tone", - "woman_judge_tone5", - "woman_judge_dark_skin_tone", - "man_judge", - "man_judge_tone1", - "man_judge_light_skin_tone", - "man_judge_tone2", - "man_judge_medium_light_skin_tone", - "man_judge_tone3", - "man_judge_medium_skin_tone", - "man_judge_tone4", - "man_judge_medium_dark_skin_tone", - "man_judge_tone5", - "man_judge_dark_skin_tone", - "person_with_veil", - "person_with_veil_tone1", - "person_with_veil_tone2", - "person_with_veil_tone3", - "person_with_veil_tone4", - "person_with_veil_tone5", - "woman_with_veil", - "bride_with_veil", - "woman_with_veil_tone1", - "woman_with_veil_light_skin_tone", - "woman_with_veil_tone2", - "woman_with_veil_medium_light_skin_tone", - "woman_with_veil_tone3", - "woman_with_veil_medium_skin_tone", - "woman_with_veil_tone4", - "woman_with_veil_medium_dark_skin_tone", - "woman_with_veil_tone5", - "woman_with_veil_dark_skin_tone", - "man_with_veil", - "man_with_veil_tone1", - "man_with_veil_light_skin_tone", - "man_with_veil_tone2", - "man_with_veil_medium_light_skin_tone", - "man_with_veil_tone3", - "man_with_veil_medium_skin_tone", - "man_with_veil_tone4", - "man_with_veil_medium_dark_skin_tone", - "man_with_veil_tone5", - "man_with_veil_dark_skin_tone", - "person_in_tuxedo", - "person_in_tuxedo_tone1", - "tuxedo_tone1", - "person_in_tuxedo_tone2", - "tuxedo_tone2", - "person_in_tuxedo_tone3", - "tuxedo_tone3", - "person_in_tuxedo_tone4", - "tuxedo_tone4", - "person_in_tuxedo_tone5", - "tuxedo_tone5", - "woman_in_tuxedo", - "woman_in_tuxedo_tone1", - "woman_in_tuxedo_light_skin_tone", - "woman_in_tuxedo_tone2", - "woman_in_tuxedo_medium_light_skin_tone", - "woman_in_tuxedo_tone3", - "woman_in_tuxedo_medium_skin_tone", - "woman_in_tuxedo_tone4", - "woman_in_tuxedo_medium_dark_skin_tone", - "woman_in_tuxedo_tone5", - "woman_in_tuxedo_dark_skin_tone", - "man_in_tuxedo", - "man_in_tuxedo_tone1", - "man_in_tuxedo_light_skin_tone", - "man_in_tuxedo_tone2", - "man_in_tuxedo_medium_light_skin_tone", - "man_in_tuxedo_tone3", - "man_in_tuxedo_medium_skin_tone", - "man_in_tuxedo_tone4", - "man_in_tuxedo_medium_dark_skin_tone", - "man_in_tuxedo_tone5", - "man_in_tuxedo_dark_skin_tone", - "person_with_crown", - "person_with_crown_tone1", - "person_with_crown_light_skin_tone", - "person_with_crown_tone2", - "person_with_crown_medium_light_skin_tone", - "person_with_crown_tone3", - "person_with_crown_medium_skin_tone", - "person_with_crown_tone4", - "person_with_crown_medium_dark_skin_tone", - "person_with_crown_tone5", - "person_with_crown_dark_skin_tone", - "princess", - "princess_tone1", - "princess_tone2", - "princess_tone3", - "princess_tone4", - "princess_tone5", - "prince", - "prince_tone1", - "prince_tone2", - "prince_tone3", - "prince_tone4", - "prince_tone5", - "superhero", - "superhero_tone1", - "superhero_light_skin_tone", - "superhero_tone2", - "superhero_medium_light_skin_tone", - "superhero_tone3", - "superhero_medium_skin_tone", - "superhero_tone4", - "superhero_medium_dark_skin_tone", - "superhero_tone5", - "superhero_dark_skin_tone", - "woman_superhero", - "woman_superhero_tone1", - "woman_superhero_light_skin_tone", - "woman_superhero_tone2", - "woman_superhero_medium_light_skin_tone", - "woman_superhero_tone3", - "woman_superhero_medium_skin_tone", - "woman_superhero_tone4", - "woman_superhero_medium_dark_skin_tone", - "woman_superhero_tone5", - "woman_superhero_dark_skin_tone", - "man_superhero", - "man_superhero_tone1", - "man_superhero_light_skin_tone", - "man_superhero_tone2", - "man_superhero_medium_light_skin_tone", - "man_superhero_tone3", - "man_superhero_medium_skin_tone", - "man_superhero_tone4", - "man_superhero_medium_dark_skin_tone", - "man_superhero_tone5", - "man_superhero_dark_skin_tone", - "supervillain", - "supervillain_tone1", - "supervillain_light_skin_tone", - "supervillain_tone2", - "supervillain_medium_light_skin_tone", - "supervillain_tone3", - "supervillain_medium_skin_tone", - "supervillain_tone4", - "supervillain_medium_dark_skin_tone", - "supervillain_tone5", - "supervillain_dark_skin_tone", - "woman_supervillain", - "woman_supervillain_tone1", - "woman_supervillain_light_skin_tone", - "woman_supervillain_tone2", - "woman_supervillain_medium_light_skin_tone", - "woman_supervillain_tone3", - "woman_supervillain_medium_skin_tone", - "woman_supervillain_tone4", - "woman_supervillain_medium_dark_skin_tone", - "woman_supervillain_tone5", - "woman_supervillain_dark_skin_tone", - "man_supervillain", - "man_supervillain_tone1", - "man_supervillain_light_skin_tone", - "man_supervillain_tone2", - "man_supervillain_medium_light_skin_tone", - "man_supervillain_tone3", - "man_supervillain_medium_skin_tone", - "man_supervillain_tone4", - "man_supervillain_medium_dark_skin_tone", - "man_supervillain_tone5", - "man_supervillain_dark_skin_tone", - "ninja", - "ninja_tone1", - "ninja_light_skin_tone", - "ninja_tone2", - "ninja_medium_light_skin_tone", - "ninja_tone3", - "ninja_medium_skin_tone", - "ninja_tone4", - "ninja_medium_dark_skin_tone", - "ninja_tone5", - "ninja_dark_skin_tone", - "mx_claus", - "mx_claus_tone1", - "mx_claus_light_skin_tone", - "mx_claus_tone2", - "mx_claus_medium_light_skin_tone", - "mx_claus_tone3", - "mx_claus_medium_skin_tone", - "mx_claus_tone4", - "mx_claus_medium_dark_skin_tone", - "mx_claus_tone5", - "mx_claus_dark_skin_tone", - "mrs_claus", - "mother_christmas", - "mrs_claus_tone1", - "mother_christmas_tone1", - "mrs_claus_tone2", - "mother_christmas_tone2", - "mrs_claus_tone3", - "mother_christmas_tone3", - "mrs_claus_tone4", - "mother_christmas_tone4", - "mrs_claus_tone5", - "mother_christmas_tone5", - "santa", - "santa_claus", - "santa_tone1", - "santa_tone2", - "santa_tone3", - "santa_tone4", - "santa_tone5", - "mage", - "mage_tone1", - "mage_light_skin_tone", - "mage_tone2", - "mage_medium_light_skin_tone", - "mage_tone3", - "mage_medium_skin_tone", - "mage_tone4", - "mage_medium_dark_skin_tone", - "mage_tone5", - "mage_dark_skin_tone", - "woman_mage", - "woman_mage_tone1", - "woman_mage_light_skin_tone", - "woman_mage_tone2", - "woman_mage_medium_light_skin_tone", - "woman_mage_tone3", - "woman_mage_medium_skin_tone", - "woman_mage_tone4", - "woman_mage_medium_dark_skin_tone", - "woman_mage_tone5", - "woman_mage_dark_skin_tone", - "man_mage", - "man_mage_tone1", - "man_mage_light_skin_tone", - "man_mage_tone2", - "man_mage_medium_light_skin_tone", - "man_mage_tone3", - "man_mage_medium_skin_tone", - "man_mage_tone4", - "man_mage_medium_dark_skin_tone", - "man_mage_tone5", - "man_mage_dark_skin_tone", - "elf", - "elf_tone1", - "elf_light_skin_tone", - "elf_tone2", - "elf_medium_light_skin_tone", - "elf_tone3", - "elf_medium_skin_tone", - "elf_tone4", - "elf_medium_dark_skin_tone", - "elf_tone5", - "elf_dark_skin_tone", - "woman_elf", - "woman_elf_tone1", - "woman_elf_light_skin_tone", - "woman_elf_tone2", - "woman_elf_medium_light_skin_tone", - "woman_elf_tone3", - "woman_elf_medium_skin_tone", - "woman_elf_tone4", - "woman_elf_medium_dark_skin_tone", - "woman_elf_tone5", - "woman_elf_dark_skin_tone", - "man_elf", - "man_elf_tone1", - "man_elf_light_skin_tone", - "man_elf_tone2", - "man_elf_medium_light_skin_tone", - "man_elf_tone3", - "man_elf_medium_skin_tone", - "man_elf_tone4", - "man_elf_medium_dark_skin_tone", - "man_elf_tone5", - "man_elf_dark_skin_tone", - "troll", - "vampire", - "vampire_tone1", - "vampire_light_skin_tone", - "vampire_tone2", - "vampire_medium_light_skin_tone", - "vampire_tone3", - "vampire_medium_skin_tone", - "vampire_tone4", - "vampire_medium_dark_skin_tone", - "vampire_tone5", - "vampire_dark_skin_tone", - "woman_vampire", - "woman_vampire_tone1", - "woman_vampire_light_skin_tone", - "woman_vampire_tone2", - "woman_vampire_medium_light_skin_tone", - "woman_vampire_tone3", - "woman_vampire_medium_skin_tone", - "woman_vampire_tone4", - "woman_vampire_medium_dark_skin_tone", - "woman_vampire_tone5", - "woman_vampire_dark_skin_tone", - "man_vampire", - "man_vampire_tone1", - "man_vampire_light_skin_tone", - "man_vampire_tone2", - "man_vampire_medium_light_skin_tone", - "man_vampire_tone3", - "man_vampire_medium_skin_tone", - "man_vampire_tone4", - "man_vampire_medium_dark_skin_tone", - "man_vampire_tone5", - "man_vampire_dark_skin_tone", - "zombie", - "woman_zombie", - "man_zombie", - "genie", - "woman_genie", - "man_genie", - "merperson", - "merperson_tone1", - "merperson_light_skin_tone", - "merperson_tone2", - "merperson_medium_light_skin_tone", - "merperson_tone3", - "merperson_medium_skin_tone", - "merperson_tone4", - "merperson_medium_dark_skin_tone", - "merperson_tone5", - "merperson_dark_skin_tone", - "mermaid", - "mermaid_tone1", - "mermaid_light_skin_tone", - "mermaid_tone2", - "mermaid_medium_light_skin_tone", - "mermaid_tone3", - "mermaid_medium_skin_tone", - "mermaid_tone4", - "mermaid_medium_dark_skin_tone", - "mermaid_tone5", - "mermaid_dark_skin_tone", - "merman", - "merman_tone1", - "merman_light_skin_tone", - "merman_tone2", - "merman_medium_light_skin_tone", - "merman_tone3", - "merman_medium_skin_tone", - "merman_tone4", - "merman_medium_dark_skin_tone", - "merman_tone5", - "merman_dark_skin_tone", - "fairy", - "fairy_tone1", - "fairy_light_skin_tone", - "fairy_tone2", - "fairy_medium_light_skin_tone", - "fairy_tone3", - "fairy_medium_skin_tone", - "fairy_tone4", - "fairy_medium_dark_skin_tone", - "fairy_tone5", - "fairy_dark_skin_tone", - "woman_fairy", - "woman_fairy_tone1", - "woman_fairy_light_skin_tone", - "woman_fairy_tone2", - "woman_fairy_medium_light_skin_tone", - "woman_fairy_tone3", - "woman_fairy_medium_skin_tone", - "woman_fairy_tone4", - "woman_fairy_medium_dark_skin_tone", - "woman_fairy_tone5", - "woman_fairy_dark_skin_tone", - "man_fairy", - "man_fairy_tone1", - "man_fairy_light_skin_tone", - "man_fairy_tone2", - "man_fairy_medium_light_skin_tone", - "man_fairy_tone3", - "man_fairy_medium_skin_tone", - "man_fairy_tone4", - "man_fairy_medium_dark_skin_tone", - "man_fairy_tone5", - "man_fairy_dark_skin_tone", - "angel", - "baby_angel", - "angel_tone1", - "angel_tone2", - "angel_tone3", - "angel_tone4", - "angel_tone5", - "pregnant_person", - "pregnant_person_tone1", - "pregnant_person_light_skin_tone", - "pregnant_person_tone2", - "pregnant_person_medium_light_skin_tone", - "pregnant_person_tone3", - "pregnant_person_medium_skin_tone", - "pregnant_person_tone4", - "pregnant_person_medium_dark_skin_tone", - "pregnant_person_tone5", - "pregnant_person_dark_skin_tone", - "pregnant_woman", - "expecting_woman", - "pregnant_woman_tone1", - "expecting_woman_tone1", - "pregnant_woman_tone2", - "expecting_woman_tone2", - "pregnant_woman_tone3", - "expecting_woman_tone3", - "pregnant_woman_tone4", - "expecting_woman_tone4", - "pregnant_woman_tone5", - "expecting_woman_tone5", - "pregnant_man", - "pregnant_man_tone1", - "pregnant_man_light_skin_tone", - "pregnant_man_tone2", - "pregnant_man_medium_light_skin_tone", - "pregnant_man_tone3", - "pregnant_man_medium_skin_tone", - "pregnant_man_tone4", - "pregnant_man_medium_dark_skin_tone", - "pregnant_man_tone5", - "pregnant_man_dark_skin_tone", - "breast_feeding", - "breast_feeding_tone1", - "breast_feeding_light_skin_tone", - "breast_feeding_tone2", - "breast_feeding_medium_light_skin_tone", - "breast_feeding_tone3", - "breast_feeding_medium_skin_tone", - "breast_feeding_tone4", - "breast_feeding_medium_dark_skin_tone", - "breast_feeding_tone5", - "breast_feeding_dark_skin_tone", - "person_feeding_baby", - "person_feeding_baby_tone1", - "person_feeding_baby_light_skin_tone", - "person_feeding_baby_tone2", - "person_feeding_baby_medium_light_skin_tone", - "person_feeding_baby_tone3", - "person_feeding_baby_medium_skin_tone", - "person_feeding_baby_tone4", - "person_feeding_baby_medium_dark_skin_tone", - "person_feeding_baby_tone5", - "person_feeding_baby_dark_skin_tone", - "woman_feeding_baby", - "woman_feeding_baby_tone1", - "woman_feeding_baby_light_skin_tone", - "woman_feeding_baby_tone2", - "woman_feeding_baby_medium_light_skin_tone", - "woman_feeding_baby_tone3", - "woman_feeding_baby_medium_skin_tone", - "woman_feeding_baby_tone4", - "woman_feeding_baby_medium_dark_skin_tone", - "woman_feeding_baby_tone5", - "woman_feeding_baby_dark_skin_tone", - "man_feeding_baby", - "man_feeding_baby_tone1", - "man_feeding_baby_light_skin_tone", - "man_feeding_baby_tone2", - "man_feeding_baby_medium_light_skin_tone", - "man_feeding_baby_tone3", - "man_feeding_baby_medium_skin_tone", - "man_feeding_baby_tone4", - "man_feeding_baby_medium_dark_skin_tone", - "man_feeding_baby_tone5", - "man_feeding_baby_dark_skin_tone", - "person_bowing", - "bow", - "person_bowing_tone1", - "bow_tone1", - "person_bowing_tone2", - "bow_tone2", - "person_bowing_tone3", - "bow_tone3", - "person_bowing_tone4", - "bow_tone4", - "person_bowing_tone5", - "bow_tone5", - "woman_bowing", - "woman_bowing_tone1", - "woman_bowing_light_skin_tone", - "woman_bowing_tone2", - "woman_bowing_medium_light_skin_tone", - "woman_bowing_tone3", - "woman_bowing_medium_skin_tone", - "woman_bowing_tone4", - "woman_bowing_medium_dark_skin_tone", - "woman_bowing_tone5", - "woman_bowing_dark_skin_tone", - "man_bowing", - "man_bowing_tone1", - "man_bowing_light_skin_tone", - "man_bowing_tone2", - "man_bowing_medium_light_skin_tone", - "man_bowing_tone3", - "man_bowing_medium_skin_tone", - "man_bowing_tone4", - "man_bowing_medium_dark_skin_tone", - "man_bowing_tone5", - "man_bowing_dark_skin_tone", - "person_tipping_hand", - "information_desk_person", - "person_tipping_hand_tone1", - "information_desk_person_tone1", - "person_tipping_hand_tone2", - "information_desk_person_tone2", - "person_tipping_hand_tone3", - "information_desk_person_tone3", - "person_tipping_hand_tone4", - "information_desk_person_tone4", - "person_tipping_hand_tone5", - "information_desk_person_tone5", - "woman_tipping_hand", - "woman_tipping_hand_tone1", - "woman_tipping_hand_light_skin_tone", - "woman_tipping_hand_tone2", - "woman_tipping_hand_medium_light_skin_tone", - "woman_tipping_hand_tone3", - "woman_tipping_hand_medium_skin_tone", - "woman_tipping_hand_tone4", - "woman_tipping_hand_medium_dark_skin_tone", - "woman_tipping_hand_tone5", - "woman_tipping_hand_dark_skin_tone", - "man_tipping_hand", - "man_tipping_hand_tone1", - "man_tipping_hand_light_skin_tone", - "man_tipping_hand_tone2", - "man_tipping_hand_medium_light_skin_tone", - "man_tipping_hand_tone3", - "man_tipping_hand_medium_skin_tone", - "man_tipping_hand_tone4", - "man_tipping_hand_medium_dark_skin_tone", - "man_tipping_hand_tone5", - "man_tipping_hand_dark_skin_tone", - "person_gesturing_no", - "no_good", - "person_gesturing_no_tone1", - "no_good_tone1", - "person_gesturing_no_tone2", - "no_good_tone2", - "person_gesturing_no_tone3", - "no_good_tone3", - "person_gesturing_no_tone4", - "no_good_tone4", - "person_gesturing_no_tone5", - "no_good_tone5", - "woman_gesturing_no", - "woman_gesturing_no_tone1", - "woman_gesturing_no_light_skin_tone", - "woman_gesturing_no_tone2", - "woman_gesturing_no_medium_light_skin_tone", - "woman_gesturing_no_tone3", - "woman_gesturing_no_medium_skin_tone", - "woman_gesturing_no_tone4", - "woman_gesturing_no_medium_dark_skin_tone", - "woman_gesturing_no_tone5", - "woman_gesturing_no_dark_skin_tone", - "man_gesturing_no", - "man_gesturing_no_tone1", - "man_gesturing_no_light_skin_tone", - "man_gesturing_no_tone2", - "man_gesturing_no_medium_light_skin_tone", - "man_gesturing_no_tone3", - "man_gesturing_no_medium_skin_tone", - "man_gesturing_no_tone4", - "man_gesturing_no_medium_dark_skin_tone", - "man_gesturing_no_tone5", - "man_gesturing_no_dark_skin_tone", - "person_gesturing_ok", - "person_gesturing_ok_tone1", - "person_gesturing_ok_tone2", - "person_gesturing_ok_tone3", - "person_gesturing_ok_tone4", - "person_gesturing_ok_tone5", - "woman_gesturing_ok", - "woman_gesturing_ok_tone1", - "woman_gesturing_ok_light_skin_tone", - "woman_gesturing_ok_tone2", - "woman_gesturing_ok_medium_light_skin_tone", - "woman_gesturing_ok_tone3", - "woman_gesturing_ok_medium_skin_tone", - "woman_gesturing_ok_tone4", - "woman_gesturing_ok_medium_dark_skin_tone", - "woman_gesturing_ok_tone5", - "woman_gesturing_ok_dark_skin_tone", - "man_gesturing_ok", - "man_gesturing_ok_tone1", - "man_gesturing_ok_light_skin_tone", - "man_gesturing_ok_tone2", - "man_gesturing_ok_medium_light_skin_tone", - "man_gesturing_ok_tone3", - "man_gesturing_ok_medium_skin_tone", - "man_gesturing_ok_tone4", - "man_gesturing_ok_medium_dark_skin_tone", - "man_gesturing_ok_tone5", - "man_gesturing_ok_dark_skin_tone", - "person_raising_hand", - "raising_hand", - "person_raising_hand_tone1", - "raising_hand_tone1", - "person_raising_hand_tone2", - "raising_hand_tone2", - "person_raising_hand_tone3", - "raising_hand_tone3", - "person_raising_hand_tone4", - "raising_hand_tone4", - "person_raising_hand_tone5", - "raising_hand_tone5", - "woman_raising_hand", - "woman_raising_hand_tone1", - "woman_raising_hand_light_skin_tone", - "woman_raising_hand_tone2", - "woman_raising_hand_medium_light_skin_tone", - "woman_raising_hand_tone3", - "woman_raising_hand_medium_skin_tone", - "woman_raising_hand_tone4", - "woman_raising_hand_medium_dark_skin_tone", - "woman_raising_hand_tone5", - "woman_raising_hand_dark_skin_tone", - "man_raising_hand", - "man_raising_hand_tone1", - "man_raising_hand_light_skin_tone", - "man_raising_hand_tone2", - "man_raising_hand_medium_light_skin_tone", - "man_raising_hand_tone3", - "man_raising_hand_medium_skin_tone", - "man_raising_hand_tone4", - "man_raising_hand_medium_dark_skin_tone", - "man_raising_hand_tone5", - "man_raising_hand_dark_skin_tone", - "deaf_person", - "deaf_person_tone1", - "deaf_person_light_skin_tone", - "deaf_person_tone2", - "deaf_person_medium_light_skin_tone", - "deaf_person_tone3", - "deaf_person_medium_skin_tone", - "deaf_person_tone4", - "deaf_person_medium_dark_skin_tone", - "deaf_person_tone5", - "deaf_person_dark_skin_tone", - "deaf_woman", - "deaf_woman_tone1", - "deaf_woman_light_skin_tone", - "deaf_woman_tone2", - "deaf_woman_medium_light_skin_tone", - "deaf_woman_tone3", - "deaf_woman_medium_skin_tone", - "deaf_woman_tone4", - "deaf_woman_medium_dark_skin_tone", - "deaf_woman_tone5", - "deaf_woman_dark_skin_tone", - "deaf_man", - "deaf_man_tone1", - "deaf_man_light_skin_tone", - "deaf_man_tone2", - "deaf_man_medium_light_skin_tone", - "deaf_man_tone3", - "deaf_man_medium_skin_tone", - "deaf_man_tone4", - "deaf_man_medium_dark_skin_tone", - "deaf_man_tone5", - "deaf_man_dark_skin_tone", - "person_facepalming", - "face_palm", - "facepalm", - "person_facepalming_tone1", - "face_palm_tone1", - "facepalm_tone1", - "person_facepalming_tone2", - "face_palm_tone2", - "facepalm_tone2", - "person_facepalming_tone3", - "face_palm_tone3", - "facepalm_tone3", - "person_facepalming_tone4", - "face_palm_tone4", - "facepalm_tone4", - "person_facepalming_tone5", - "face_palm_tone5", - "facepalm_tone5", - "woman_facepalming", - "woman_facepalming_tone1", - "woman_facepalming_light_skin_tone", - "woman_facepalming_tone2", - "woman_facepalming_medium_light_skin_tone", - "woman_facepalming_tone3", - "woman_facepalming_medium_skin_tone", - "woman_facepalming_tone4", - "woman_facepalming_medium_dark_skin_tone", - "woman_facepalming_tone5", - "woman_facepalming_dark_skin_tone", - "man_facepalming", - "man_facepalming_tone1", - "man_facepalming_light_skin_tone", - "man_facepalming_tone2", - "man_facepalming_medium_light_skin_tone", - "man_facepalming_tone3", - "man_facepalming_medium_skin_tone", - "man_facepalming_tone4", - "man_facepalming_medium_dark_skin_tone", - "man_facepalming_tone5", - "man_facepalming_dark_skin_tone", - "person_shrugging", - "shrug", - "person_shrugging_tone1", - "shrug_tone1", - "person_shrugging_tone2", - "shrug_tone2", - "person_shrugging_tone3", - "shrug_tone3", - "person_shrugging_tone4", - "shrug_tone4", - "person_shrugging_tone5", - "shrug_tone5", - "woman_shrugging", - "woman_shrugging_tone1", - "woman_shrugging_light_skin_tone", - "woman_shrugging_tone2", - "woman_shrugging_medium_light_skin_tone", - "woman_shrugging_tone3", - "woman_shrugging_medium_skin_tone", - "woman_shrugging_tone4", - "woman_shrugging_medium_dark_skin_tone", - "woman_shrugging_tone5", - "woman_shrugging_dark_skin_tone", - "man_shrugging", - "man_shrugging_tone1", - "man_shrugging_light_skin_tone", - "man_shrugging_tone2", - "man_shrugging_medium_light_skin_tone", - "man_shrugging_tone3", - "man_shrugging_medium_skin_tone", - "man_shrugging_tone4", - "man_shrugging_medium_dark_skin_tone", - "man_shrugging_tone5", - "man_shrugging_dark_skin_tone", - "person_pouting", - "person_with_pouting_face", - "person_pouting_tone1", - "person_with_pouting_face_tone1", - "person_pouting_tone2", - "person_with_pouting_face_tone2", - "person_pouting_tone3", - "person_with_pouting_face_tone3", - "person_pouting_tone4", - "person_with_pouting_face_tone4", - "person_pouting_tone5", - "person_with_pouting_face_tone5", - "woman_pouting", - "woman_pouting_tone1", - "woman_pouting_light_skin_tone", - "woman_pouting_tone2", - "woman_pouting_medium_light_skin_tone", - "woman_pouting_tone3", - "woman_pouting_medium_skin_tone", - "woman_pouting_tone4", - "woman_pouting_medium_dark_skin_tone", - "woman_pouting_tone5", - "woman_pouting_dark_skin_tone", - "man_pouting", - "man_pouting_tone1", - "man_pouting_light_skin_tone", - "man_pouting_tone2", - "man_pouting_medium_light_skin_tone", - "man_pouting_tone3", - "man_pouting_medium_skin_tone", - "man_pouting_tone4", - "man_pouting_medium_dark_skin_tone", - "man_pouting_tone5", - "man_pouting_dark_skin_tone", - "person_frowning", - "person_frowning_tone1", - "person_frowning_tone2", - "person_frowning_tone3", - "person_frowning_tone4", - "person_frowning_tone5", - "woman_frowning", - "woman_frowning_tone1", - "woman_frowning_light_skin_tone", - "woman_frowning_tone2", - "woman_frowning_medium_light_skin_tone", - "woman_frowning_tone3", - "woman_frowning_medium_skin_tone", - "woman_frowning_tone4", - "woman_frowning_medium_dark_skin_tone", - "woman_frowning_tone5", - "woman_frowning_dark_skin_tone", - "man_frowning", - "man_frowning_tone1", - "man_frowning_light_skin_tone", - "man_frowning_tone2", - "man_frowning_medium_light_skin_tone", - "man_frowning_tone3", - "man_frowning_medium_skin_tone", - "man_frowning_tone4", - "man_frowning_medium_dark_skin_tone", - "man_frowning_tone5", - "man_frowning_dark_skin_tone", - "person_getting_haircut", - "haircut", - "person_getting_haircut_tone1", - "haircut_tone1", - "person_getting_haircut_tone2", - "haircut_tone2", - "person_getting_haircut_tone3", - "haircut_tone3", - "person_getting_haircut_tone4", - "haircut_tone4", - "person_getting_haircut_tone5", - "haircut_tone5", - "woman_getting_haircut", - "woman_getting_haircut_tone1", - "woman_getting_haircut_light_skin_tone", - "woman_getting_haircut_tone2", - "woman_getting_haircut_medium_light_skin_tone", - "woman_getting_haircut_tone3", - "woman_getting_haircut_medium_skin_tone", - "woman_getting_haircut_tone4", - "woman_getting_haircut_medium_dark_skin_tone", - "woman_getting_haircut_tone5", - "woman_getting_haircut_dark_skin_tone", - "man_getting_haircut", - "man_getting_haircut_tone1", - "man_getting_haircut_light_skin_tone", - "man_getting_haircut_tone2", - "man_getting_haircut_medium_light_skin_tone", - "man_getting_haircut_tone3", - "man_getting_haircut_medium_skin_tone", - "man_getting_haircut_tone4", - "man_getting_haircut_medium_dark_skin_tone", - "man_getting_haircut_tone5", - "man_getting_haircut_dark_skin_tone", - "person_getting_massage", - "massage", - "person_getting_massage_tone1", - "massage_tone1", - "person_getting_massage_tone2", - "massage_tone2", - "person_getting_massage_tone3", - "massage_tone3", - "person_getting_massage_tone4", - "massage_tone4", - "person_getting_massage_tone5", - "massage_tone5", - "woman_getting_face_massage", - "woman_getting_face_massage_tone1", - "woman_getting_face_massage_light_skin_tone", - "woman_getting_face_massage_tone2", - "woman_getting_face_massage_medium_light_skin_tone", - "woman_getting_face_massage_tone3", - "woman_getting_face_massage_medium_skin_tone", - "woman_getting_face_massage_tone4", - "woman_getting_face_massage_medium_dark_skin_tone", - "woman_getting_face_massage_tone5", - "woman_getting_face_massage_dark_skin_tone", - "man_getting_face_massage", - "man_getting_face_massage_tone1", - "man_getting_face_massage_light_skin_tone", - "man_getting_face_massage_tone2", - "man_getting_face_massage_medium_light_skin_tone", - "man_getting_face_massage_tone3", - "man_getting_face_massage_medium_skin_tone", - "man_getting_face_massage_tone4", - "man_getting_face_massage_medium_dark_skin_tone", - "man_getting_face_massage_tone5", - "man_getting_face_massage_dark_skin_tone", - "person_in_steamy_room", - "person_in_steamy_room_tone1", - "person_in_steamy_room_light_skin_tone", - "person_in_steamy_room_tone2", - "person_in_steamy_room_medium_light_skin_tone", - "person_in_steamy_room_tone3", - "person_in_steamy_room_medium_skin_tone", - "person_in_steamy_room_tone4", - "person_in_steamy_room_medium_dark_skin_tone", - "person_in_steamy_room_tone5", - "person_in_steamy_room_dark_skin_tone", - "woman_in_steamy_room", - "woman_in_steamy_room_tone1", - "woman_in_steamy_room_light_skin_tone", - "woman_in_steamy_room_tone2", - "woman_in_steamy_room_medium_light_skin_tone", - "woman_in_steamy_room_tone3", - "woman_in_steamy_room_medium_skin_tone", - "woman_in_steamy_room_tone4", - "woman_in_steamy_room_medium_dark_skin_tone", - "woman_in_steamy_room_tone5", - "woman_in_steamy_room_dark_skin_tone", - "man_in_steamy_room", - "man_in_steamy_room_tone1", - "man_in_steamy_room_light_skin_tone", - "man_in_steamy_room_tone2", - "man_in_steamy_room_medium_light_skin_tone", - "man_in_steamy_room_tone3", - "man_in_steamy_room_medium_skin_tone", - "man_in_steamy_room_tone4", - "man_in_steamy_room_medium_dark_skin_tone", - "man_in_steamy_room_tone5", - "man_in_steamy_room_dark_skin_tone", - "nail_care", - "nail_polish", - "nail_care_tone1", - "nail_care_tone2", - "nail_care_tone3", - "nail_care_tone4", - "nail_care_tone5", - "selfie", - "selfie_tone1", - "selfie_tone2", - "selfie_tone3", - "selfie_tone4", - "selfie_tone5", - "dancer", - "woman_dancing", - "dancer_tone1", - "dancer_tone2", - "dancer_tone3", - "dancer_tone4", - "dancer_tone5", - "man_dancing", - "male_dancer", - "man_dancing_tone1", - "male_dancer_tone1", - "man_dancing_tone2", - "male_dancer_tone2", - "man_dancing_tone3", - "male_dancer_tone3", - "man_dancing_tone5", - "male_dancer_tone5", - "man_dancing_tone4", - "male_dancer_tone4", - "people_with_bunny_ears_partying", - "dancers", - "women_with_bunny_ears_partying", - "men_with_bunny_ears_partying", - "levitate", - "man_in_business_suit_levitating", - "levitate_tone1", - "man_in_business_suit_levitating_tone1", - "man_in_business_suit_levitating_light_skin_tone", - "levitate_tone2", - "man_in_business_suit_levitating_tone2", - "man_in_business_suit_levitating_medium_light_skin_tone", - "levitate_tone3", - "man_in_business_suit_levitating_tone3", - "man_in_business_suit_levitating_medium_skin_tone", - "levitate_tone4", - "man_in_business_suit_levitating_tone4", - "man_in_business_suit_levitating_medium_dark_skin_tone", - "levitate_tone5", - "man_in_business_suit_levitating_tone5", - "man_in_business_suit_levitating_dark_skin_tone", - "person_in_manual_wheelchair", - "person_in_manual_wheelchair_tone1", - "person_in_manual_wheelchair_light_skin_tone", - "person_in_manual_wheelchair_tone2", - "person_in_manual_wheelchair_medium_light_skin_tone", - "person_in_manual_wheelchair_tone3", - "person_in_manual_wheelchair_medium_skin_tone", - "person_in_manual_wheelchair_tone4", - "person_in_manual_wheelchair_medium_dark_skin_tone", - "person_in_manual_wheelchair_tone5", - "person_in_manual_wheelchair_dark_skin_tone", - "woman_in_manual_wheelchair", - "woman_in_manual_wheelchair_tone1", - "woman_in_manual_wheelchair_light_skin_tone", - "woman_in_manual_wheelchair_tone2", - "woman_in_manual_wheelchair_medium_light_skin_tone", - "woman_in_manual_wheelchair_tone3", - "woman_in_manual_wheelchair_medium_skin_tone", - "woman_in_manual_wheelchair_tone4", - "woman_in_manual_wheelchair_medium_dark_skin_tone", - "woman_in_manual_wheelchair_tone5", - "woman_in_manual_wheelchair_dark_skin_tone", - "man_in_manual_wheelchair", - "man_in_manual_wheelchair_tone1", - "man_in_manual_wheelchair_light_skin_tone", - "man_in_manual_wheelchair_tone2", - "man_in_manual_wheelchair_medium_light_skin_tone", - "man_in_manual_wheelchair_tone3", - "man_in_manual_wheelchair_medium_skin_tone", - "man_in_manual_wheelchair_tone4", - "man_in_manual_wheelchair_medium_dark_skin_tone", - "man_in_manual_wheelchair_tone5", - "man_in_manual_wheelchair_dark_skin_tone", - "person_in_motorized_wheelchair", - "person_in_motorized_wheelchair_tone1", - "person_in_motorized_wheelchair_light_skin_tone", - "person_in_motorized_wheelchair_tone2", - "person_in_motorized_wheelchair_medium_light_skin_tone", - "person_in_motorized_wheelchair_tone3", - "person_in_motorized_wheelchair_medium_skin_tone", - "person_in_motorized_wheelchair_tone4", - "person_in_motorized_wheelchair_medium_dark_skin_tone", - "person_in_motorized_wheelchair_tone5", - "person_in_motorized_wheelchair_dark_skin_tone", - "woman_in_motorized_wheelchair", - "woman_in_motorized_wheelchair_tone1", - "woman_in_motorized_wheelchair_light_skin_tone", - "woman_in_motorized_wheelchair_tone2", - "woman_in_motorized_wheelchair_medium_light_skin_tone", - "woman_in_motorized_wheelchair_tone3", - "woman_in_motorized_wheelchair_medium_skin_tone", - "woman_in_motorized_wheelchair_tone4", - "woman_in_motorized_wheelchair_medium_dark_skin_tone", - "woman_in_motorized_wheelchair_tone5", - "woman_in_motorized_wheelchair_dark_skin_tone", - "man_in_motorized_wheelchair", - "man_in_motorized_wheelchair_tone1", - "man_in_motorized_wheelchair_light_skin_tone", - "man_in_motorized_wheelchair_tone2", - "man_in_motorized_wheelchair_medium_light_skin_tone", - "man_in_motorized_wheelchair_tone3", - "man_in_motorized_wheelchair_medium_skin_tone", - "man_in_motorized_wheelchair_tone4", - "man_in_motorized_wheelchair_medium_dark_skin_tone", - "man_in_motorized_wheelchair_tone5", - "man_in_motorized_wheelchair_dark_skin_tone", - "person_walking", - "walking", - "person_walking_tone1", - "walking_tone1", - "person_walking_tone2", - "walking_tone2", - "person_walking_tone3", - "walking_tone3", - "person_walking_tone4", - "walking_tone4", - "person_walking_tone5", - "walking_tone5", - "woman_walking", - "woman_walking_tone1", - "woman_walking_light_skin_tone", - "woman_walking_tone2", - "woman_walking_medium_light_skin_tone", - "woman_walking_tone3", - "woman_walking_medium_skin_tone", - "woman_walking_tone4", - "woman_walking_medium_dark_skin_tone", - "woman_walking_tone5", - "woman_walking_dark_skin_tone", - "man_walking", - "man_walking_tone1", - "man_walking_light_skin_tone", - "man_walking_tone2", - "man_walking_medium_light_skin_tone", - "man_walking_tone3", - "man_walking_medium_skin_tone", - "man_walking_tone4", - "man_walking_medium_dark_skin_tone", - "man_walking_tone5", - "man_walking_dark_skin_tone", - "person_with_probing_cane", - "person_with_probing_cane_tone1", - "person_with_probing_cane_light_skin_tone", - "person_with_probing_cane_tone2", - "person_with_probing_cane_medium_light_skin_tone", - "person_with_probing_cane_tone3", - "person_with_probing_cane_medium_skin_tone", - "person_with_probing_cane_tone4", - "person_with_probing_cane_medium_dark_skin_tone", - "person_with_probing_cane_tone5", - "person_with_probing_cane_dark_skin_tone", - "woman_with_probing_cane", - "woman_with_probing_cane_tone1", - "woman_with_probing_cane_light_skin_tone", - "woman_with_probing_cane_tone2", - "woman_with_probing_cane_medium_light_skin_tone", - "woman_with_probing_cane_tone3", - "woman_with_probing_cane_medium_skin_tone", - "woman_with_probing_cane_tone4", - "woman_with_probing_cane_medium_dark_skin_tone", - "woman_with_probing_cane_tone5", - "woman_with_probing_cane_dark_skin_tone", - "man_with_probing_cane", - "man_with_probing_cane_tone1", - "man_with_probing_cane_light_skin_tone", - "man_with_probing_cane_tone2", - "man_with_probing_cane_medium_light_skin_tone", - "man_with_probing_cane_tone3", - "man_with_probing_cane_medium_skin_tone", - "man_with_probing_cane_tone4", - "man_with_probing_cane_medium_dark_skin_tone", - "man_with_probing_cane_tone5", - "man_with_probing_cane_dark_skin_tone", - "person_kneeling", - "person_kneeling_tone1", - "person_kneeling_light_skin_tone", - "person_kneeling_tone2", - "person_kneeling_medium_light_skin_tone", - "person_kneeling_tone3", - "person_kneeling_medium_skin_tone", - "person_kneeling_tone4", - "person_kneeling_medium_dark_skin_tone", - "person_kneeling_tone5", - "person_kneeling_dark_skin_tone", - "woman_kneeling", - "woman_kneeling_tone1", - "woman_kneeling_light_skin_tone", - "woman_kneeling_tone2", - "woman_kneeling_medium_light_skin_tone", - "woman_kneeling_tone3", - "woman_kneeling_medium_skin_tone", - "woman_kneeling_tone4", - "woman_kneeling_medium_dark_skin_tone", - "woman_kneeling_tone5", - "woman_kneeling_dark_skin_tone", - "man_kneeling", - "man_kneeling_tone1", - "man_kneeling_light_skin_tone", - "man_kneeling_tone2", - "man_kneeling_medium_light_skin_tone", - "man_kneeling_tone3", - "man_kneeling_medium_skin_tone", - "man_kneeling_tone4", - "man_kneeling_medium_dark_skin_tone", - "man_kneeling_tone5", - "man_kneeling_dark_skin_tone", - "person_running", - "runner", - "person_running_tone1", - "runner_tone1", - "person_running_tone2", - "runner_tone2", - "person_running_tone3", - "runner_tone3", - "person_running_tone4", - "runner_tone4", - "person_running_tone5", - "runner_tone5", - "woman_running", - "woman_running_tone1", - "woman_running_light_skin_tone", - "woman_running_tone2", - "woman_running_medium_light_skin_tone", - "woman_running_tone3", - "woman_running_medium_skin_tone", - "woman_running_tone4", - "woman_running_medium_dark_skin_tone", - "woman_running_tone5", - "woman_running_dark_skin_tone", - "man_running", - "man_running_tone1", - "man_running_light_skin_tone", - "man_running_tone2", - "man_running_medium_light_skin_tone", - "man_running_tone3", - "man_running_medium_skin_tone", - "man_running_tone4", - "man_running_medium_dark_skin_tone", - "man_running_tone5", - "man_running_dark_skin_tone", - "person_standing", - "person_standing_tone1", - "person_standing_light_skin_tone", - "person_standing_tone2", - "person_standing_medium_light_skin_tone", - "person_standing_tone3", - "person_standing_medium_skin_tone", - "person_standing_tone4", - "person_standing_medium_dark_skin_tone", - "person_standing_tone5", - "person_standing_dark_skin_tone", - "woman_standing", - "woman_standing_tone1", - "woman_standing_light_skin_tone", - "woman_standing_tone2", - "woman_standing_medium_light_skin_tone", - "woman_standing_tone3", - "woman_standing_medium_skin_tone", - "woman_standing_tone4", - "woman_standing_medium_dark_skin_tone", - "woman_standing_tone5", - "woman_standing_dark_skin_tone", - "man_standing", - "man_standing_tone1", - "man_standing_light_skin_tone", - "man_standing_tone2", - "man_standing_medium_light_skin_tone", - "man_standing_tone3", - "man_standing_medium_skin_tone", - "man_standing_tone4", - "man_standing_medium_dark_skin_tone", - "man_standing_tone5", - "man_standing_dark_skin_tone", - "people_holding_hands", - "people_holding_hands_tone1", - "people_holding_hands_light_skin_tone", - "people_holding_hands_tone1_tone2", - "people_holding_hands_light_skin_tone_medium_light_skin_tone", - "people_holding_hands_tone1_tone3", - "people_holding_hands_light_skin_tone_medium_skin_tone", - "people_holding_hands_tone1_tone4", - "people_holding_hands_light_skin_tone_medium_dark_skin_tone", - "people_holding_hands_tone1_tone5", - "people_holding_hands_light_skin_tone_dark_skin_tone", - "people_holding_hands_tone2_tone1", - "people_holding_hands_medium_light_skin_tone_light_skin_tone", - "people_holding_hands_tone2", - "people_holding_hands_medium_light_skin_tone", - "people_holding_hands_tone2_tone3", - "people_holding_hands_medium_light_skin_tone_medium_skin_tone", - "people_holding_hands_tone2_tone4", - "people_holding_hands_medium_light_skin_tone_medium_dark_skin_tone", - "people_holding_hands_tone2_tone5", - "people_holding_hands_medium_light_skin_tone_dark_skin_tone", - "people_holding_hands_tone3_tone1", - "people_holding_hands_medium_skin_tone_light_skin_tone", - "people_holding_hands_tone3_tone2", - "people_holding_hands_medium_skin_tone_medium_light_skin_tone", - "people_holding_hands_tone3", - "people_holding_hands_medium_skin_tone", - "people_holding_hands_tone3_tone4", - "people_holding_hands_medium_skin_tone_medium_dark_skin_tone", - "people_holding_hands_tone3_tone5", - "people_holding_hands_medium_skin_tone_dark_skin_tone", - "people_holding_hands_tone4_tone1", - "people_holding_hands_medium_dark_skin_tone_light_skin_tone", - "people_holding_hands_tone4_tone2", - "people_holding_hands_medium_dark_skin_tone_medium_light_skin_tone", - "people_holding_hands_tone4_tone3", - "people_holding_hands_medium_dark_skin_tone_medium_skin_tone", - "people_holding_hands_tone4", - "people_holding_hands_medium_dark_skin_tone", - "people_holding_hands_tone4_tone5", - "people_holding_hands_medium_dark_skin_tone_dark_skin_tone", - "people_holding_hands_tone5_tone1", - "people_holding_hands_dark_skin_tone_light_skin_tone", - "people_holding_hands_tone5_tone2", - "people_holding_hands_dark_skin_tone_medium_light_skin_tone", - "people_holding_hands_tone5_tone3", - "people_holding_hands_dark_skin_tone_medium_skin_tone", - "people_holding_hands_tone5_tone4", - "people_holding_hands_dark_skin_tone_medium_dark_skin_tone", - "people_holding_hands_tone5", - "people_holding_hands_dark_skin_tone", - "couple", - "woman_and_man_holding_hands_tone1", - "woman_and_man_holding_hands_light_skin_tone", - "woman_and_man_holding_hands_tone1_tone2", - "woman_and_man_holding_hands_light_skin_tone_medium_light_skin_tone", - "woman_and_man_holding_hands_tone1_tone3", - "woman_and_man_holding_hands_light_skin_tone_medium_skin_tone", - "woman_and_man_holding_hands_tone1_tone4", - "woman_and_man_holding_hands_light_skin_tone_medium_dark_skin_tone", - "woman_and_man_holding_hands_tone1_tone5", - "woman_and_man_holding_hands_light_skin_tone_dark_skin_tone", - "woman_and_man_holding_hands_tone2_tone1", - "woman_and_man_holding_hands_medium_light_skin_tone_light_skin_tone", - "woman_and_man_holding_hands_tone2", - "woman_and_man_holding_hands_medium_light_skin_tone", - "woman_and_man_holding_hands_tone2_tone3", - "woman_and_man_holding_hands_medium_light_skin_tone_medium_skin_tone", - "woman_and_man_holding_hands_tone2_tone4", - "woman_and_man_holding_hands_medium_light_skin_tone_medium_dark_skin_tone", - "woman_and_man_holding_hands_tone2_tone5", - "woman_and_man_holding_hands_medium_light_skin_tone_dark_skin_tone", - "woman_and_man_holding_hands_tone3_tone1", - "woman_and_man_holding_hands_medium_skin_tone_light_skin_tone", - "woman_and_man_holding_hands_tone3_tone2", - "woman_and_man_holding_hands_medium_skin_tone_medium_light_skin_tone", - "woman_and_man_holding_hands_tone3", - "woman_and_man_holding_hands_medium_skin_tone", - "woman_and_man_holding_hands_tone3_tone4", - "woman_and_man_holding_hands_medium_skin_tone_medium_dark_skin_tone", - "woman_and_man_holding_hands_tone3_tone5", - "woman_and_man_holding_hands_medium_skin_tone_dark_skin_tone", - "woman_and_man_holding_hands_tone4_tone1", - "woman_and_man_holding_hands_medium_dark_skin_tone_light_skin_tone", - "woman_and_man_holding_hands_tone4_tone2", - "woman_and_man_holding_hands_medium_dark_skin_tone_medium_light_skin_tone", - "woman_and_man_holding_hands_tone4_tone3", - "woman_and_man_holding_hands_medium_dark_skin_tone_medium_skin_tone", - "woman_and_man_holding_hands_tone4", - "woman_and_man_holding_hands_medium_dark_skin_tone", - "woman_and_man_holding_hands_tone4_tone5", - "woman_and_man_holding_hands_medium_dark_skin_tone_dark_skin_tone", - "woman_and_man_holding_hands_tone5_tone1", - "woman_and_man_holding_hands_dark_skin_tone_light_skin_tone", - "woman_and_man_holding_hands_tone5_tone2", - "woman_and_man_holding_hands_dark_skin_tone_medium_light_skin_tone", - "woman_and_man_holding_hands_tone5_tone3", - "woman_and_man_holding_hands_dark_skin_tone_medium_skin_tone", - "woman_and_man_holding_hands_tone5_tone4", - "woman_and_man_holding_hands_dark_skin_tone_medium_dark_skin_tone", - "woman_and_man_holding_hands_tone5", - "woman_and_man_holding_hands_dark_skin_tone", - "two_women_holding_hands", - "women_holding_hands_tone1", - "women_holding_hands_light_skin_tone", - "women_holding_hands_tone1_tone2", - "women_holding_hands_light_skin_tone_medium_light_skin_tone", - "women_holding_hands_tone1_tone3", - "women_holding_hands_light_skin_tone_medium_skin_tone", - "women_holding_hands_tone1_tone4", - "women_holding_hands_light_skin_tone_medium_dark_skin_tone", - "women_holding_hands_tone1_tone5", - "women_holding_hands_light_skin_tone_dark_skin_tone", - "women_holding_hands_tone2_tone1", - "women_holding_hands_medium_light_skin_tone_light_skin_tone", - "women_holding_hands_tone2", - "women_holding_hands_medium_light_skin_tone", - "women_holding_hands_tone2_tone3", - "women_holding_hands_medium_light_skin_tone_medium_skin_tone", - "women_holding_hands_tone2_tone4", - "women_holding_hands_medium_light_skin_tone_medium_dark_skin_tone", - "women_holding_hands_tone2_tone5", - "women_holding_hands_medium_light_skin_tone_dark_skin_tone", - "women_holding_hands_tone3_tone1", - "women_holding_hands_medium_skin_tone_light_skin_tone", - "women_holding_hands_tone3_tone2", - "women_holding_hands_medium_skin_tone_medium_light_skin_tone", - "women_holding_hands_tone3", - "women_holding_hands_medium_skin_tone", - "women_holding_hands_tone3_tone4", - "women_holding_hands_medium_skin_tone_medium_dark_skin_tone", - "women_holding_hands_tone3_tone5", - "women_holding_hands_medium_skin_tone_dark_skin_tone", - "women_holding_hands_tone4_tone1", - "women_holding_hands_medium_dark_skin_tone_light_skin_tone", - "women_holding_hands_tone4_tone2", - "women_holding_hands_medium_dark_skin_tone_medium_light_skin_tone", - "women_holding_hands_tone4_tone3", - "women_holding_hands_medium_dark_skin_tone_medium_skin_tone", - "women_holding_hands_tone4", - "women_holding_hands_medium_dark_skin_tone", - "women_holding_hands_tone4_tone5", - "women_holding_hands_medium_dark_skin_tone_dark_skin_tone", - "women_holding_hands_tone5_tone1", - "women_holding_hands_dark_skin_tone_light_skin_tone", - "women_holding_hands_tone5_tone2", - "women_holding_hands_dark_skin_tone_medium_light_skin_tone", - "women_holding_hands_tone5_tone3", - "women_holding_hands_dark_skin_tone_medium_skin_tone", - "women_holding_hands_tone5_tone4", - "women_holding_hands_dark_skin_tone_medium_dark_skin_tone", - "women_holding_hands_tone5", - "women_holding_hands_dark_skin_tone", - "two_men_holding_hands", - "men_holding_hands_tone1", - "men_holding_hands_light_skin_tone", - "men_holding_hands_tone1_tone2", - "men_holding_hands_light_skin_tone_medium_light_skin_tone", - "men_holding_hands_tone1_tone3", - "men_holding_hands_light_skin_tone_medium_skin_tone", - "men_holding_hands_tone1_tone4", - "men_holding_hands_light_skin_tone_medium_dark_skin_tone", - "men_holding_hands_tone1_tone5", - "men_holding_hands_light_skin_tone_dark_skin_tone", - "men_holding_hands_tone2_tone1", - "men_holding_hands_medium_light_skin_tone_light_skin_tone", - "men_holding_hands_tone2", - "men_holding_hands_medium_light_skin_tone", - "men_holding_hands_tone2_tone3", - "men_holding_hands_medium_light_skin_tone_medium_skin_tone", - "men_holding_hands_tone2_tone4", - "men_holding_hands_medium_light_skin_tone_medium_dark_skin_tone", - "men_holding_hands_tone2_tone5", - "men_holding_hands_medium_light_skin_tone_dark_skin_tone", - "men_holding_hands_tone3_tone1", - "men_holding_hands_medium_skin_tone_light_skin_tone", - "men_holding_hands_tone3_tone2", - "men_holding_hands_medium_skin_tone_medium_light_skin_tone", - "men_holding_hands_tone3", - "men_holding_hands_medium_skin_tone", - "men_holding_hands_tone3_tone4", - "men_holding_hands_medium_skin_tone_medium_dark_skin_tone", - "men_holding_hands_tone3_tone5", - "men_holding_hands_medium_skin_tone_dark_skin_tone", - "men_holding_hands_tone4_tone1", - "men_holding_hands_medium_dark_skin_tone_light_skin_tone", - "men_holding_hands_tone4_tone2", - "men_holding_hands_medium_dark_skin_tone_medium_light_skin_tone", - "men_holding_hands_tone4_tone3", - "men_holding_hands_medium_dark_skin_tone_medium_skin_tone", - "men_holding_hands_tone4", - "men_holding_hands_medium_dark_skin_tone", - "men_holding_hands_tone4_tone5", - "men_holding_hands_medium_dark_skin_tone_dark_skin_tone", - "men_holding_hands_tone5_tone1", - "men_holding_hands_dark_skin_tone_light_skin_tone", - "men_holding_hands_tone5_tone2", - "men_holding_hands_dark_skin_tone_medium_light_skin_tone", - "men_holding_hands_tone5_tone3", - "men_holding_hands_dark_skin_tone_medium_skin_tone", - "men_holding_hands_tone5_tone4", - "men_holding_hands_dark_skin_tone_medium_dark_skin_tone", - "men_holding_hands_tone5", - "men_holding_hands_dark_skin_tone", - "couple_with_heart", - "couple_with_heart_tone1", - "couple_with_heart_light_skin_tone", - "couple_with_heart_person_person_tone1_tone2", - "couple_with_heart_person_person_light_skin_tone_medium_light_skin_tone", - "couple_with_heart_person_person_tone1_tone3", - "couple_with_heart_person_person_light_skin_tone_medium_skin_tone", - "couple_with_heart_person_person_tone1_tone4", - "couple_with_heart_person_person_light_skin_tone_medium_dark_skin_tone", - "couple_with_heart_person_person_tone1_tone5", - "couple_with_heart_person_person_light_skin_tone_dark_skin_tone", - "couple_with_heart_person_person_tone2_tone1", - "couple_with_heart_person_person_medium_light_skin_tone_light_skin_tone", - "couple_with_heart_tone2", - "couple_with_heart_medium_light_skin_tone", - "couple_with_heart_person_person_tone2_tone3", - "couple_with_heart_person_person_medium_light_skin_tone_medium_skin_tone", - "couple_with_heart_person_person_tone2_tone4", - "couple_with_heart_person_person_medium_light_skin_tone_medium_dark_skin_tone", - "couple_with_heart_person_person_tone2_tone5", - "couple_with_heart_person_person_medium_light_skin_tone_dark_skin_tone", - "couple_with_heart_person_person_tone3_tone1", - "couple_with_heart_person_person_medium_skin_tone_light_skin_tone", - "couple_with_heart_person_person_tone3_tone2", - "couple_with_heart_person_person_medium_skin_tone_medium_light_skin_tone", - "couple_with_heart_tone3", - "couple_with_heart_medium_skin_tone", - "couple_with_heart_person_person_tone3_tone4", - "couple_with_heart_person_person_medium_skin_tone_medium_dark_skin_tone", - "couple_with_heart_person_person_tone3_tone5", - "couple_with_heart_person_person_medium_skin_tone_dark_skin_tone", - "couple_with_heart_person_person_tone4_tone1", - "couple_with_heart_person_person_medium_dark_skin_tone_light_skin_tone", - "couple_with_heart_person_person_tone4_tone2", - "couple_with_heart_person_person_medium_dark_skin_tone_medium_light_skin_tone", - "couple_with_heart_person_person_tone4_tone3", - "couple_with_heart_person_person_medium_dark_skin_tone_medium_skin_tone", - "couple_with_heart_tone4", - "couple_with_heart_medium_dark_skin_tone", - "couple_with_heart_person_person_tone4_tone5", - "couple_with_heart_person_person_medium_dark_skin_tone_dark_skin_tone", - "couple_with_heart_person_person_tone5_tone1", - "couple_with_heart_person_person_dark_skin_tone_light_skin_tone", - "couple_with_heart_person_person_tone5_tone2", - "couple_with_heart_person_person_dark_skin_tone_medium_light_skin_tone", - "couple_with_heart_person_person_tone5_tone3", - "couple_with_heart_person_person_dark_skin_tone_medium_skin_tone", - "couple_with_heart_person_person_tone5_tone4", - "couple_with_heart_person_person_dark_skin_tone_medium_dark_skin_tone", - "couple_with_heart_tone5", - "couple_with_heart_dark_skin_tone", - "couple_with_heart_woman_man", - "couple_with_heart_woman_man_tone1", - "couple_with_heart_woman_man_light_skin_tone", - "couple_with_heart_woman_man_tone1_tone2", - "couple_with_heart_woman_man_light_skin_tone_medium_light_skin_tone", - "couple_with_heart_woman_man_tone1_tone3", - "couple_with_heart_woman_man_light_skin_tone_medium_skin_tone", - "couple_with_heart_woman_man_tone1_tone4", - "couple_with_heart_woman_man_light_skin_tone_medium_dark_skin_tone", - "couple_with_heart_woman_man_tone1_tone5", - "couple_with_heart_woman_man_light_skin_tone_dark_skin_tone", - "couple_with_heart_woman_man_tone2_tone1", - "couple_with_heart_woman_man_medium_light_skin_tone_light_skin_tone", - "couple_with_heart_woman_man_tone2", - "couple_with_heart_woman_man_medium_light_skin_tone", - "couple_with_heart_woman_man_tone2_tone3", - "couple_with_heart_woman_man_medium_light_skin_tone_medium_skin_tone", - "couple_with_heart_woman_man_tone2_tone4", - "couple_with_heart_woman_man_medium_light_skin_tone_medium_dark_skin_tone", - "couple_with_heart_woman_man_tone2_tone5", - "couple_with_heart_woman_man_medium_light_skin_tone_dark_skin_tone", - "couple_with_heart_woman_man_tone3_tone1", - "couple_with_heart_woman_man_medium_skin_tone_light_skin_tone", - "couple_with_heart_woman_man_tone3_tone2", - "couple_with_heart_woman_man_medium_skin_tone_medium_light_skin_tone", - "couple_with_heart_woman_man_tone3", - "couple_with_heart_woman_man_medium_skin_tone", - "couple_with_heart_woman_man_tone3_tone4", - "couple_with_heart_woman_man_medium_skin_tone_medium_dark_skin_tone", - "couple_with_heart_woman_man_tone3_tone5", - "couple_with_heart_woman_man_medium_skin_tone_dark_skin_tone", - "couple_with_heart_woman_man_tone4_tone1", - "couple_with_heart_woman_man_medium_dark_skin_tone_light_skin_tone", - "couple_with_heart_woman_man_tone4_tone2", - "couple_with_heart_woman_man_medium_dark_skin_tone_medium_light_skin_tone", - "couple_with_heart_woman_man_tone4_tone3", - "couple_with_heart_woman_man_medium_dark_skin_tone_medium_skin_tone", - "couple_with_heart_woman_man_tone4", - "couple_with_heart_woman_man_medium_dark_skin_tone", - "couple_with_heart_woman_man_tone4_tone5", - "couple_with_heart_woman_man_medium_dark_skin_tone_dark_skin_tone", - "couple_with_heart_woman_man_tone5_tone1", - "couple_with_heart_woman_man_dark_skin_tone_light_skin_tone", - "couple_with_heart_woman_man_tone5_tone2", - "couple_with_heart_woman_man_dark_skin_tone_medium_light_skin_tone", - "couple_with_heart_woman_man_tone5_tone3", - "couple_with_heart_woman_man_dark_skin_tone_medium_skin_tone", - "couple_with_heart_woman_man_tone5_tone4", - "couple_with_heart_woman_man_dark_skin_tone_medium_dark_skin_tone", - "couple_with_heart_woman_man_tone5", - "couple_with_heart_woman_man_dark_skin_tone", - "couple_ww", - "couple_with_heart_ww", - "couple_with_heart_woman_woman_tone1", - "couple_with_heart_woman_woman_light_skin_tone", - "couple_with_heart_woman_woman_tone1_tone2", - "couple_with_heart_woman_woman_light_skin_tone_medium_light_skin_tone", - "couple_with_heart_woman_woman_tone1_tone3", - "couple_with_heart_woman_woman_light_skin_tone_medium_skin_tone", - "couple_with_heart_woman_woman_tone1_tone4", - "couple_with_heart_woman_woman_light_skin_tone_medium_dark_skin_tone", - "couple_with_heart_woman_woman_tone1_tone5", - "couple_with_heart_woman_woman_light_skin_tone_dark_skin_tone", - "couple_with_heart_woman_woman_tone2_tone1", - "couple_with_heart_woman_woman_medium_light_skin_tone_light_skin_tone", - "couple_with_heart_woman_woman_tone2", - "couple_with_heart_woman_woman_medium_light_skin_tone", - "couple_with_heart_woman_woman_tone2_tone3", - "couple_with_heart_woman_woman_medium_light_skin_tone_medium_skin_tone", - "couple_with_heart_woman_woman_tone2_tone4", - "couple_with_heart_woman_woman_medium_light_skin_tone_medium_dark_skin_tone", - "couple_with_heart_woman_woman_tone2_tone5", - "couple_with_heart_woman_woman_medium_light_skin_tone_dark_skin_tone", - "couple_with_heart_woman_woman_tone3_tone1", - "couple_with_heart_woman_woman_medium_skin_tone_light_skin_tone", - "couple_with_heart_woman_woman_tone3_tone2", - "couple_with_heart_woman_woman_medium_skin_tone_medium_light_skin_tone", - "couple_with_heart_woman_woman_tone3", - "couple_with_heart_woman_woman_medium_skin_tone", - "couple_with_heart_woman_woman_tone3_tone4", - "couple_with_heart_woman_woman_medium_skin_tone_medium_dark_skin_tone", - "couple_with_heart_woman_woman_tone3_tone5", - "couple_with_heart_woman_woman_medium_skin_tone_dark_skin_tone", - "couple_with_heart_woman_woman_tone4_tone1", - "couple_with_heart_woman_woman_medium_dark_skin_tone_light_skin_tone", - "couple_with_heart_woman_woman_tone4_tone2", - "couple_with_heart_woman_woman_medium_dark_skin_tone_medium_light_skin_tone", - "couple_with_heart_woman_woman_tone4_tone3", - "couple_with_heart_woman_woman_medium_dark_skin_tone_medium_skin_tone", - "couple_with_heart_woman_woman_tone4", - "couple_with_heart_woman_woman_medium_dark_skin_tone", - "couple_with_heart_woman_woman_tone4_tone5", - "couple_with_heart_woman_woman_medium_dark_skin_tone_dark_skin_tone", - "couple_with_heart_woman_woman_tone5_tone1", - "couple_with_heart_woman_woman_dark_skin_tone_light_skin_tone", - "couple_with_heart_woman_woman_tone5_tone2", - "couple_with_heart_woman_woman_dark_skin_tone_medium_light_skin_tone", - "couple_with_heart_woman_woman_tone5_tone3", - "couple_with_heart_woman_woman_dark_skin_tone_medium_skin_tone", - "couple_with_heart_woman_woman_tone5_tone4", - "couple_with_heart_woman_woman_dark_skin_tone_medium_dark_skin_tone", - "couple_with_heart_woman_woman_tone5", - "couple_with_heart_woman_woman_dark_skin_tone", - "couple_mm", - "couple_with_heart_mm", - "couple_with_heart_man_man_tone1", - "couple_with_heart_man_man_light_skin_tone", - "couple_with_heart_man_man_tone1_tone2", - "couple_with_heart_man_man_light_skin_tone_medium_light_skin_tone", - "couple_with_heart_man_man_tone1_tone3", - "couple_with_heart_man_man_light_skin_tone_medium_skin_tone", - "couple_with_heart_man_man_tone1_tone4", - "couple_with_heart_man_man_light_skin_tone_medium_dark_skin_tone", - "couple_with_heart_man_man_tone1_tone5", - "couple_with_heart_man_man_light_skin_tone_dark_skin_tone", - "couple_with_heart_man_man_tone2_tone1", - "couple_with_heart_man_man_medium_light_skin_tone_light_skin_tone", - "couple_with_heart_man_man_tone2", - "couple_with_heart_man_man_medium_light_skin_tone", - "couple_with_heart_man_man_tone2_tone3", - "couple_with_heart_man_man_medium_light_skin_tone_medium_skin_tone", - "couple_with_heart_man_man_tone2_tone4", - "couple_with_heart_man_man_medium_light_skin_tone_medium_dark_skin_tone", - "couple_with_heart_man_man_tone2_tone5", - "couple_with_heart_man_man_medium_light_skin_tone_dark_skin_tone", - "couple_with_heart_man_man_tone3_tone1", - "couple_with_heart_man_man_medium_skin_tone_light_skin_tone", - "couple_with_heart_man_man_tone3_tone2", - "couple_with_heart_man_man_medium_skin_tone_medium_light_skin_tone", - "couple_with_heart_man_man_tone3", - "couple_with_heart_man_man_medium_skin_tone", - "couple_with_heart_man_man_tone3_tone4", - "couple_with_heart_man_man_medium_skin_tone_medium_dark_skin_tone", - "couple_with_heart_man_man_tone3_tone5", - "couple_with_heart_man_man_medium_skin_tone_dark_skin_tone", - "couple_with_heart_man_man_tone4_tone1", - "couple_with_heart_man_man_medium_dark_skin_tone_light_skin_tone", - "couple_with_heart_man_man_tone4_tone2", - "couple_with_heart_man_man_medium_dark_skin_tone_medium_light_skin_tone", - "couple_with_heart_man_man_tone4_tone3", - "couple_with_heart_man_man_medium_dark_skin_tone_medium_skin_tone", - "couple_with_heart_man_man_tone4", - "couple_with_heart_man_man_medium_dark_skin_tone", - "couple_with_heart_man_man_tone4_tone5", - "couple_with_heart_man_man_medium_dark_skin_tone_dark_skin_tone", - "couple_with_heart_man_man_tone5_tone1", - "couple_with_heart_man_man_dark_skin_tone_light_skin_tone", - "couple_with_heart_man_man_tone5_tone2", - "couple_with_heart_man_man_dark_skin_tone_medium_light_skin_tone", - "couple_with_heart_man_man_tone5_tone3", - "couple_with_heart_man_man_dark_skin_tone_medium_skin_tone", - "couple_with_heart_man_man_tone5_tone4", - "couple_with_heart_man_man_dark_skin_tone_medium_dark_skin_tone", - "couple_with_heart_man_man_tone5", - "couple_with_heart_man_man_dark_skin_tone", - "couplekiss", - "kiss_tone1", - "kiss_light_skin_tone", - "kiss_person_person_tone1_tone2", - "kiss_person_person_light_skin_tone_medium_light_skin_tone", - "kiss_person_person_tone1_tone3", - "kiss_person_person_light_skin_tone_medium_skin_tone", - "kiss_person_person_tone1_tone4", - "kiss_person_person_light_skin_tone_medium_dark_skin_tone", - "kiss_person_person_tone1_tone5", - "kiss_person_person_light_skin_tone_dark_skin_tone", - "kiss_person_person_tone2_tone1", - "kiss_person_person_medium_light_skin_tone_light_skin_tone", - "kiss_tone2", - "kiss_medium_light_skin_tone", - "kiss_person_person_tone2_tone3", - "kiss_person_person_medium_light_skin_tone_medium_skin_tone", - "kiss_person_person_tone2_tone4", - "kiss_person_person_medium_light_skin_tone_medium_dark_skin_tone", - "kiss_person_person_tone2_tone5", - "kiss_person_person_medium_light_skin_tone_dark_skin_tone", - "kiss_person_person_tone3_tone1", - "kiss_person_person_medium_skin_tone_light_skin_tone", - "kiss_person_person_tone3_tone2", - "kiss_person_person_medium_skin_tone_medium_light_skin_tone", - "kiss_tone3", - "kiss_medium_skin_tone", - "kiss_person_person_tone3_tone4", - "kiss_person_person_medium_skin_tone_medium_dark_skin_tone", - "kiss_person_person_tone3_tone5", - "kiss_person_person_medium_skin_tone_dark_skin_tone", - "kiss_person_person_tone4_tone1", - "kiss_person_person_medium_dark_skin_tone_light_skin_tone", - "kiss_person_person_tone4_tone2", - "kiss_person_person_medium_dark_skin_tone_medium_light_skin_tone", - "kiss_person_person_tone4_tone3", - "kiss_person_person_medium_dark_skin_tone_medium_skin_tone", - "kiss_tone4", - "kiss_medium_dark_skin_tone", - "kiss_person_person_tone4_tone5", - "kiss_person_person_medium_dark_skin_tone_dark_skin_tone", - "kiss_person_person_tone5_tone1", - "kiss_person_person_dark_skin_tone_light_skin_tone", - "kiss_person_person_tone5_tone2", - "kiss_person_person_dark_skin_tone_medium_light_skin_tone", - "kiss_person_person_tone5_tone3", - "kiss_person_person_dark_skin_tone_medium_skin_tone", - "kiss_person_person_tone5_tone4", - "kiss_person_person_dark_skin_tone_medium_dark_skin_tone", - "kiss_tone5", - "kiss_dark_skin_tone", - "kiss_woman_man", - "kiss_woman_man_tone1", - "kiss_woman_man_light_skin_tone", - "kiss_woman_man_tone1_tone2", - "kiss_woman_man_light_skin_tone_medium_light_skin_tone", - "kiss_woman_man_tone1_tone3", - "kiss_woman_man_light_skin_tone_medium_skin_tone", - "kiss_woman_man_tone1_tone4", - "kiss_woman_man_light_skin_tone_medium_dark_skin_tone", - "kiss_woman_man_tone1_tone5", - "kiss_woman_man_light_skin_tone_dark_skin_tone", - "kiss_woman_man_tone2_tone1", - "kiss_woman_man_medium_light_skin_tone_light_skin_tone", - "kiss_woman_man_tone2", - "kiss_woman_man_medium_light_skin_tone", - "kiss_woman_man_tone2_tone3", - "kiss_woman_man_medium_light_skin_tone_medium_skin_tone", - "kiss_woman_man_tone2_tone4", - "kiss_woman_man_medium_light_skin_tone_medium_dark_skin_tone", - "kiss_woman_man_tone2_tone5", - "kiss_woman_man_medium_light_skin_tone_dark_skin_tone", - "kiss_woman_man_tone3_tone1", - "kiss_woman_man_medium_skin_tone_light_skin_tone", - "kiss_woman_man_tone3_tone2", - "kiss_woman_man_medium_skin_tone_medium_light_skin_tone", - "kiss_woman_man_tone3", - "kiss_woman_man_medium_skin_tone", - "kiss_woman_man_tone3_tone4", - "kiss_woman_man_medium_skin_tone_medium_dark_skin_tone", - "kiss_woman_man_tone3_tone5", - "kiss_woman_man_medium_skin_tone_dark_skin_tone", - "kiss_woman_man_tone4_tone1", - "kiss_woman_man_medium_dark_skin_tone_light_skin_tone", - "kiss_woman_man_tone4_tone2", - "kiss_woman_man_medium_dark_skin_tone_medium_light_skin_tone", - "kiss_woman_man_tone4_tone3", - "kiss_woman_man_medium_dark_skin_tone_medium_skin_tone", - "kiss_woman_man_tone4", - "kiss_woman_man_medium_dark_skin_tone", - "kiss_woman_man_tone4_tone5", - "kiss_woman_man_medium_dark_skin_tone_dark_skin_tone", - "kiss_woman_man_tone5_tone1", - "kiss_woman_man_dark_skin_tone_light_skin_tone", - "kiss_woman_man_tone5_tone2", - "kiss_woman_man_dark_skin_tone_medium_light_skin_tone", - "kiss_woman_man_tone5_tone3", - "kiss_woman_man_dark_skin_tone_medium_skin_tone", - "kiss_woman_man_tone5_tone4", - "kiss_woman_man_dark_skin_tone_medium_dark_skin_tone", - "kiss_woman_man_tone5", - "kiss_woman_man_dark_skin_tone", - "kiss_ww", - "couplekiss_ww", - "kiss_woman_woman_tone1", - "kiss_woman_woman_light_skin_tone", - "kiss_woman_woman_tone1_tone2", - "kiss_woman_woman_light_skin_tone_medium_light_skin_tone", - "kiss_woman_woman_tone1_tone3", - "kiss_woman_woman_light_skin_tone_medium_skin_tone", - "kiss_woman_woman_tone1_tone4", - "kiss_woman_woman_light_skin_tone_medium_dark_skin_tone", - "kiss_woman_woman_tone1_tone5", - "kiss_woman_woman_light_skin_tone_dark_skin_tone", - "kiss_woman_woman_tone2_tone1", - "kiss_woman_woman_medium_light_skin_tone_light_skin_tone", - "kiss_woman_woman_tone2", - "kiss_woman_woman_medium_light_skin_tone", - "kiss_woman_woman_tone2_tone3", - "kiss_woman_woman_medium_light_skin_tone_medium_skin_tone", - "kiss_woman_woman_tone2_tone4", - "kiss_woman_woman_medium_light_skin_tone_medium_dark_skin_tone", - "kiss_woman_woman_tone2_tone5", - "kiss_woman_woman_medium_light_skin_tone_dark_skin_tone", - "kiss_woman_woman_tone3_tone1", - "kiss_woman_woman_medium_skin_tone_light_skin_tone", - "kiss_woman_woman_tone3_tone2", - "kiss_woman_woman_medium_skin_tone_medium_light_skin_tone", - "kiss_woman_woman_tone3", - "kiss_woman_woman_medium_skin_tone", - "kiss_woman_woman_tone3_tone4", - "kiss_woman_woman_medium_skin_tone_medium_dark_skin_tone", - "kiss_woman_woman_tone3_tone5", - "kiss_woman_woman_medium_skin_tone_dark_skin_tone", - "kiss_woman_woman_tone4_tone1", - "kiss_woman_woman_medium_dark_skin_tone_light_skin_tone", - "kiss_woman_woman_tone4_tone2", - "kiss_woman_woman_medium_dark_skin_tone_medium_light_skin_tone", - "kiss_woman_woman_tone4_tone3", - "kiss_woman_woman_medium_dark_skin_tone_medium_skin_tone", - "kiss_woman_woman_tone4", - "kiss_woman_woman_medium_dark_skin_tone", - "kiss_woman_woman_tone4_tone5", - "kiss_woman_woman_medium_dark_skin_tone_dark_skin_tone", - "kiss_woman_woman_tone5_tone1", - "kiss_woman_woman_dark_skin_tone_light_skin_tone", - "kiss_woman_woman_tone5_tone2", - "kiss_woman_woman_dark_skin_tone_medium_light_skin_tone", - "kiss_woman_woman_tone5_tone3", - "kiss_woman_woman_dark_skin_tone_medium_skin_tone", - "kiss_woman_woman_tone5_tone4", - "kiss_woman_woman_dark_skin_tone_medium_dark_skin_tone", - "kiss_woman_woman_tone5", - "kiss_woman_woman_dark_skin_tone", - "kiss_mm", - "couplekiss_mm", - "kiss_man_man", - "kiss_man_man_tone1", - "kiss_man_man_light_skin_tone", - "kiss_man_man_tone1_tone2", - "kiss_man_man_light_skin_tone_medium_light_skin_tone", - "kiss_man_man_tone1_tone3", - "kiss_man_man_light_skin_tone_medium_skin_tone", - "kiss_man_man_tone1_tone4", - "kiss_man_man_light_skin_tone_medium_dark_skin_tone", - "kiss_man_man_tone1_tone5", - "kiss_man_man_light_skin_tone_dark_skin_tone", - "kiss_man_man_tone2_tone1", - "kiss_man_man_medium_light_skin_tone_light_skin_tone", - "kiss_man_man_tone2", - "kiss_man_man_medium_light_skin_tone", - "kiss_man_man_tone2_tone3", - "kiss_man_man_medium_light_skin_tone_medium_skin_tone", - "kiss_man_man_tone2_tone4", - "kiss_man_man_medium_light_skin_tone_medium_dark_skin_tone", - "kiss_man_man_tone2_tone5", - "kiss_man_man_medium_light_skin_tone_dark_skin_tone", - "kiss_man_man_tone3_tone1", - "kiss_man_man_medium_skin_tone_light_skin_tone", - "kiss_man_man_tone3_tone2", - "kiss_man_man_medium_skin_tone_medium_light_skin_tone", - "kiss_man_man_tone3", - "kiss_man_man_medium_skin_tone", - "kiss_man_man_tone3_tone4", - "kiss_man_man_medium_skin_tone_medium_dark_skin_tone", - "kiss_man_man_tone3_tone5", - "kiss_man_man_medium_skin_tone_dark_skin_tone", - "kiss_man_man_tone4_tone1", - "kiss_man_man_medium_dark_skin_tone_light_skin_tone", - "kiss_man_man_tone4_tone2", - "kiss_man_man_medium_dark_skin_tone_medium_light_skin_tone", - "kiss_man_man_tone4_tone3", - "kiss_man_man_medium_dark_skin_tone_medium_skin_tone", - "kiss_man_man_tone4", - "kiss_man_man_medium_dark_skin_tone", - "kiss_man_man_tone4_tone5", - "kiss_man_man_medium_dark_skin_tone_dark_skin_tone", - "kiss_man_man_tone5_tone1", - "kiss_man_man_dark_skin_tone_light_skin_tone", - "kiss_man_man_tone5_tone2", - "kiss_man_man_dark_skin_tone_medium_light_skin_tone", - "kiss_man_man_tone5_tone3", - "kiss_man_man_dark_skin_tone_medium_skin_tone", - "kiss_man_man_tone5_tone4", - "kiss_man_man_dark_skin_tone_medium_dark_skin_tone", - "kiss_man_man_tone5", - "kiss_man_man_dark_skin_tone", - "family", - "family_man_woman_boy", - "family_mwg", - "family_mwgb", - "family_mwbb", - "family_mwgg", - "family_wwb", - "family_wwg", - "family_wwgb", - "family_wwbb", - "family_wwgg", - "family_mmb", - "family_mmg", - "family_mmgb", - "family_mmbb", - "family_mmgg", - "family_woman_boy", - "family_woman_girl", - "family_woman_girl_boy", - "family_woman_boy_boy", - "family_woman_girl_girl", - "family_man_boy", - "family_man_girl", - "family_man_girl_boy", - "family_man_boy_boy", - "family_man_girl_girl", - "knot", - "yarn", - "thread", - "sewing_needle", - "coat", - "lab_coat", - "safety_vest", - "womans_clothes", - "shirt", - "t_shirt", - "jeans", - "briefs", - "shorts", - "necktie", - "dress", - "bikini", - "one_piece_swimsuit", - "kimono", - "sari", - "thong_sandal", - "womans_flat_shoe", - "flat_shoe", - "high_heel", - "sandal", - "womans_sandal", - "boot", - "womans_boot", - "mans_shoe", - "athletic_shoe", - "running_shoe", - "hiking_boot", - "socks", - "gloves", - "scarf", - "tophat", - "top_hat", - "billed_cap", - "womans_hat", - "mortar_board", - "helmet_with_cross", - "helmet_with_white_cross", - "military_helmet", - "crown", - "ring", - "pouch", - "clutch_bag", - "purse", - "handbag", - "briefcase", - "school_satchel", - "backpack", - "luggage", - "eyeglasses", - "glasses", - "dark_sunglasses", - "goggles", - "closed_umbrella", - "pink_heart", - "heart", - "red_heart", - "orange_heart", - "yellow_heart", - "green_heart", - "light_blue_heart", - "blue_heart", - "purple_heart", - "black_heart", - "grey_heart", - "white_heart", - "brown_heart", - "broken_heart", - "heart_exclamation", - "heavy_heart_exclamation_mark_ornament", - "two_hearts", - "revolving_hearts", - "heartbeat", - "beating_heart", - "heartpulse", - "growing_heart", - "sparkling_heart", - "cupid", - "gift_heart", - "mending_heart", - "heart_on_fire", - "heart_decoration", - "peace", - "peace_symbol", - "cross", - "latin_cross", - "star_and_crescent", - "om_symbol", - "wheel_of_dharma", - "khanda", - "star_of_david", - "six_pointed_star", - "menorah", - "yin_yang", - "orthodox_cross", - "place_of_worship", - "worship_symbol", - "ophiuchus", - "aries", - "taurus", - "gemini", - "cancer", - "leo", - "virgo", - "libra", - "scorpius", - "scorpio", - "sagittarius", - "capricorn", - "aquarius", - "pisces", - "id", - "atom", - "atom_symbol", - "accept", - "radioactive", - "radioactive_sign", - "biohazard", - "biohazard_sign", - "mobile_phone_off", - "vibration_mode", - "u6709", - "u7121", - "u7533", - "u55b6", - "u6708", - "eight_pointed_black_star", - "vs", - "white_flower", - "ideograph_advantage", - "secret", - "congratulations", - "u5408", - "u6e80", - "u5272", - "u7981", - "a", - "b", - "ab", - "cl", - "o2", - "sos", - "x", - "cross_mark", - "o", - "octagonal_sign", - "stop_sign", - "no_entry", - "name_badge", - "no_entry_sign", - "prohibited", - "anger", - "hotsprings", - "hot_springs", - "no_pedestrians", - "do_not_litter", - "no_littering", - "no_bicycles", - "non_potable_water", - "underage", - "no_mobile_phones", - "no_smoking", - "exclamation", - "grey_exclamation", - "question", - "question_mark", - "grey_question", - "bangbang", - "interrobang", - "low_brightness", - "high_brightness", - "part_alternation_mark", - "warning", - "children_crossing", - "trident", - "fleur_de_lis", - "beginner", - "recycle", - "white_check_mark", - "u6307", - "chart", - "sparkle", - "eight_spoked_asterisk", - "negative_squared_cross_mark", - "globe_with_meridians", - "diamond_shape_with_a_dot_inside", - "m", - "circled_m", - "cyclone", - "zzz", - "atm", - "wc", - "water_closet", - "wheelchair", - "parking", - "elevator", - "u7a7a", - "sa", - "passport_control", - "customs", - "baggage_claim", - "left_luggage", - "wireless", - "mens", - "mens_room", - "womens", - "womens_room", - "baby_symbol", - "restroom", - "put_litter_in_its_place", - "cinema", - "signal_strength", - "antenna_bars", - "koko", - "symbols", - "input_symbols", - "information_source", - "information", - "abc", - "abcd", - "capital_abcd", - "ng", - "ok", - "up", - "cool", - "new", - "free", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "keycap_ten", - "input_numbers", - "hash", - "asterisk", - "keycap_asterisk", - "eject", - "eject_symbol", - "arrow_forward", - "pause_button", - "double_vertical_bar", - "play_pause", - "stop_button", - "record_button", - "track_next", - "next_track", - "track_previous", - "previous_track", - "fast_forward", - "rewind", - "arrow_double_up", - "arrow_double_down", - "arrow_backward", - "arrow_up_small", - "arrow_down_small", - "arrow_right", - "right_arrow", - "arrow_left", - "left_arrow", - "arrow_up", - "up_arrow", - "arrow_down", - "down_arrow", - "arrow_upper_right", - "arrow_lower_right", - "arrow_lower_left", - "arrow_upper_left", - "up_left_arrow", - "arrow_up_down", - "up_down_arrow", - "left_right_arrow", - "arrow_right_hook", - "leftwards_arrow_with_hook", - "arrow_heading_up", - "arrow_heading_down", - "twisted_rightwards_arrows", - "repeat", - "repeat_one", - "arrows_counterclockwise", - "arrows_clockwise", - "musical_note", - "notes", - "musical_notes", - "heavy_plus_sign", - "heavy_minus_sign", - "heavy_division_sign", - "heavy_multiplication_x", - "heavy_equals_sign", - "infinity", - "heavy_dollar_sign", - "currency_exchange", - "tm", - "trade_mark", - "copyright", - "registered", - "wavy_dash", - "curly_loop", - "loop", - "end", - "end_arrow", - "back", - "back_arrow", - "on", - "on_arrow", - "top", - "top_arrow", - "soon", - "soon_arrow", - "heavy_check_mark", - "check_mark", - "ballot_box_with_check", - "radio_button", - "white_circle", - "black_circle", - "red_circle", - "blue_circle", - "brown_circle", - "purple_circle", - "green_circle", - "yellow_circle", - "orange_circle", - "small_red_triangle", - "small_red_triangle_down", - "small_orange_diamond", - "small_blue_diamond", - "large_orange_diamond", - "large_blue_diamond", - "white_square_button", - "black_square_button", - "black_small_square", - "white_small_square", - "black_medium_small_square", - "white_medium_small_square", - "black_medium_square", - "white_medium_square", - "black_large_square", - "white_large_square", - "orange_square", - "blue_square", - "red_square", - "brown_square", - "purple_square", - "green_square", - "yellow_square", - "speaker", - "mute", - "muted_speaker", - "sound", - "loud_sound", - "bell", - "no_bell", - "mega", - "megaphone", - "loudspeaker", - "speech_left", - "left_speech_bubble", - "eye_in_speech_bubble", - "speech_balloon", - "thought_balloon", - "anger_right", - "right_anger_bubble", - "spades", - "spade_suit", - "clubs", - "club_suit", - "hearts", - "heart_suit", - "diamonds", - "diamond_suit", - "black_joker", - "joker", - "flower_playing_cards", - "mahjong", - "clock1", - "one_oclock", - "clock2", - "two_oclock", - "clock3", - "three_oclock", - "clock4", - "four_oclock", - "clock5", - "five_oclock", - "clock6", - "six_oclock", - "clock7", - "seven_oclock", - "clock8", - "eight_oclock", - "clock9", - "nine_oclock", - "clock10", - "ten_oclock", - "clock11", - "eleven_oclock", - "clock12", - "twelve_oclock", - "clock130", - "one_thirty", - "clock230", - "two_thirty", - "clock330", - "three_thirty", - "clock430", - "four_thirty", - "clock530", - "five_thirty", - "clock630", - "six_thirty", - "clock730", - "seven_thirty", - "clock830", - "eight_thirty", - "clock930", - "nine_thirty", - "clock1030", - "ten_thirty", - "clock1130", - "eleven_thirty", - "clock1230", - "twelve_thirty", - "female_sign", - "male_sign", - "transgender_symbol", - "medical_symbol", - "regional_indicator_z", - "regional_indicator_y", - "regional_indicator_x", - "regional_indicator_w", - "regional_indicator_v", - "regional_indicator_u", - "regional_indicator_t", - "regional_indicator_s", - "regional_indicator_r", - "regional_indicator_q", - "regional_indicator_p", - "regional_indicator_o", - "regional_indicator_n", - "regional_indicator_m", - "regional_indicator_l", - "regional_indicator_k", - "regional_indicator_j", - "regional_indicator_i", - "regional_indicator_h", - "regional_indicator_g", - "regional_indicator_f", - "regional_indicator_e", - "regional_indicator_d", - "regional_indicator_c", - "regional_indicator_b", - "regional_indicator_a", - "red_car", - "automobile", - "taxi", - "blue_car", - "pickup_truck", - "minibus", - "bus", - "trolleybus", - "race_car", - "racing_car", - "police_car", - "ambulance", - "fire_engine", - "truck", - "articulated_lorry", - "tractor", - "probing_cane", - "manual_wheelchair", - "motorized_wheelchair", - "crutch", - "scooter", - "kick_scooter", - "bike", - "bicycle", - "motor_scooter", - "motorbike", - "motorcycle", - "racing_motorcycle", - "auto_rickshaw", - "wheel", - "rotating_light", - "oncoming_police_car", - "oncoming_bus", - "oncoming_automobile", - "oncoming_taxi", - "aerial_tramway", - "mountain_cableway", - "suspension_railway", - "railway_car", - "train", - "tram_car", - "mountain_railway", - "monorail", - "bullettrain_side", - "bullettrain_front", - "bullet_train", - "light_rail", - "steam_locomotive", - "locomotive", - "train2", - "metro", - "tram", - "station", - "airplane", - "airplane_departure", - "airplane_arriving", - "airplane_small", - "small_airplane", - "seat", - "satellite_orbital", - "rocket", - "flying_saucer", - "helicopter", - "canoe", - "kayak", - "sailboat", - "speedboat", - "motorboat", - "motor_boat", - "cruise_ship", - "passenger_ship", - "ferry", - "ship", - "ring_buoy", - "anchor", - "hook", - "fuelpump", - "fuel_pump", - "construction", - "vertical_traffic_light", - "traffic_light", - "busstop", - "bus_stop", - "map", - "world_map", - "moyai", - "moai", - "statue_of_liberty", - "tokyo_tower", - "european_castle", - "castle", - "japanese_castle", - "stadium", - "ferris_wheel", - "roller_coaster", - "carousel_horse", - "fountain", - "beach_umbrella", - "umbrella_on_ground", - "beach", - "beach_with_umbrella", - "island", - "desert_island", - "desert", - "volcano", - "mountain", - "mountain_snow", - "snow_capped_mountain", - "mount_fuji", - "camping", - "tent", - "house", - "house_with_garden", - "homes", - "house_buildings", - "houses", - "house_abandoned", - "derelict_house_building", - "hut", - "construction_site", - "building_construction", - "factory", - "office", - "department_store", - "post_office", - "european_post_office", - "hospital", - "bank", - "hotel", - "convenience_store", - "school", - "love_hotel", - "wedding", - "classical_building", - "church", - "mosque", - "synagogue", - "hindu_temple", - "kaaba", - "shinto_shrine", - "railway_track", - "railroad_track", - "motorway", - "japan", - "map_of_japan", - "rice_scene", - "park", - "national_park", - "sunrise", - "sunrise_over_mountains", - "stars", - "shooting_star", - "sparkler", - "fireworks", - "city_sunset", - "city_sunrise", - "sunset", - "city_dusk", - "cityscape", - "night_with_stars", - "milky_way", - "bridge_at_night", - "foggy" -]; - -# List of all emojis. -list emoji_values = [ - "💯", - "🔢", - "⚽", - "⚽", - "🏀", - "🏈", - "⚾", - "🥎", - "🎾", - "🏐", - "🏉", - "🥏", - "🎱", - "🪀", - "🏓", - "🏓", - "🏸", - "🏒", - "🏒", - "🏑", - "🥍", - "🏏", - "🏏", - "🪃", - "🥅", - "🥅", - "⛳", - "⛳", - "🪁", - "🛝", - "🏹", - "🏹", - "🎣", - "🎣", - "🤿", - "🥊", - "🥊", - "🥋", - "🥋", - "🎽", - "🎽", - "🛹", - "🛼", - "🛷", - "⛸️", - "🥌", - "🎿", - "🎿", - "⛷️", - "🏂", - "🏂🏻", - "🏂🏻", - "🏂🏼", - "🏂🏼", - "🏂🏽", - "🏂🏽", - "🏂🏾", - "🏂🏾", - "🏂🏿", - "🏂🏿", - "🪂", - "🏋️", - "🏋️", - "🏋️", - "🏋🏻", - "🏋🏻", - "🏋🏻", - "🏋🏼", - "🏋🏼", - "🏋🏼", - "🏋🏽", - "🏋🏽", - "🏋🏽", - "🏋🏾", - "🏋🏾", - "🏋🏾", - "🏋🏿", - "🏋🏿", - "🏋🏿", - "🏋️‍♀️", - "🏋🏻‍♀️", - "🏋🏻‍♀️", - "🏋🏼‍♀️", - "🏋🏼‍♀️", - "🏋🏽‍♀️", - "🏋🏽‍♀️", - "🏋🏾‍♀️", - "🏋🏾‍♀️", - "🏋🏿‍♀️", - "🏋🏿‍♀️", - "🏋️‍♂️", - "🏋🏻‍♂️", - "🏋🏻‍♂️", - "🏋🏼‍♂️", - "🏋🏼‍♂️", - "🏋🏽‍♂️", - "🏋🏽‍♂️", - "🏋🏾‍♂️", - "🏋🏾‍♂️", - "🏋🏿‍♂️", - "🏋🏿‍♂️", - "🤼", - "🤼", - "🤼", - "🤼‍♀️", - "🤼‍♂️", - "🤸", - "🤸", - "🤸🏻", - "🤸🏻", - "🤸🏼", - "🤸🏼", - "🤸🏽", - "🤸🏽", - "🤸🏾", - "🤸🏾", - "🤸🏿", - "🤸🏿", - "🤸‍♀️", - "🤸🏻‍♀️", - "🤸🏻‍♀️", - "🤸🏼‍♀️", - "🤸🏼‍♀️", - "🤸🏽‍♀️", - "🤸🏽‍♀️", - "🤸🏾‍♀️", - "🤸🏾‍♀️", - "🤸🏿‍♀️", - "🤸🏿‍♀️", - "🤸‍♂️", - "🤸🏻‍♂️", - "🤸🏻‍♂️", - "🤸🏼‍♂️", - "🤸🏼‍♂️", - "🤸🏽‍♂️", - "🤸🏽‍♂️", - "🤸🏾‍♂️", - "🤸🏾‍♂️", - "🤸🏿‍♂️", - "🤸🏿‍♂️", - "⛹️", - "⛹️", - "⛹️", - "⛹🏻", - "⛹🏻", - "⛹🏻", - "⛹🏼", - "⛹🏼", - "⛹🏼", - "⛹🏽", - "⛹🏽", - "⛹🏽", - "⛹🏾", - "⛹🏾", - "⛹🏾", - "⛹🏿", - "⛹🏿", - "⛹🏿", - "⛹️‍♀️", - "⛹🏻‍♀️", - "⛹🏻‍♀️", - "⛹🏼‍♀️", - "⛹🏼‍♀️", - "⛹🏽‍♀️", - "⛹🏽‍♀️", - "⛹🏾‍♀️", - "⛹🏾‍♀️", - "⛹🏿‍♀️", - "⛹🏿‍♀️", - "⛹️‍♂️", - "⛹🏻‍♂️", - "⛹🏻‍♂️", - "⛹🏼‍♂️", - "⛹🏼‍♂️", - "⛹🏽‍♂️", - "⛹🏽‍♂️", - "⛹🏾‍♂️", - "⛹🏾‍♂️", - "⛹🏿‍♂️", - "⛹🏿‍♂️", - "🤺", - "🤺", - "🤺", - "🤾", - "🤾", - "🤾🏻", - "🤾🏻", - "🤾🏼", - "🤾🏼", - "🤾🏽", - "🤾🏽", - "🤾🏾", - "🤾🏾", - "🤾🏿", - "🤾🏿", - "🤾‍♀️", - "🤾🏻‍♀️", - "🤾🏻‍♀️", - "🤾🏼‍♀️", - "🤾🏼‍♀️", - "🤾🏽‍♀️", - "🤾🏽‍♀️", - "🤾🏾‍♀️", - "🤾🏾‍♀️", - "🤾🏿‍♀️", - "🤾🏿‍♀️", - "🤾‍♂️", - "🤾🏻‍♂️", - "🤾🏻‍♂️", - "🤾🏼‍♂️", - "🤾🏼‍♂️", - "🤾🏽‍♂️", - "🤾🏽‍♂️", - "🤾🏾‍♂️", - "🤾🏾‍♂️", - "🤾🏿‍♂️", - "🤾🏿‍♂️", - "🏌️", - "🏌️", - "🏌🏻", - "🏌🏻", - "🏌🏼", - "🏌🏼", - "🏌🏽", - "🏌🏽", - "🏌🏾", - "🏌🏾", - "🏌🏿", - "🏌🏿", - "🏌️‍♀️", - "🏌🏻‍♀️", - "🏌🏻‍♀️", - "🏌🏼‍♀️", - "🏌🏼‍♀️", - "🏌🏽‍♀️", - "🏌🏽‍♀️", - "🏌🏾‍♀️", - "🏌🏾‍♀️", - "🏌🏿‍♀️", - "🏌🏿‍♀️", - "🏌️‍♂️", - "🏌🏻‍♂️", - "🏌🏻‍♂️", - "🏌🏼‍♂️", - "🏌🏼‍♂️", - "🏌🏽‍♂️", - "🏌🏽‍♂️", - "🏌🏾‍♂️", - "🏌🏾‍♂️", - "🏌🏿‍♂️", - "🏌🏿‍♂️", - "🏇", - "🏇🏻", - "🏇🏼", - "🏇🏽", - "🏇🏾", - "🏇🏿", - "🧘", - "🧘🏻", - "🧘🏻", - "🧘🏼", - "🧘🏼", - "🧘🏽", - "🧘🏽", - "🧘🏾", - "🧘🏾", - "🧘🏿", - "🧘🏿", - "🧘‍♀️", - "🧘🏻‍♀️", - "🧘🏻‍♀️", - "🧘🏼‍♀️", - "🧘🏼‍♀️", - "🧘🏽‍♀️", - "🧘🏽‍♀️", - "🧘🏾‍♀️", - "🧘🏾‍♀️", - "🧘🏿‍♀️", - "🧘🏿‍♀️", - "🧘‍♂️", - "🧘🏻‍♂️", - "🧘🏻‍♂️", - "🧘🏼‍♂️", - "🧘🏼‍♂️", - "🧘🏽‍♂️", - "🧘🏽‍♂️", - "🧘🏾‍♂️", - "🧘🏾‍♂️", - "🧘🏿‍♂️", - "🧘🏿‍♂️", - "🏄", - "🏄", - "🏄🏻", - "🏄🏻", - "🏄🏼", - "🏄🏼", - "🏄🏽", - "🏄🏽", - "🏄🏾", - "🏄🏾", - "🏄🏿", - "🏄🏿", - "🏄‍♀️", - "🏄🏻‍♀️", - "🏄🏻‍♀️", - "🏄🏼‍♀️", - "🏄🏼‍♀️", - "🏄🏽‍♀️", - "🏄🏽‍♀️", - "🏄🏾‍♀️", - "🏄🏾‍♀️", - "🏄🏿‍♀️", - "🏄🏿‍♀️", - "🏄‍♂️", - "🏄🏻‍♂️", - "🏄🏻‍♂️", - "🏄🏼‍♂️", - "🏄🏼‍♂️", - "🏄🏽‍♂️", - "🏄🏽‍♂️", - "🏄🏾‍♂️", - "🏄🏾‍♂️", - "🏄🏿‍♂️", - "🏄🏿‍♂️", - "🏊", - "🏊", - "🏊🏻", - "🏊🏻", - "🏊🏼", - "🏊🏼", - "🏊🏽", - "🏊🏽", - "🏊🏾", - "🏊🏾", - "🏊🏿", - "🏊🏿", - "🏊‍♀️", - "🏊🏻‍♀️", - "🏊🏻‍♀️", - "🏊🏼‍♀️", - "🏊🏼‍♀️", - "🏊🏽‍♀️", - "🏊🏽‍♀️", - "🏊🏾‍♀️", - "🏊🏾‍♀️", - "🏊🏿‍♀️", - "🏊🏿‍♀️", - "🏊‍♂️", - "🏊🏻‍♂️", - "🏊🏻‍♂️", - "🏊🏼‍♂️", - "🏊🏼‍♂️", - "🏊🏽‍♂️", - "🏊🏽‍♂️", - "🏊🏾‍♂️", - "🏊🏾‍♂️", - "🏊🏿‍♂️", - "🏊🏿‍♂️", - "🤽", - "🤽", - "🤽🏻", - "🤽🏻", - "🤽🏼", - "🤽🏼", - "🤽🏽", - "🤽🏽", - "🤽🏾", - "🤽🏾", - "🤽🏿", - "🤽🏿", - "🤽‍♀️", - "🤽🏻‍♀️", - "🤽🏻‍♀️", - "🤽🏼‍♀️", - "🤽🏼‍♀️", - "🤽🏽‍♀️", - "🤽🏽‍♀️", - "🤽🏾‍♀️", - "🤽🏾‍♀️", - "🤽🏿‍♀️", - "🤽🏿‍♀️", - "🤽‍♂️", - "🤽🏻‍♂️", - "🤽🏻‍♂️", - "🤽🏼‍♂️", - "🤽🏼‍♂️", - "🤽🏽‍♂️", - "🤽🏽‍♂️", - "🤽🏾‍♂️", - "🤽🏾‍♂️", - "🤽🏿‍♂️", - "🤽🏿‍♂️", - "🚣", - "🚣", - "🚣🏻", - "🚣🏻", - "🚣🏼", - "🚣🏼", - "🚣🏽", - "🚣🏽", - "🚣🏾", - "🚣🏾", - "🚣🏿", - "🚣🏿", - "🚣‍♀️", - "🚣🏻‍♀️", - "🚣🏻‍♀️", - "🚣🏼‍♀️", - "🚣🏼‍♀️", - "🚣🏽‍♀️", - "🚣🏽‍♀️", - "🚣🏾‍♀️", - "🚣🏾‍♀️", - "🚣🏿‍♀️", - "🚣🏿‍♀️", - "🚣‍♂️", - "🚣🏻‍♂️", - "🚣🏻‍♂️", - "🚣🏼‍♂️", - "🚣🏼‍♂️", - "🚣🏽‍♂️", - "🚣🏽‍♂️", - "🚣🏾‍♂️", - "🚣🏾‍♂️", - "🚣🏿‍♂️", - "🚣🏿‍♂️", - "🧗", - "🧗🏻", - "🧗🏻", - "🧗🏼", - "🧗🏼", - "🧗🏽", - "🧗🏽", - "🧗🏾", - "🧗🏾", - "🧗🏿", - "🧗🏿", - "🧗‍♀️", - "🧗🏻‍♀️", - "🧗🏻‍♀️", - "🧗🏼‍♀️", - "🧗🏼‍♀️", - "🧗🏽‍♀️", - "🧗🏽‍♀️", - "🧗🏾‍♀️", - "🧗🏾‍♀️", - "🧗🏿‍♀️", - "🧗🏿‍♀️", - "🧗‍♂️", - "🧗🏻‍♂️", - "🧗🏻‍♂️", - "🧗🏼‍♂️", - "🧗🏼‍♂️", - "🧗🏽‍♂️", - "🧗🏽‍♂️", - "🧗🏾‍♂️", - "🧗🏾‍♂️", - "🧗🏿‍♂️", - "🧗🏿‍♂️", - "🚵", - "🚵", - "🚵🏻", - "🚵🏻", - "🚵🏼", - "🚵🏼", - "🚵🏽", - "🚵🏽", - "🚵🏾", - "🚵🏾", - "🚵🏿", - "🚵🏿", - "🚵‍♀️", - "🚵🏻‍♀️", - "🚵🏻‍♀️", - "🚵🏼‍♀️", - "🚵🏼‍♀️", - "🚵🏽‍♀️", - "🚵🏽‍♀️", - "🚵🏾‍♀️", - "🚵🏾‍♀️", - "🚵🏿‍♀️", - "🚵🏿‍♀️", - "🚵‍♂️", - "🚵🏻‍♂️", - "🚵🏻‍♂️", - "🚵🏼‍♂️", - "🚵🏼‍♂️", - "🚵🏽‍♂️", - "🚵🏽‍♂️", - "🚵🏾‍♂️", - "🚵🏾‍♂️", - "🚵🏿‍♂️", - "🚵🏿‍♂️", - "🚴", - "🚴", - "🚴🏻", - "🚴🏻", - "🚴🏼", - "🚴🏼", - "🚴🏽", - "🚴🏽", - "🚴🏾", - "🚴🏾", - "🚴🏿", - "🚴🏿", - "🚴‍♀️", - "🚴🏻‍♀️", - "🚴🏻‍♀️", - "🚴🏼‍♀️", - "🚴🏼‍♀️", - "🚴🏽‍♀️", - "🚴🏽‍♀️", - "🚴🏾‍♀️", - "🚴🏾‍♀️", - "🚴🏿‍♀️", - "🚴🏿‍♀️", - "🚴‍♂️", - "🚴🏻‍♂️", - "🚴🏻‍♂️", - "🚴🏼‍♂️", - "🚴🏼‍♂️", - "🚴🏽‍♂️", - "🚴🏽‍♂️", - "🚴🏾‍♂️", - "🚴🏾‍♂️", - "🚴🏿‍♂️", - "🚴🏿‍♂️", - "🏆", - "🥇", - "🥇", - "🥈", - "🥈", - "🥉", - "🥉", - "🏅", - "🏅", - "🎖️", - "🏵️", - "🎗️", - "🎫", - "🎟️", - "🎟️", - "🎪", - "🤹", - "🤹", - "🤹", - "🤹🏻", - "🤹🏻", - "🤹🏻", - "🤹🏼", - "🤹🏼", - "🤹🏼", - "🤹🏽", - "🤹🏽", - "🤹🏽", - "🤹🏾", - "🤹🏾", - "🤹🏾", - "🤹🏿", - "🤹🏿", - "🤹🏿", - "🤹‍♀️", - "🤹🏻‍♀️", - "🤹🏻‍♀️", - "🤹🏼‍♀️", - "🤹🏼‍♀️", - "🤹🏽‍♀️", - "🤹🏽‍♀️", - "🤹🏾‍♀️", - "🤹🏾‍♀️", - "🤹🏿‍♀️", - "🤹🏿‍♀️", - "🤹‍♂️", - "🤹🏻‍♂️", - "🤹🏻‍♂️", - "🤹🏼‍♂️", - "🤹🏼‍♂️", - "🤹🏽‍♂️", - "🤹🏽‍♂️", - "🤹🏾‍♂️", - "🤹🏾‍♂️", - "🤹🏿‍♂️", - "🤹🏿‍♂️", - "🎭", - "🩰", - "🎨", - "🎬", - "🎬", - "🎤", - "🎧", - "🎧", - "🎼", - "🎹", - "🪇", - "🥁", - "🥁", - "🪘", - "🎷", - "🎺", - "🪗", - "🎸", - "🪕", - "🎻", - "🪈", - "🎲", - "♟️", - "🎯", - "🎯", - "🎳", - "🎮", - "🎰", - "🧩", - "🧩", - "🏳️", - "🏴", - "🏴‍☠️", - "🏁", - "🚩", - "🏳️‍🌈", - "🏳️‍🌈", - "🏳️‍⚧️", - "🇺🇳", - "🇦🇫", - "🇦🇽", - "🇦🇱", - "🇩🇿", - "🇦🇸", - "🇦🇩", - "🇦🇴", - "🇦🇮", - "🇦🇶", - "🇦🇬", - "🇦🇷", - "🇦🇲", - "🇦🇼", - "🇦🇺", - "🇦🇹", - "🇦🇿", - "🇧🇸", - "🇧🇭", - "🇧🇩", - "🇧🇧", - "🇧🇾", - "🇧🇪", - "🇧🇿", - "🇧🇯", - "🇧🇲", - "🇧🇹", - "🇧🇴", - "🇧🇦", - "🇧🇼", - "🇧🇷", - "🇮🇴", - "🇻🇬", - "🇧🇳", - "🇧🇬", - "🇧🇫", - "🇧🇮", - "🇰🇭", - "🇨🇲", - "🇨🇦", - "🇮🇨", - "🇨🇻", - "🇧🇶", - "🇰🇾", - "🇨🇫", - "🇹🇩", - "🇨🇱", - "🇨🇳", - "🇨🇽", - "🇨🇨", - "🇨🇴", - "🇰🇲", - "🇨🇬", - "🇨🇩", - "🇨🇰", - "🇨🇷", - "🇨🇮", - "🇭🇷", - "🇨🇺", - "🇨🇼", - "🇨🇾", - "🇨🇿", - "🇩🇰", - "🇩🇯", - "🇩🇲", - "🇩🇴", - "🇪🇨", - "🇪🇬", - "🇸🇻", - "🇬🇶", - "🇪🇷", - "🇪🇪", - "🇪🇹", - "🇪🇺", - "🇫🇰", - "🇫🇴", - "🇫🇯", - "🇫🇮", - "🇫🇷", - "🇬🇫", - "🇵🇫", - "🇹🇫", - "🇬🇦", - "🇬🇲", - "🇬🇪", - "🇩🇪", - "🇬🇭", - "🇬🇮", - "🇬🇷", - "🇬🇱", - "🇬🇩", - "🇬🇵", - "🇬🇺", - "🇬🇹", - "🇬🇬", - "🇬🇳", - "🇬🇼", - "🇬🇾", - "🇭🇹", - "🇭🇳", - "🇭🇰", - "🇭🇺", - "🇮🇸", - "🇮🇳", - "🇮🇩", - "🇮🇷", - "🇮🇶", - "🇮🇪", - "🇮🇲", - "🇮🇱", - "🇮🇹", - "🇯🇲", - "🇯🇵", - "🎌", - "🇯🇪", - "🇯🇴", - "🇰🇿", - "🇰🇪", - "🇰🇮", - "🇽🇰", - "🇰🇼", - "🇰🇬", - "🇱🇦", - "🇱🇻", - "🇱🇧", - "🇱🇸", - "🇱🇷", - "🇱🇾", - "🇱🇮", - "🇱🇹", - "🇱🇺", - "🇲🇴", - "🇲🇰", - "🇲🇬", - "🇲🇼", - "🇲🇾", - "🇲🇻", - "🇲🇱", - "🇲🇹", - "🇲🇭", - "🇲🇶", - "🇲🇷", - "🇲🇺", - "🇾🇹", - "🇲🇽", - "🇫🇲", - "🇲🇩", - "🇲🇨", - "🇲🇳", - "🇲🇪", - "🇲🇸", - "🇲🇦", - "🇲🇿", - "🇲🇲", - "🇳🇦", - "🇳🇷", - "🇳🇵", - "🇳🇱", - "🇳🇨", - "🇳🇿", - "🇳🇮", - "🇳🇪", - "🇳🇬", - "🇳🇺", - "🇳🇫", - "🇰🇵", - "🇲🇵", - "🇳🇴", - "🇴🇲", - "🇵🇰", - "🇵🇼", - "🇵🇸", - "🇵🇦", - "🇵🇬", - "🇵🇾", - "🇵🇪", - "🇵🇭", - "🇵🇳", - "🇵🇱", - "🇵🇹", - "🇵🇷", - "🇶🇦", - "🇷🇪", - "🇷🇴", - "🇷🇺", - "🇷🇼", - "🇼🇸", - "🇸🇲", - "🇸🇹", - "🇸🇦", - "🇸🇳", - "🇷🇸", - "🇸🇨", - "🇸🇱", - "🇸🇬", - "🇸🇽", - "🇸🇰", - "🇸🇮", - "🇬🇸", - "🇸🇧", - "🇸🇴", - "🇿🇦", - "🇰🇷", - "🇸🇸", - "🇪🇸", - "🇱🇰", - "🇧🇱", - "🇸🇭", - "🇰🇳", - "🇱🇨", - "🇵🇲", - "🇻🇨", - "🇸🇩", - "🇸🇷", - "🇸🇿", - "🇸🇪", - "🇨🇭", - "🇸🇾", - "🇹🇼", - "🇹🇯", - "🇹🇿", - "🇹🇭", - "🇹🇱", - "🇹🇬", - "🇹🇰", - "🇹🇴", - "🇹🇹", - "🇹🇳", - "🇹🇷", - "🇹🇲", - "🇹🇨", - "🇻🇮", - "🇹🇻", - "🇺🇬", - "🇺🇦", - "🇦🇪", - "🇬🇧", - "🏴󠁧󠁢󠁥󠁮󠁧󠁿", - "🏴󠁧󠁢󠁳󠁣󠁴󠁿", - "🏴󠁧󠁢󠁷󠁬󠁳󠁿", - "🇺🇸", - "🇺🇾", - "🇺🇿", - "🇻🇺", - "🇻🇦", - "🇻🇪", - "🇻🇳", - "🇼🇫", - "🇪🇭", - "🇾🇪", - "🇿🇲", - "🇿🇼", - "🇦🇨", - "🇧🇻", - "🇨🇵", - "🇪🇦", - "🇩🇬", - "🇭🇲", - "🇲🇫", - "🇸🇯", - "🇹🇦", - "🇺🇲", - "🍏", - "🍎", - "🍎", - "🍐", - "🍊", - "🍋", - "🍌", - "🍉", - "🍇", - "🍓", - "🫐", - "🍈", - "🍒", - "🍑", - "🥭", - "🍍", - "🥥", - "🥝", - "🥝", - "🥝", - "🍅", - "🍆", - "🥑", - "🫛", - "🥦", - "🥬", - "🥒", - "🌶️", - "🫑", - "🌽", - "🌽", - "🥕", - "🫒", - "🧄", - "🧅", - "🥔", - "🍠", - "🫚", - "🥐", - "🥯", - "🍞", - "🥖", - "🥖", - "🥨", - "🧀", - "🧀", - "🥚", - "🍳", - "🧈", - "🥞", - "🧇", - "🥓", - "🥩", - "🍗", - "🍖", - "🦴", - "🌭", - "🌭", - "🍔", - "🍟", - "🍟", - "🍕", - "🫓", - "🥪", - "🥙", - "🥙", - "🧆", - "🌮", - "🌯", - "🫔", - "🥗", - "🥗", - "🥘", - "🥘", - "🫕", - "🥫", - "🫙", - "🍝", - "🍜", - "🍜", - "🍲", - "🍲", - "🍛", - "🍛", - "🍣", - "🍱", - "🍱", - "🥟", - "🦪", - "🍤", - "🍙", - "🍚", - "🍚", - "🍘", - "🍥", - "🥠", - "🥮", - "🍢", - "🍡", - "🍧", - "🍨", - "🍦", - "🥧", - "🧁", - "🍰", - "🍰", - "🎂", - "🎂", - "🍮", - "🍮", - "🍮", - "🍭", - "🍬", - "🍫", - "🍿", - "🍩", - "🍪", - "🌰", - "🥜", - "🥜", - "🫘", - "🍯", - "🥛", - "🥛", - "🫗", - "🍼", - "🫖", - "☕", - "☕", - "🍵", - "🧉", - "🧃", - "🥤", - "🧋", - "🍶", - "🍺", - "🍺", - "🍻", - "🥂", - "🥂", - "🍷", - "🥃", - "🥃", - "🍸", - "🍹", - "🍾", - "🍾", - "🧊", - "🥄", - "🍴", - "🍽️", - "🍽️", - "🥣", - "🥡", - "🥢", - "🧂", - "🐶", - "🐶", - "🐱", - "🐱", - "🐭", - "🐭", - "🐹", - "🐰", - "🐰", - "🦊", - "🦊", - "🐻", - "🐼", - "🐼", - "🐻‍❄️", - "🐨", - "🐯", - "🐯", - "🦁", - "🦁", - "🐮", - "🐮", - "🐷", - "🐷", - "🐽", - "🐸", - "🐵", - "🙈", - "🙉", - "🙊", - "🐒", - "🐔", - "🐧", - "🐦", - "🐤", - "🐣", - "🐥", - "🪿", - "🦆", - "🐦‍⬛", - "🦅", - "🦉", - "🦇", - "🐺", - "🐗", - "🐴", - "🐴", - "🦄", - "🦄", - "🫎", - "🐝", - "🐝", - "🪱", - "🐛", - "🦋", - "🐌", - "🐞", - "🐜", - "🪰", - "🪲", - "🪳", - "🦟", - "🦗", - "🕷️", - "🕸️", - "🦂", - "🐢", - "🐍", - "🦎", - "🦖", - "🦕", - "🐙", - "🦑", - "🪼", - "🦐", - "🦞", - "🦀", - "🐡", - "🐠", - "🐟", - "🐬", - "🐳", - "🐋", - "🦈", - "🦭", - "🐊", - "🐅", - "🐆", - "🦓", - "🦍", - "🦧", - "🦣", - "🐘", - "🦛", - "🦏", - "🦏", - "🐪", - "🐫", - "🦒", - "🦘", - "🦬", - "🐃", - "🐂", - "🐄", - "🫏", - "🐎", - "🐖", - "🐏", - "🐑", - "🐑", - "🦙", - "🐐", - "🦌", - "🐕", - "🐩", - "🦮", - "🐕‍🦺", - "🐈", - "🐈‍⬛", - "🪶", - "🪽", - "🐓", - "🦃", - "🦤", - "🦚", - "🦜", - "🦢", - "🦩", - "🕊️", - "🕊️", - "🐇", - "🦝", - "🦨", - "🦡", - "🦫", - "🦦", - "🦥", - "🐁", - "🐀", - "🐿️", - "🦔", - "🐾", - "🐾", - "🐉", - "🐲", - "🌵", - "🎄", - "🌲", - "🌳", - "🌴", - "🪵", - "🌱", - "🌿", - "☘️", - "🍀", - "🎍", - "🪴", - "🎋", - "🍃", - "🍂", - "🍁", - "🪺", - "🪹", - "🍄", - "🐚", - "🐚", - "🪸", - "🪨", - "🌾", - "🌾", - "💐", - "🌷", - "🌹", - "🥀", - "🥀", - "🪻", - "🪷", - "🌺", - "🌸", - "🌼", - "🌻", - "🌞", - "🌝", - "🌛", - "🌜", - "🌚", - "🌚", - "🌕", - "🌖", - "🌗", - "🌘", - "🌑", - "🌒", - "🌓", - "🌔", - "🌙", - "🌎", - "🌍", - "🌏", - "🪐", - "💫", - "⭐", - "🌟", - "🌟", - "✨", - "⚡", - "⚡", - "☄️", - "💥", - "💥", - "🔥", - "🔥", - "🌪️", - "🌪️", - "🌪️", - "🌈", - "☀️", - "☀️", - "🌤️", - "🌤️", - "⛅", - "🌥️", - "🌥️", - "☁️", - "🌦️", - "🌦️", - "🌧️", - "🌧️", - "⛈️", - "⛈️", - "🌩️", - "🌩️", - "🌨️", - "🌨️", - "❄️", - "☃️", - "⛄", - "🌬️", - "🌬️", - "💨", - "💨", - "💧", - "💦", - "🫧", - "☔", - "☂️", - "🌊", - "🌊", - "🌫️", - "⌚", - "📱", - "📱", - "📲", - "💻", - "⌨️", - "🖥️", - "🖥️", - "🖨️", - "🖱️", - "🖱️", - "🖲️", - "🕹️", - "🗜️", - "🗜️", - "💽", - "💽", - "💾", - "💿", - "💿", - "📀", - "📼", - "📼", - "📷", - "📸", - "📹", - "🎥", - "📽️", - "📽️", - "🎞️", - "📞", - "☎️", - "📟", - "📠", - "📠", - "📺", - "📺", - "📻", - "🎙️", - "🎙️", - "🎚️", - "🎛️", - "🧭", - "⏱️", - "⏲️", - "⏲️", - "⏰", - "🕰️", - "🕰️", - "⌛", - "⏳", - "📡", - "🔋", - "🪫", - "🔌", - "💡", - "💡", - "🔦", - "🕯️", - "🪔", - "🧯", - "🛢️", - "🛢️", - "💸", - "💵", - "💴", - "💴", - "💶", - "💶", - "💷", - "🪙", - "💰", - "💰", - "💳", - "🪪", - "💎", - "💎", - "⚖️", - "⚖️", - "🪜", - "🧰", - "🪛", - "🔧", - "🔨", - "⚒️", - "⚒️", - "🛠️", - "🛠️", - "⛏️", - "🪚", - "🔩", - "⚙️", - "🪤", - "🧱", - "🧱", - "⛓️", - "🧲", - "🔫", - "🔫", - "💣", - "🧨", - "🪓", - "🔪", - "🔪", - "🗡️", - "🗡️", - "⚔️", - "🛡️", - "🚬", - "🚬", - "⚰️", - "🪦", - "⚱️", - "⚱️", - "🏺", - "🔮", - "📿", - "🧿", - "🪬", - "💈", - "💈", - "⚗️", - "🔭", - "🔬", - "🕳️", - "🩻", - "🩹", - "🩺", - "💊", - "💉", - "🩸", - "🧬", - "🦠", - "🧫", - "🧪", - "🌡️", - "🧹", - "🪠", - "🧺", - "🧻", - "🚽", - "🚰", - "🚿", - "🛁", - "🛀", - "🛀🏻", - "🛀🏼", - "🛀🏽", - "🛀🏾", - "🛀🏿", - "🧼", - "🪥", - "🪒", - "🪮", - "🧽", - "🪣", - "🧴", - "🧴", - "🛎️", - "🛎️", - "🔑", - "🗝️", - "🗝️", - "🚪", - "🪑", - "🛋️", - "🛋️", - "🛏️", - "🛌", - "🛌", - "🛌🏻", - "🛌🏻", - "🛌🏼", - "🛌🏼", - "🛌🏽", - "🛌🏽", - "🛌🏾", - "🛌🏾", - "🛌🏿", - "🛌🏿", - "🧸", - "🪆", - "🖼️", - "🖼️", - "🪞", - "🪟", - "🛍️", - "🛒", - "🛒", - "🎁", - "🎁", - "🎈", - "🎏", - "🎏", - "🎀", - "🪄", - "🪅", - "🎊", - "🎉", - "🎉", - "🎎", - "🪭", - "🏮", - "🎐", - "🪩", - "🧧", - "✉️", - "📩", - "📨", - "📧", - "📧", - "💌", - "📥", - "📤", - "📦", - "🏷️", - "🪧", - "📪", - "📫", - "📬", - "📭", - "📮", - "📯", - "📜", - "📃", - "📄", - "📑", - "🧾", - "📊", - "📈", - "📉", - "🗒️", - "🗒️", - "🗓️", - "🗓️", - "📆", - "📅", - "🗑️", - "📇", - "🗃️", - "🗃️", - "🗳️", - "🗳️", - "🗄️", - "📋", - "📁", - "📂", - "🗂️", - "🗂️", - "🗞️", - "🗞️", - "📰", - "📓", - "📔", - "📒", - "📕", - "📗", - "📘", - "📙", - "📚", - "📖", - "📖", - "🔖", - "🧷", - "🔗", - "📎", - "🖇️", - "🖇️", - "📐", - "📏", - "🧮", - "📌", - "📍", - "✂️", - "🖊️", - "🖊️", - "🖊️", - "🖋️", - "🖋️", - "🖋️", - "✒️", - "🖌️", - "🖌️", - "🖍️", - "🖍️", - "📝", - "📝", - "✏️", - "🔍", - "🔎", - "🔏", - "🔐", - "🔒", - "🔒", - "🔓", - "🔓", - "😀", - "😀", - "😃", - "😄", - "😁", - "😆", - "😆", - "🥹", - "😅", - "😂", - "🤣", - "🤣", - "🥲", - "☺️", - "☺️", - "😊", - "😇", - "🙂", - "🙂", - "🙃", - "🙃", - "😉", - "😉", - "😌", - "😌", - "😍", - "🥰", - "😘", - "😗", - "😗", - "😙", - "😚", - "😋", - "😛", - "😝", - "😜", - "🤪", - "🤨", - "🧐", - "🤓", - "🤓", - "😎", - "🥸", - "🤩", - "🥳", - "😏", - "😏", - "😒", - "😒", - "😞", - "😔", - "😔", - "😟", - "😟", - "😕", - "😕", - "🙁", - "🙁", - "☹️", - "☹️", - "☹️", - "😣", - "😖", - "😫", - "😩", - "😩", - "🥺", - "😢", - "😢", - "😭", - "😤", - "😠", - "😠", - "😡", - "😡", - "🤬", - "🤯", - "😳", - "😳", - "🥵", - "🥶", - "😶‍🌫️", - "😱", - "😨", - "😨", - "😰", - "😥", - "😓", - "🤗", - "🤗", - "🤔", - "🤔", - "🫣", - "🤭", - "🫢", - "🫡", - "🤫", - "🫠", - "🤥", - "🤥", - "😶", - "🫥", - "😐", - "🫤", - "😑", - "🫨", - "😬", - "🙄", - "🙄", - "😯", - "😯", - "😦", - "😧", - "😮", - "😲", - "🥱", - "😴", - "😴", - "🤤", - "🤤", - "😪", - "😪", - "😮‍💨", - "😵", - "😵‍💫", - "🤐", - "🤐", - "🥴", - "🤢", - "🤢", - "🤮", - "🤧", - "🤧", - "😷", - "🤒", - "🤒", - "🤕", - "🤕", - "🤑", - "🤑", - "🤠", - "🤠", - "😈", - "👿", - "👹", - "👹", - "👺", - "👺", - "🤡", - "🤡", - "💩", - "💩", - "💩", - "💩", - "💩", - "👻", - "💀", - "💀", - "☠️", - "☠️", - "👽", - "👾", - "👾", - "🤖", - "🤖", - "🎃", - "😺", - "😺", - "😸", - "😹", - "😻", - "😼", - "😽", - "🙀", - "🙀", - "😿", - "😿", - "😾", - "🫶", - "🫶🏻", - "🫶🏻", - "🫶🏼", - "🫶🏼", - "🫶🏽", - "🫶🏽", - "🫶🏾", - "🫶🏾", - "🫶🏿", - "🫶🏿", - "🤲", - "🤲🏻", - "🤲🏻", - "🤲🏼", - "🤲🏼", - "🤲🏽", - "🤲🏽", - "🤲🏾", - "🤲🏾", - "🤲🏿", - "🤲🏿", - "👐", - "👐🏻", - "👐🏼", - "👐🏽", - "👐🏾", - "👐🏿", - "🙌", - "🙌", - "🙌🏻", - "🙌🏼", - "🙌🏽", - "🙌🏾", - "🙌🏿", - "👏", - "👏🏻", - "👏🏼", - "👏🏽", - "👏🏾", - "👏🏿", - "🤝", - "🤝", - "🤝🏻", - "🤝🏻", - "🫱🏻‍🫲🏼", - "🫱🏻‍🫲🏼", - "🫱🏻‍🫲🏽", - "🫱🏻‍🫲🏽", - "🫱🏻‍🫲🏾", - "🫱🏻‍🫲🏾", - "🫱🏻‍🫲🏿", - "🫱🏻‍🫲🏿", - "🫱🏼‍🫲🏻", - "🫱🏼‍🫲🏻", - "🤝🏼", - "🤝🏼", - "🫱🏼‍🫲🏽", - "🫱🏼‍🫲🏽", - "🫱🏼‍🫲🏾", - "🫱🏼‍🫲🏾", - "🫱🏼‍🫲🏿", - "🫱🏼‍🫲🏿", - "🫱🏽‍🫲🏻", - "🫱🏽‍🫲🏻", - "🫱🏽‍🫲🏼", - "🫱🏽‍🫲🏼", - "🤝🏽", - "🤝🏽", - "🫱🏽‍🫲🏾", - "🫱🏽‍🫲🏾", - "🫱🏽‍🫲🏿", - "🫱🏽‍🫲🏿", - "🫱🏾‍🫲🏻", - "🫱🏾‍🫲🏻", - "🫱🏾‍🫲🏼", - "🫱🏾‍🫲🏼", - "🫱🏾‍🫲🏽", - "🫱🏾‍🫲🏽", - "🤝🏾", - "🤝🏾", - "🫱🏾‍🫲🏿", - "🫱🏾‍🫲🏿", - "🫱🏿‍🫲🏻", - "🫱🏿‍🫲🏻", - "🫱🏿‍🫲🏼", - "🫱🏿‍🫲🏼", - "🫱🏿‍🫲🏽", - "🫱🏿‍🫲🏽", - "🫱🏿‍🫲🏾", - "🫱🏿‍🫲🏾", - "🤝🏿", - "🤝🏿", - "👍", - "👍", - "👍", - "👍", - "👍🏻", - "👍🏻", - "👍🏻", - "👍🏼", - "👍🏼", - "👍🏼", - "👍🏽", - "👍🏽", - "👍🏽", - "👍🏾", - "👍🏾", - "👍🏾", - "👍🏿", - "👍🏿", - "👍🏿", - "👎", - "👎", - "👎", - "👎", - "👎🏻", - "👎🏻", - "👎🏻", - "👎🏼", - "👎🏼", - "👎🏼", - "👎🏽", - "👎🏽", - "👎🏽", - "👎🏾", - "👎🏾", - "👎🏾", - "👎🏿", - "👎🏿", - "👎🏿", - "👊", - "👊", - "👊🏻", - "👊🏼", - "👊🏽", - "👊🏾", - "👊🏿", - "✊", - "✊", - "✊🏻", - "✊🏼", - "✊🏽", - "✊🏾", - "✊🏿", - "🤛", - "🤛", - "🤛🏻", - "🤛🏻", - "🤛🏼", - "🤛🏼", - "🤛🏽", - "🤛🏽", - "🤛🏾", - "🤛🏾", - "🤛🏿", - "🤛🏿", - "🤜", - "🤜", - "🤜🏻", - "🤜🏻", - "🤜🏼", - "🤜🏼", - "🤜🏽", - "🤜🏽", - "🤜🏾", - "🤜🏾", - "🤜🏿", - "🤜🏿", - "🫷", - "🫷🏻", - "🫷🏻", - "🫷🏼", - "🫷🏼", - "🫷🏽", - "🫷🏽", - "🫷🏾", - "🫷🏾", - "🫷🏿", - "🫷🏿", - "🫸", - "🫸🏻", - "🫸🏻", - "🫸🏼", - "🫸🏼", - "🫸🏽", - "🫸🏽", - "🫸🏾", - "🫸🏾", - "🫸🏿", - "🫸🏿", - "🤞", - "🤞", - "🤞🏻", - "🤞🏻", - "🤞🏼", - "🤞🏼", - "🤞🏽", - "🤞🏽", - "🤞🏾", - "🤞🏾", - "🤞🏿", - "🤞🏿", - "✌️", - "✌️", - "✌🏻", - "✌🏼", - "✌🏽", - "✌🏾", - "✌🏿", - "🫰", - "🫰🏻", - "🫰🏻", - "🫰🏼", - "🫰🏼", - "🫰🏽", - "🫰🏽", - "🫰🏾", - "🫰🏾", - "🫰🏿", - "🫰🏿", - "🤟", - "🤟🏻", - "🤟🏻", - "🤟🏼", - "🤟🏼", - "🤟🏽", - "🤟🏽", - "🤟🏾", - "🤟🏾", - "🤟🏿", - "🤟🏿", - "🤘", - "🤘", - "🤘🏻", - "🤘🏻", - "🤘🏼", - "🤘🏼", - "🤘🏽", - "🤘🏽", - "🤘🏾", - "🤘🏾", - "🤘🏿", - "🤘🏿", - "👌", - "👌🏻", - "👌🏼", - "👌🏽", - "👌🏾", - "👌🏿", - "🤌", - "🤌🏼", - "🤌🏼", - "🤌🏻", - "🤌🏻", - "🤌🏽", - "🤌🏽", - "🤌🏾", - "🤌🏾", - "🤌🏿", - "🤌🏿", - "🤏", - "🤏🏻", - "🤏🏻", - "🤏🏼", - "🤏🏼", - "🤏🏽", - "🤏🏽", - "🤏🏾", - "🤏🏾", - "🤏🏿", - "🤏🏿", - "🫳", - "🫳🏻", - "🫳🏻", - "🫳🏼", - "🫳🏼", - "🫳🏽", - "🫳🏽", - "🫳🏾", - "🫳🏾", - "🫳🏿", - "🫳🏿", - "🫴", - "🫴🏻", - "🫴🏻", - "🫴🏼", - "🫴🏼", - "🫴🏽", - "🫴🏽", - "🫴🏾", - "🫴🏾", - "🫴🏿", - "🫴🏿", - "👈", - "👈🏻", - "👈🏼", - "👈🏽", - "👈🏾", - "👈🏿", - "👉", - "👉🏻", - "👉🏼", - "👉🏽", - "👉🏾", - "👉🏿", - "👆", - "👆🏻", - "👆🏼", - "👆🏽", - "👆🏾", - "👆🏿", - "👇", - "👇🏻", - "👇🏼", - "👇🏽", - "👇🏾", - "👇🏿", - "☝️", - "☝🏻", - "☝🏼", - "☝🏽", - "☝🏾", - "☝🏿", - "✋", - "✋🏻", - "✋🏼", - "✋🏽", - "✋🏾", - "✋🏿", - "🤚", - "🤚", - "🤚🏻", - "🤚🏻", - "🤚🏼", - "🤚🏼", - "🤚🏽", - "🤚🏽", - "🤚🏾", - "🤚🏾", - "🤚🏿", - "🤚🏿", - "🖐️", - "🖐️", - "🖐🏻", - "🖐🏻", - "🖐🏼", - "🖐🏼", - "🖐🏽", - "🖐🏽", - "🖐🏾", - "🖐🏾", - "🖐🏿", - "🖐🏿", - "🖖", - "🖖", - "🖖", - "🖖🏻", - "🖖🏻", - "🖖🏼", - "🖖🏼", - "🖖🏽", - "🖖🏽", - "🖖🏾", - "🖖🏾", - "🖖🏿", - "🖖🏿", - "👋", - "👋", - "👋🏻", - "👋🏼", - "👋🏽", - "👋🏾", - "👋🏿", - "🤙", - "🤙", - "🤙🏻", - "🤙🏻", - "🤙🏼", - "🤙🏼", - "🤙🏽", - "🤙🏽", - "🤙🏾", - "🤙🏾", - "🤙🏿", - "🤙🏿", - "🫲", - "🫲🏻", - "🫲🏻", - "🫲🏼", - "🫲🏼", - "🫲🏽", - "🫲🏽", - "🫲🏾", - "🫲🏾", - "🫲🏿", - "🫲🏿", - "🫱", - "🫱🏻", - "🫱🏻", - "🫱🏼", - "🫱🏼", - "🫱🏽", - "🫱🏽", - "🫱🏾", - "🫱🏾", - "🫱🏿", - "🫱🏿", - "💪", - "💪", - "💪🏻", - "💪🏼", - "💪🏽", - "💪🏾", - "💪🏿", - "🦾", - "🖕", - "🖕", - "🖕🏻", - "🖕🏻", - "🖕🏼", - "🖕🏼", - "🖕🏽", - "🖕🏽", - "🖕🏾", - "🖕🏾", - "🖕🏿", - "🖕🏿", - "✍️", - "✍🏻", - "✍🏼", - "✍🏽", - "✍🏾", - "✍🏿", - "🙏", - "🙏", - "🙏🏻", - "🙏🏼", - "🙏🏽", - "🙏🏾", - "🙏🏿", - "🫵", - "🫵🏻", - "🫵🏻", - "🫵🏼", - "🫵🏼", - "🫵🏽", - "🫵🏽", - "🫵🏾", - "🫵🏾", - "🫵🏿", - "🫵🏿", - "🦶", - "🦶🏻", - "🦶🏻", - "🦶🏼", - "🦶🏼", - "🦶🏽", - "🦶🏽", - "🦶🏾", - "🦶🏾", - "🦶🏿", - "🦶🏿", - "🦵", - "🦵🏻", - "🦵🏻", - "🦵🏼", - "🦵🏼", - "🦵🏽", - "🦵🏽", - "🦵🏾", - "🦵🏾", - "🦵🏿", - "🦵🏿", - "🦿", - "💄", - "💋", - "💋", - "👄", - "👄", - "🫦", - "🦷", - "👅", - "👂", - "👂🏻", - "👂🏼", - "👂🏽", - "👂🏾", - "👂🏿", - "🦻", - "🦻🏻", - "🦻🏻", - "🦻🏼", - "🦻🏼", - "🦻🏽", - "🦻🏽", - "🦻🏾", - "🦻🏾", - "🦻🏿", - "🦻🏿", - "👃", - "👃🏻", - "👃🏼", - "👃🏽", - "👃🏾", - "👃🏿", - "👣", - "👁️", - "👀", - "🫀", - "🫁", - "🧠", - "🗣️", - "🗣️", - "👤", - "👥", - "🫂", - "👶", - "👶🏻", - "👶🏼", - "👶🏽", - "👶🏾", - "👶🏿", - "🧒", - "🧒🏻", - "🧒🏻", - "🧒🏼", - "🧒🏼", - "🧒🏽", - "🧒🏽", - "🧒🏾", - "🧒🏾", - "🧒🏿", - "🧒🏿", - "👧", - "👧🏻", - "👧🏼", - "👧🏽", - "👧🏾", - "👧🏿", - "👦", - "👦🏻", - "👦🏼", - "👦🏽", - "👦🏾", - "👦🏿", - "🧑", - "🧑", - "🧑🏻", - "🧑🏻", - "🧑🏼", - "🧑🏼", - "🧑🏽", - "🧑🏽", - "🧑🏾", - "🧑🏾", - "🧑🏿", - "🧑🏿", - "👩", - "👩🏻", - "👩🏼", - "👩🏽", - "👩🏾", - "👩🏿", - "👨", - "👨🏻", - "👨🏼", - "👨🏽", - "👨🏾", - "👨🏿", - "🧑‍🦱", - "🧑🏻‍🦱", - "🧑🏻‍🦱", - "🧑🏼‍🦱", - "🧑🏼‍🦱", - "🧑🏽‍🦱", - "🧑🏽‍🦱", - "🧑🏾‍🦱", - "🧑🏾‍🦱", - "🧑🏿‍🦱", - "🧑🏿‍🦱", - "👩‍🦱", - "👩🏻‍🦱", - "👩🏻‍🦱", - "👩🏼‍🦱", - "👩🏼‍🦱", - "👩🏽‍🦱", - "👩🏽‍🦱", - "👩🏾‍🦱", - "👩🏾‍🦱", - "👩🏿‍🦱", - "👩🏿‍🦱", - "👨‍🦱", - "👨🏻‍🦱", - "👨🏻‍🦱", - "👨🏼‍🦱", - "👨🏼‍🦱", - "👨🏽‍🦱", - "👨🏽‍🦱", - "👨🏾‍🦱", - "👨🏾‍🦱", - "👨🏿‍🦱", - "👨🏿‍🦱", - "🧑‍🦰", - "🧑🏻‍🦰", - "🧑🏻‍🦰", - "🧑🏼‍🦰", - "🧑🏼‍🦰", - "🧑🏽‍🦰", - "🧑🏽‍🦰", - "🧑🏾‍🦰", - "🧑🏾‍🦰", - "🧑🏿‍🦰", - "🧑🏿‍🦰", - "👩‍🦰", - "👩🏻‍🦰", - "👩🏻‍🦰", - "👩🏼‍🦰", - "👩🏼‍🦰", - "👩🏽‍🦰", - "👩🏽‍🦰", - "👩🏾‍🦰", - "👩🏾‍🦰", - "👩🏿‍🦰", - "👩🏿‍🦰", - "👨‍🦰", - "👨‍🦰", - "👨🏻‍🦰", - "👨🏻‍🦰", - "👨🏼‍🦰", - "👨🏼‍🦰", - "👨🏽‍🦰", - "👨🏽‍🦰", - "👨🏾‍🦰", - "👨🏾‍🦰", - "👨🏿‍🦰", - "👨🏿‍🦰", - "👱", - "👱", - "👱🏻", - "👱🏻", - "👱🏼", - "👱🏼", - "👱🏽", - "👱🏽", - "👱🏾", - "👱🏾", - "👱🏿", - "👱🏿", - "👱‍♀️", - "👱🏻‍♀️", - "👱🏻‍♀️", - "👱🏼‍♀️", - "👱🏼‍♀️", - "👱🏽‍♀️", - "👱🏽‍♀️", - "👱🏾‍♀️", - "👱🏾‍♀️", - "👱🏿‍♀️", - "👱🏿‍♀️", - "👱‍♂️", - "👱🏻‍♂️", - "👱🏻‍♂️", - "👱🏼‍♂️", - "👱🏼‍♂️", - "👱🏽‍♂️", - "👱🏽‍♂️", - "👱🏾‍♂️", - "👱🏾‍♂️", - "👱🏿‍♂️", - "👱🏿‍♂️", - "🧑‍🦳", - "🧑🏻‍🦳", - "🧑🏻‍🦳", - "🧑🏼‍🦳", - "🧑🏼‍🦳", - "🧑🏽‍🦳", - "🧑🏽‍🦳", - "🧑🏾‍🦳", - "🧑🏾‍🦳", - "🧑🏿‍🦳", - "🧑🏿‍🦳", - "👩‍🦳", - "👩🏻‍🦳", - "👩🏻‍🦳", - "👩🏼‍🦳", - "👩🏼‍🦳", - "👩🏽‍🦳", - "👩🏽‍🦳", - "👩🏾‍🦳", - "👩🏾‍🦳", - "👩🏿‍🦳", - "👩🏿‍🦳", - "👨‍🦳", - "👨🏻‍🦳", - "👨🏻‍🦳", - "👨🏼‍🦳", - "👨🏼‍🦳", - "👨🏽‍🦳", - "👨🏽‍🦳", - "👨🏾‍🦳", - "👨🏾‍🦳", - "👨🏿‍🦳", - "👨🏿‍🦳", - "🧑‍🦲", - "🧑🏻‍🦲", - "🧑🏻‍🦲", - "🧑🏼‍🦲", - "🧑🏼‍🦲", - "🧑🏽‍🦲", - "🧑🏽‍🦲", - "🧑🏾‍🦲", - "🧑🏾‍🦲", - "🧑🏿‍🦲", - "🧑🏿‍🦲", - "👩‍🦲", - "👩🏻‍🦲", - "👩🏻‍🦲", - "👩🏼‍🦲", - "👩🏼‍🦲", - "👩🏽‍🦲", - "👩🏽‍🦲", - "👩🏾‍🦲", - "👩🏾‍🦲", - "👩🏿‍🦲", - "👩🏿‍🦲", - "👨‍🦲", - "👨🏻‍🦲", - "👨🏻‍🦲", - "👨🏼‍🦲", - "👨🏼‍🦲", - "👨🏽‍🦲", - "👨🏽‍🦲", - "👨🏾‍🦲", - "👨🏾‍🦲", - "👨🏿‍🦲", - "👨🏿‍🦲", - "🧔", - "🧔", - "🧔🏻", - "🧔🏻", - "🧔🏼", - "🧔🏼", - "🧔🏽", - "🧔🏽", - "🧔🏾", - "🧔🏾", - "🧔🏿", - "🧔🏿", - "🧔‍♀️", - "🧔🏻‍♀️", - "🧔🏻‍♀️", - "🧔🏼‍♀️", - "🧔🏼‍♀️", - "🧔🏽‍♀️", - "🧔🏽‍♀️", - "🧔🏾‍♀️", - "🧔🏾‍♀️", - "🧔🏿‍♀️", - "🧔🏿‍♀️", - "🧔‍♂️", - "🧔🏻‍♂️", - "🧔🏻‍♂️", - "🧔🏼‍♂️", - "🧔🏼‍♂️", - "🧔🏽‍♂️", - "🧔🏽‍♂️", - "🧔🏾‍♂️", - "🧔🏾‍♂️", - "🧔🏿‍♂️", - "🧔🏿‍♂️", - "🧓", - "🧓", - "🧓🏻", - "🧓🏻", - "🧓🏼", - "🧓🏼", - "🧓🏽", - "🧓🏽", - "🧓🏾", - "🧓🏾", - "🧓🏿", - "🧓🏿", - "👵", - "👵", - "👵", - "👵🏻", - "👵🏻", - "👵🏼", - "👵🏼", - "👵🏽", - "👵🏽", - "👵🏾", - "👵🏾", - "👵🏿", - "👵🏿", - "👴", - "👴", - "👴🏻", - "👴🏼", - "👴🏽", - "👴🏾", - "👴🏿", - "👲", - "👲", - "👲🏻", - "👲🏻", - "👲🏼", - "👲🏼", - "👲🏽", - "👲🏽", - "👲🏾", - "👲🏾", - "👲🏿", - "👲🏿", - "👳", - "👳", - "👳🏻", - "👳🏻", - "👳🏼", - "👳🏼", - "👳🏽", - "👳🏽", - "👳🏾", - "👳🏾", - "👳🏿", - "👳🏿", - "👳‍♀️", - "👳🏻‍♀️", - "👳🏻‍♀️", - "👳🏼‍♀️", - "👳🏼‍♀️", - "👳🏽‍♀️", - "👳🏽‍♀️", - "👳🏾‍♀️", - "👳🏾‍♀️", - "👳🏿‍♀️", - "👳🏿‍♀️", - "👳‍♂️", - "👳🏻‍♂️", - "👳🏻‍♂️", - "👳🏼‍♂️", - "👳🏼‍♂️", - "👳🏽‍♂️", - "👳🏽‍♂️", - "👳🏾‍♂️", - "👳🏾‍♂️", - "👳🏿‍♂️", - "👳🏿‍♂️", - "🧕", - "🧕🏻", - "🧕🏻", - "🧕🏼", - "🧕🏼", - "🧕🏽", - "🧕🏽", - "🧕🏾", - "🧕🏾", - "🧕🏿", - "🧕🏿", - "👮", - "👮", - "👮🏻", - "👮🏻", - "👮🏼", - "👮🏼", - "👮🏽", - "👮🏽", - "👮🏾", - "👮🏾", - "👮🏿", - "👮🏿", - "👮‍♀️", - "👮🏻‍♀️", - "👮🏻‍♀️", - "👮🏼‍♀️", - "👮🏼‍♀️", - "👮🏽‍♀️", - "👮🏽‍♀️", - "👮🏾‍♀️", - "👮🏾‍♀️", - "👮🏿‍♀️", - "👮🏿‍♀️", - "👮‍♂️", - "👮🏻‍♂️", - "👮🏻‍♂️", - "👮🏼‍♂️", - "👮🏼‍♂️", - "👮🏽‍♂️", - "👮🏽‍♂️", - "👮🏾‍♂️", - "👮🏾‍♂️", - "👮🏿‍♂️", - "👮🏿‍♂️", - "👷", - "👷🏻", - "👷🏼", - "👷🏽", - "👷🏾", - "👷🏿", - "👷‍♀️", - "👷🏻‍♀️", - "👷🏻‍♀️", - "👷🏼‍♀️", - "👷🏼‍♀️", - "👷🏽‍♀️", - "👷🏽‍♀️", - "👷🏾‍♀️", - "👷🏾‍♀️", - "👷🏿‍♀️", - "👷🏿‍♀️", - "👷‍♂️", - "👷🏻‍♂️", - "👷🏻‍♂️", - "👷🏼‍♂️", - "👷🏼‍♂️", - "👷🏽‍♂️", - "👷🏽‍♂️", - "👷🏾‍♂️", - "👷🏾‍♂️", - "👷🏿‍♂️", - "👷🏿‍♂️", - "💂", - "💂", - "💂🏻", - "💂🏻", - "💂🏼", - "💂🏼", - "💂🏽", - "💂🏽", - "💂🏾", - "💂🏾", - "💂🏿", - "💂🏿", - "💂‍♀️", - "💂🏻‍♀️", - "💂🏻‍♀️", - "💂🏼‍♀️", - "💂🏼‍♀️", - "💂🏽‍♀️", - "💂🏽‍♀️", - "💂🏾‍♀️", - "💂🏾‍♀️", - "💂🏿‍♀️", - "💂🏿‍♀️", - "💂‍♂️", - "💂🏻‍♂️", - "💂🏻‍♂️", - "💂🏼‍♂️", - "💂🏼‍♂️", - "💂🏽‍♂️", - "💂🏽‍♂️", - "💂🏾‍♂️", - "💂🏾‍♂️", - "💂🏿‍♂️", - "💂🏿‍♂️", - "🕵️", - "🕵️", - "🕵️", - "🕵🏻", - "🕵🏻", - "🕵🏻", - "🕵🏼", - "🕵🏼", - "🕵🏼", - "🕵🏽", - "🕵🏽", - "🕵🏽", - "🕵🏾", - "🕵🏾", - "🕵🏾", - "🕵🏿", - "🕵🏿", - "🕵🏿", - "🕵️‍♀️", - "🕵🏻‍♀️", - "🕵🏻‍♀️", - "🕵🏼‍♀️", - "🕵🏼‍♀️", - "🕵🏽‍♀️", - "🕵🏽‍♀️", - "🕵🏾‍♀️", - "🕵🏾‍♀️", - "🕵🏿‍♀️", - "🕵🏿‍♀️", - "🕵️‍♂️", - "🕵🏻‍♂️", - "🕵🏻‍♂️", - "🕵🏼‍♂️", - "🕵🏼‍♂️", - "🕵🏽‍♂️", - "🕵🏽‍♂️", - "🕵🏾‍♂️", - "🕵🏾‍♂️", - "🕵🏿‍♂️", - "🕵🏿‍♂️", - "🧑‍⚕️", - "🧑🏻‍⚕️", - "🧑🏻‍⚕️", - "🧑🏼‍⚕️", - "🧑🏼‍⚕️", - "🧑🏽‍⚕️", - "🧑🏽‍⚕️", - "🧑🏾‍⚕️", - "🧑🏾‍⚕️", - "🧑🏿‍⚕️", - "🧑🏿‍⚕️", - "👩‍⚕️", - "👩🏻‍⚕️", - "👩🏻‍⚕️", - "👩🏼‍⚕️", - "👩🏼‍⚕️", - "👩🏽‍⚕️", - "👩🏽‍⚕️", - "👩🏾‍⚕️", - "👩🏾‍⚕️", - "👩🏿‍⚕️", - "👩🏿‍⚕️", - "👨‍⚕️", - "👨🏻‍⚕️", - "👨🏻‍⚕️", - "👨🏼‍⚕️", - "👨🏼‍⚕️", - "👨🏽‍⚕️", - "👨🏽‍⚕️", - "👨🏾‍⚕️", - "👨🏾‍⚕️", - "👨🏿‍⚕️", - "👨🏿‍⚕️", - "🧑‍🌾", - "🧑🏻‍🌾", - "🧑🏻‍🌾", - "🧑🏼‍🌾", - "🧑🏼‍🌾", - "🧑🏽‍🌾", - "🧑🏽‍🌾", - "🧑🏾‍🌾", - "🧑🏾‍🌾", - "🧑🏿‍🌾", - "🧑🏿‍🌾", - "👩‍🌾", - "👩🏻‍🌾", - "👩🏻‍🌾", - "👩🏼‍🌾", - "👩🏼‍🌾", - "👩🏽‍🌾", - "👩🏽‍🌾", - "👩🏾‍🌾", - "👩🏾‍🌾", - "👩🏿‍🌾", - "👩🏿‍🌾", - "👨‍🌾", - "👨🏻‍🌾", - "👨🏻‍🌾", - "👨🏼‍🌾", - "👨🏼‍🌾", - "👨🏽‍🌾", - "👨🏽‍🌾", - "👨🏾‍🌾", - "👨🏾‍🌾", - "👨🏿‍🌾", - "👨🏿‍🌾", - "🧑‍🍳", - "🧑🏻‍🍳", - "🧑🏻‍🍳", - "🧑🏼‍🍳", - "🧑🏼‍🍳", - "🧑🏽‍🍳", - "🧑🏽‍🍳", - "🧑🏾‍🍳", - "🧑🏾‍🍳", - "🧑🏿‍🍳", - "🧑🏿‍🍳", - "👩‍🍳", - "👩🏻‍🍳", - "👩🏻‍🍳", - "👩🏼‍🍳", - "👩🏼‍🍳", - "👩🏽‍🍳", - "👩🏽‍🍳", - "👩🏾‍🍳", - "👩🏾‍🍳", - "👩🏿‍🍳", - "👩🏿‍🍳", - "👨‍🍳", - "👨🏻‍🍳", - "👨🏻‍🍳", - "👨🏼‍🍳", - "👨🏼‍🍳", - "👨🏽‍🍳", - "👨🏽‍🍳", - "👨🏾‍🍳", - "👨🏾‍🍳", - "👨🏿‍🍳", - "👨🏿‍🍳", - "🧑‍🎓", - "🧑🏻‍🎓", - "🧑🏻‍🎓", - "🧑🏼‍🎓", - "🧑🏼‍🎓", - "🧑🏽‍🎓", - "🧑🏽‍🎓", - "🧑🏾‍🎓", - "🧑🏾‍🎓", - "🧑🏿‍🎓", - "🧑🏿‍🎓", - "👩‍🎓", - "👩🏻‍🎓", - "👩🏻‍🎓", - "👩🏼‍🎓", - "👩🏼‍🎓", - "👩🏽‍🎓", - "👩🏽‍🎓", - "👩🏾‍🎓", - "👩🏾‍🎓", - "👩🏿‍🎓", - "👩🏿‍🎓", - "👨‍🎓", - "👨🏻‍🎓", - "👨🏻‍🎓", - "👨🏼‍🎓", - "👨🏼‍🎓", - "👨🏽‍🎓", - "👨🏽‍🎓", - "👨🏾‍🎓", - "👨🏾‍🎓", - "👨🏿‍🎓", - "👨🏿‍🎓", - "🧑‍🎤", - "🧑🏻‍🎤", - "🧑🏻‍🎤", - "🧑🏼‍🎤", - "🧑🏼‍🎤", - "🧑🏽‍🎤", - "🧑🏽‍🎤", - "🧑🏾‍🎤", - "🧑🏾‍🎤", - "🧑🏿‍🎤", - "🧑🏿‍🎤", - "👩‍🎤", - "👩🏻‍🎤", - "👩🏻‍🎤", - "👩🏼‍🎤", - "👩🏼‍🎤", - "👩🏽‍🎤", - "👩🏽‍🎤", - "👩🏾‍🎤", - "👩🏾‍🎤", - "👩🏿‍🎤", - "👩🏿‍🎤", - "👨‍🎤", - "👨🏻‍🎤", - "👨🏻‍🎤", - "👨🏼‍🎤", - "👨🏼‍🎤", - "👨🏽‍🎤", - "👨🏽‍🎤", - "👨🏾‍🎤", - "👨🏾‍🎤", - "👨🏿‍🎤", - "👨🏿‍🎤", - "🧑‍🏫", - "🧑🏻‍🏫", - "🧑🏻‍🏫", - "🧑🏼‍🏫", - "🧑🏼‍🏫", - "🧑🏽‍🏫", - "🧑🏽‍🏫", - "🧑🏾‍🏫", - "🧑🏾‍🏫", - "🧑🏿‍🏫", - "🧑🏿‍🏫", - "👩‍🏫", - "👩🏻‍🏫", - "👩🏻‍🏫", - "👩🏼‍🏫", - "👩🏼‍🏫", - "👩🏽‍🏫", - "👩🏽‍🏫", - "👩🏾‍🏫", - "👩🏾‍🏫", - "👩🏿‍🏫", - "👩🏿‍🏫", - "👨‍🏫", - "👨🏻‍🏫", - "👨🏻‍🏫", - "👨🏼‍🏫", - "👨🏼‍🏫", - "👨🏽‍🏫", - "👨🏽‍🏫", - "👨🏾‍🏫", - "👨🏾‍🏫", - "👨🏿‍🏫", - "👨🏿‍🏫", - "🧑‍🏭", - "🧑🏻‍🏭", - "🧑🏻‍🏭", - "🧑🏼‍🏭", - "🧑🏼‍🏭", - "🧑🏽‍🏭", - "🧑🏽‍🏭", - "🧑🏾‍🏭", - "🧑🏾‍🏭", - "🧑🏿‍🏭", - "🧑🏿‍🏭", - "👩‍🏭", - "👩🏻‍🏭", - "👩🏻‍🏭", - "👩🏼‍🏭", - "👩🏼‍🏭", - "👩🏽‍🏭", - "👩🏽‍🏭", - "👩🏾‍🏭", - "👩🏾‍🏭", - "👩🏿‍🏭", - "👩🏿‍🏭", - "👨‍🏭", - "👨🏻‍🏭", - "👨🏻‍🏭", - "👨🏼‍🏭", - "👨🏼‍🏭", - "👨🏽‍🏭", - "👨🏽‍🏭", - "👨🏾‍🏭", - "👨🏾‍🏭", - "👨🏿‍🏭", - "👨🏿‍🏭", - "🧑‍💻", - "🧑🏻‍💻", - "🧑🏻‍💻", - "🧑🏼‍💻", - "🧑🏼‍💻", - "🧑🏽‍💻", - "🧑🏽‍💻", - "🧑🏾‍💻", - "🧑🏾‍💻", - "🧑🏿‍💻", - "🧑🏿‍💻", - "👩‍💻", - "👩🏻‍💻", - "👩🏻‍💻", - "👩🏼‍💻", - "👩🏼‍💻", - "👩🏽‍💻", - "👩🏽‍💻", - "👩🏾‍💻", - "👩🏾‍💻", - "👩🏿‍💻", - "👩🏿‍💻", - "👨‍💻", - "👨🏻‍💻", - "👨🏻‍💻", - "👨🏼‍💻", - "👨🏼‍💻", - "👨🏽‍💻", - "👨🏽‍💻", - "👨🏾‍💻", - "👨🏾‍💻", - "👨🏿‍💻", - "👨🏿‍💻", - "🧑‍💼", - "🧑🏻‍💼", - "🧑🏻‍💼", - "🧑🏼‍💼", - "🧑🏼‍💼", - "🧑🏽‍💼", - "🧑🏽‍💼", - "🧑🏾‍💼", - "🧑🏾‍💼", - "🧑🏿‍💼", - "🧑🏿‍💼", - "👩‍💼", - "👩🏻‍💼", - "👩🏻‍💼", - "👩🏼‍💼", - "👩🏼‍💼", - "👩🏽‍💼", - "👩🏽‍💼", - "👩🏾‍💼", - "👩🏾‍💼", - "👩🏿‍💼", - "👩🏿‍💼", - "👨‍💼", - "👨🏻‍💼", - "👨🏻‍💼", - "👨🏼‍💼", - "👨🏼‍💼", - "👨🏽‍💼", - "👨🏽‍💼", - "👨🏾‍💼", - "👨🏾‍💼", - "👨🏿‍💼", - "👨🏿‍💼", - "🧑‍🔧", - "🧑🏻‍🔧", - "🧑🏻‍🔧", - "🧑🏼‍🔧", - "🧑🏼‍🔧", - "🧑🏽‍🔧", - "🧑🏽‍🔧", - "🧑🏾‍🔧", - "🧑🏾‍🔧", - "🧑🏿‍🔧", - "🧑🏿‍🔧", - "👩‍🔧", - "👩🏻‍🔧", - "👩🏻‍🔧", - "👩🏼‍🔧", - "👩🏼‍🔧", - "👩🏽‍🔧", - "👩🏽‍🔧", - "👩🏾‍🔧", - "👩🏾‍🔧", - "👩🏿‍🔧", - "👩🏿‍🔧", - "👨‍🔧", - "👨🏻‍🔧", - "👨🏻‍🔧", - "👨🏼‍🔧", - "👨🏼‍🔧", - "👨🏽‍🔧", - "👨🏽‍🔧", - "👨🏾‍🔧", - "👨🏾‍🔧", - "👨🏿‍🔧", - "👨🏿‍🔧", - "🧑‍🔬", - "🧑🏻‍🔬", - "🧑🏻‍🔬", - "🧑🏼‍🔬", - "🧑🏼‍🔬", - "🧑🏽‍🔬", - "🧑🏽‍🔬", - "🧑🏾‍🔬", - "🧑🏾‍🔬", - "🧑🏿‍🔬", - "🧑🏿‍🔬", - "👩‍🔬", - "👩🏻‍🔬", - "👩🏻‍🔬", - "👩🏼‍🔬", - "👩🏼‍🔬", - "👩🏽‍🔬", - "👩🏽‍🔬", - "👩🏾‍🔬", - "👩🏾‍🔬", - "👩🏿‍🔬", - "👩🏿‍🔬", - "👨‍🔬", - "👨🏻‍🔬", - "👨🏻‍🔬", - "👨🏼‍🔬", - "👨🏼‍🔬", - "👨🏽‍🔬", - "👨🏽‍🔬", - "👨🏾‍🔬", - "👨🏾‍🔬", - "👨🏿‍🔬", - "👨🏿‍🔬", - "🧑‍🎨", - "🧑🏻‍🎨", - "🧑🏻‍🎨", - "🧑🏼‍🎨", - "🧑🏼‍🎨", - "🧑🏽‍🎨", - "🧑🏽‍🎨", - "🧑🏾‍🎨", - "🧑🏾‍🎨", - "🧑🏿‍🎨", - "🧑🏿‍🎨", - "👩‍🎨", - "👩🏻‍🎨", - "👩🏻‍🎨", - "👩🏼‍🎨", - "👩🏼‍🎨", - "👩🏽‍🎨", - "👩🏽‍🎨", - "👩🏾‍🎨", - "👩🏾‍🎨", - "👩🏿‍🎨", - "👩🏿‍🎨", - "👨‍🎨", - "👨🏻‍🎨", - "👨🏻‍🎨", - "👨🏼‍🎨", - "👨🏼‍🎨", - "👨🏽‍🎨", - "👨🏽‍🎨", - "👨🏾‍🎨", - "👨🏾‍🎨", - "👨🏿‍🎨", - "👨🏿‍🎨", - "🧑‍🚒", - "🧑🏻‍🚒", - "🧑🏻‍🚒", - "🧑🏼‍🚒", - "🧑🏼‍🚒", - "🧑🏽‍🚒", - "🧑🏽‍🚒", - "🧑🏾‍🚒", - "🧑🏾‍🚒", - "🧑🏿‍🚒", - "🧑🏿‍🚒", - "👩‍🚒", - "👩🏻‍🚒", - "👩🏻‍🚒", - "👩🏼‍🚒", - "👩🏼‍🚒", - "👩🏽‍🚒", - "👩🏽‍🚒", - "👩🏾‍🚒", - "👩🏾‍🚒", - "👩🏿‍🚒", - "👩🏿‍🚒", - "👨‍🚒", - "👨🏻‍🚒", - "👨🏻‍🚒", - "👨🏼‍🚒", - "👨🏼‍🚒", - "👨🏽‍🚒", - "👨🏽‍🚒", - "👨🏾‍🚒", - "👨🏾‍🚒", - "👨🏿‍🚒", - "👨🏿‍🚒", - "🧑‍✈️", - "🧑🏻‍✈️", - "🧑🏻‍✈️", - "🧑🏼‍✈️", - "🧑🏼‍✈️", - "🧑🏽‍✈️", - "🧑🏽‍✈️", - "🧑🏾‍✈️", - "🧑🏾‍✈️", - "🧑🏿‍✈️", - "🧑🏿‍✈️", - "👩‍✈️", - "👩🏻‍✈️", - "👩🏻‍✈️", - "👩🏼‍✈️", - "👩🏼‍✈️", - "👩🏽‍✈️", - "👩🏽‍✈️", - "👩🏾‍✈️", - "👩🏾‍✈️", - "👩🏿‍✈️", - "👩🏿‍✈️", - "👨‍✈️", - "👨🏻‍✈️", - "👨🏻‍✈️", - "👨🏼‍✈️", - "👨🏼‍✈️", - "👨🏽‍✈️", - "👨🏽‍✈️", - "👨🏾‍✈️", - "👨🏾‍✈️", - "👨🏿‍✈️", - "👨🏿‍✈️", - "🧑‍🚀", - "🧑🏻‍🚀", - "🧑🏻‍🚀", - "🧑🏼‍🚀", - "🧑🏼‍🚀", - "🧑🏽‍🚀", - "🧑🏽‍🚀", - "🧑🏾‍🚀", - "🧑🏾‍🚀", - "🧑🏿‍🚀", - "🧑🏿‍🚀", - "👩‍🚀", - "👩🏻‍🚀", - "👩🏻‍🚀", - "👩🏼‍🚀", - "👩🏼‍🚀", - "👩🏽‍🚀", - "👩🏽‍🚀", - "👩🏾‍🚀", - "👩🏾‍🚀", - "👩🏿‍🚀", - "👩🏿‍🚀", - "👨‍🚀", - "👨🏻‍🚀", - "👨🏻‍🚀", - "👨🏼‍🚀", - "👨🏼‍🚀", - "👨🏽‍🚀", - "👨🏽‍🚀", - "👨🏾‍🚀", - "👨🏾‍🚀", - "👨🏿‍🚀", - "👨🏿‍🚀", - "🧑‍⚖️", - "🧑🏻‍⚖️", - "🧑🏻‍⚖️", - "🧑🏼‍⚖️", - "🧑🏼‍⚖️", - "🧑🏽‍⚖️", - "🧑🏽‍⚖️", - "🧑🏾‍⚖️", - "🧑🏾‍⚖️", - "🧑🏿‍⚖️", - "🧑🏿‍⚖️", - "👩‍⚖️", - "👩🏻‍⚖️", - "👩🏻‍⚖️", - "👩🏼‍⚖️", - "👩🏼‍⚖️", - "👩🏽‍⚖️", - "👩🏽‍⚖️", - "👩🏾‍⚖️", - "👩🏾‍⚖️", - "👩🏿‍⚖️", - "👩🏿‍⚖️", - "👨‍⚖️", - "👨🏻‍⚖️", - "👨🏻‍⚖️", - "👨🏼‍⚖️", - "👨🏼‍⚖️", - "👨🏽‍⚖️", - "👨🏽‍⚖️", - "👨🏾‍⚖️", - "👨🏾‍⚖️", - "👨🏿‍⚖️", - "👨🏿‍⚖️", - "👰", - "👰🏻", - "👰🏼", - "👰🏽", - "👰🏾", - "👰🏿", - "👰‍♀️", - "👰‍♀️", - "👰🏻‍♀️", - "👰🏻‍♀️", - "👰🏼‍♀️", - "👰🏼‍♀️", - "👰🏽‍♀️", - "👰🏽‍♀️", - "👰🏾‍♀️", - "👰🏾‍♀️", - "👰🏿‍♀️", - "👰🏿‍♀️", - "👰‍♂️", - "👰🏻‍♂️", - "👰🏻‍♂️", - "👰🏼‍♂️", - "👰🏼‍♂️", - "👰🏽‍♂️", - "👰🏽‍♂️", - "👰🏾‍♂️", - "👰🏾‍♂️", - "👰🏿‍♂️", - "👰🏿‍♂️", - "🤵", - "🤵🏻", - "🤵🏻", - "🤵🏼", - "🤵🏼", - "🤵🏽", - "🤵🏽", - "🤵🏾", - "🤵🏾", - "🤵🏿", - "🤵🏿", - "🤵‍♀️", - "🤵🏻‍♀️", - "🤵🏻‍♀️", - "🤵🏼‍♀️", - "🤵🏼‍♀️", - "🤵🏽‍♀️", - "🤵🏽‍♀️", - "🤵🏾‍♀️", - "🤵🏾‍♀️", - "🤵🏿‍♀️", - "🤵🏿‍♀️", - "🤵‍♂️", - "🤵🏻‍♂️", - "🤵🏻‍♂️", - "🤵🏼‍♂️", - "🤵🏼‍♂️", - "🤵🏽‍♂️", - "🤵🏽‍♂️", - "🤵🏾‍♂️", - "🤵🏾‍♂️", - "🤵🏿‍♂️", - "🤵🏿‍♂️", - "🫅", - "🫅🏻", - "🫅🏻", - "🫅🏼", - "🫅🏼", - "🫅🏽", - "🫅🏽", - "🫅🏾", - "🫅🏾", - "🫅🏿", - "🫅🏿", - "👸", - "👸🏻", - "👸🏼", - "👸🏽", - "👸🏾", - "👸🏿", - "🤴", - "🤴🏻", - "🤴🏼", - "🤴🏽", - "🤴🏾", - "🤴🏿", - "🦸", - "🦸🏻", - "🦸🏻", - "🦸🏼", - "🦸🏼", - "🦸🏽", - "🦸🏽", - "🦸🏾", - "🦸🏾", - "🦸🏿", - "🦸🏿", - "🦸‍♀️", - "🦸🏻‍♀️", - "🦸🏻‍♀️", - "🦸🏼‍♀️", - "🦸🏼‍♀️", - "🦸🏽‍♀️", - "🦸🏽‍♀️", - "🦸🏾‍♀️", - "🦸🏾‍♀️", - "🦸🏿‍♀️", - "🦸🏿‍♀️", - "🦸‍♂️", - "🦸🏻‍♂️", - "🦸🏻‍♂️", - "🦸🏼‍♂️", - "🦸🏼‍♂️", - "🦸🏽‍♂️", - "🦸🏽‍♂️", - "🦸🏾‍♂️", - "🦸🏾‍♂️", - "🦸🏿‍♂️", - "🦸🏿‍♂️", - "🦹", - "🦹🏻", - "🦹🏻", - "🦹🏼", - "🦹🏼", - "🦹🏽", - "🦹🏽", - "🦹🏾", - "🦹🏾", - "🦹🏿", - "🦹🏿", - "🦹‍♀️", - "🦹🏻‍♀️", - "🦹🏻‍♀️", - "🦹🏼‍♀️", - "🦹🏼‍♀️", - "🦹🏽‍♀️", - "🦹🏽‍♀️", - "🦹🏾‍♀️", - "🦹🏾‍♀️", - "🦹🏿‍♀️", - "🦹🏿‍♀️", - "🦹‍♂️", - "🦹🏻‍♂️", - "🦹🏻‍♂️", - "🦹🏼‍♂️", - "🦹🏼‍♂️", - "🦹🏽‍♂️", - "🦹🏽‍♂️", - "🦹🏾‍♂️", - "🦹🏾‍♂️", - "🦹🏿‍♂️", - "🦹🏿‍♂️", - "🥷", - "🥷🏻", - "🥷🏻", - "🥷🏼", - "🥷🏼", - "🥷🏽", - "🥷🏽", - "🥷🏾", - "🥷🏾", - "🥷🏿", - "🥷🏿", - "🧑‍🎄", - "🧑🏻‍🎄", - "🧑🏻‍🎄", - "🧑🏼‍🎄", - "🧑🏼‍🎄", - "🧑🏽‍🎄", - "🧑🏽‍🎄", - "🧑🏾‍🎄", - "🧑🏾‍🎄", - "🧑🏿‍🎄", - "🧑🏿‍🎄", - "🤶", - "🤶", - "🤶🏻", - "🤶🏻", - "🤶🏼", - "🤶🏼", - "🤶🏽", - "🤶🏽", - "🤶🏾", - "🤶🏾", - "🤶🏿", - "🤶🏿", - "🎅", - "🎅", - "🎅🏻", - "🎅🏼", - "🎅🏽", - "🎅🏾", - "🎅🏿", - "🧙", - "🧙🏻", - "🧙🏻", - "🧙🏼", - "🧙🏼", - "🧙🏽", - "🧙🏽", - "🧙🏾", - "🧙🏾", - "🧙🏿", - "🧙🏿", - "🧙‍♀️", - "🧙🏻‍♀️", - "🧙🏻‍♀️", - "🧙🏼‍♀️", - "🧙🏼‍♀️", - "🧙🏽‍♀️", - "🧙🏽‍♀️", - "🧙🏾‍♀️", - "🧙🏾‍♀️", - "🧙🏿‍♀️", - "🧙🏿‍♀️", - "🧙‍♂️", - "🧙🏻‍♂️", - "🧙🏻‍♂️", - "🧙🏼‍♂️", - "🧙🏼‍♂️", - "🧙🏽‍♂️", - "🧙🏽‍♂️", - "🧙🏾‍♂️", - "🧙🏾‍♂️", - "🧙🏿‍♂️", - "🧙🏿‍♂️", - "🧝", - "🧝🏻", - "🧝🏻", - "🧝🏼", - "🧝🏼", - "🧝🏽", - "🧝🏽", - "🧝🏾", - "🧝🏾", - "🧝🏿", - "🧝🏿", - "🧝‍♀️", - "🧝🏻‍♀️", - "🧝🏻‍♀️", - "🧝🏼‍♀️", - "🧝🏼‍♀️", - "🧝🏽‍♀️", - "🧝🏽‍♀️", - "🧝🏾‍♀️", - "🧝🏾‍♀️", - "🧝🏿‍♀️", - "🧝🏿‍♀️", - "🧝‍♂️", - "🧝🏻‍♂️", - "🧝🏻‍♂️", - "🧝🏼‍♂️", - "🧝🏼‍♂️", - "🧝🏽‍♂️", - "🧝🏽‍♂️", - "🧝🏾‍♂️", - "🧝🏾‍♂️", - "🧝🏿‍♂️", - "🧝🏿‍♂️", - "🧌", - "🧛", - "🧛🏻", - "🧛🏻", - "🧛🏼", - "🧛🏼", - "🧛🏽", - "🧛🏽", - "🧛🏾", - "🧛🏾", - "🧛🏿", - "🧛🏿", - "🧛‍♀️", - "🧛🏻‍♀️", - "🧛🏻‍♀️", - "🧛🏼‍♀️", - "🧛🏼‍♀️", - "🧛🏽‍♀️", - "🧛🏽‍♀️", - "🧛🏾‍♀️", - "🧛🏾‍♀️", - "🧛🏿‍♀️", - "🧛🏿‍♀️", - "🧛‍♂️", - "🧛🏻‍♂️", - "🧛🏻‍♂️", - "🧛🏼‍♂️", - "🧛🏼‍♂️", - "🧛🏽‍♂️", - "🧛🏽‍♂️", - "🧛🏾‍♂️", - "🧛🏾‍♂️", - "🧛🏿‍♂️", - "🧛🏿‍♂️", - "🧟", - "🧟‍♀️", - "🧟‍♂️", - "🧞", - "🧞‍♀️", - "🧞‍♂️", - "🧜", - "🧜🏻", - "🧜🏻", - "🧜🏼", - "🧜🏼", - "🧜🏽", - "🧜🏽", - "🧜🏾", - "🧜🏾", - "🧜🏿", - "🧜🏿", - "🧜‍♀️", - "🧜🏻‍♀️", - "🧜🏻‍♀️", - "🧜🏼‍♀️", - "🧜🏼‍♀️", - "🧜🏽‍♀️", - "🧜🏽‍♀️", - "🧜🏾‍♀️", - "🧜🏾‍♀️", - "🧜🏿‍♀️", - "🧜🏿‍♀️", - "🧜‍♂️", - "🧜🏻‍♂️", - "🧜🏻‍♂️", - "🧜🏼‍♂️", - "🧜🏼‍♂️", - "🧜🏽‍♂️", - "🧜🏽‍♂️", - "🧜🏾‍♂️", - "🧜🏾‍♂️", - "🧜🏿‍♂️", - "🧜🏿‍♂️", - "🧚", - "🧚🏻", - "🧚🏻", - "🧚🏼", - "🧚🏼", - "🧚🏽", - "🧚🏽", - "🧚🏾", - "🧚🏾", - "🧚🏿", - "🧚🏿", - "🧚‍♀️", - "🧚🏻‍♀️", - "🧚🏻‍♀️", - "🧚🏼‍♀️", - "🧚🏼‍♀️", - "🧚🏽‍♀️", - "🧚🏽‍♀️", - "🧚🏾‍♀️", - "🧚🏾‍♀️", - "🧚🏿‍♀️", - "🧚🏿‍♀️", - "🧚‍♂️", - "🧚🏻‍♂️", - "🧚🏻‍♂️", - "🧚🏼‍♂️", - "🧚🏼‍♂️", - "🧚🏽‍♂️", - "🧚🏽‍♂️", - "🧚🏾‍♂️", - "🧚🏾‍♂️", - "🧚🏿‍♂️", - "🧚🏿‍♂️", - "👼", - "👼", - "👼🏻", - "👼🏼", - "👼🏽", - "👼🏾", - "👼🏿", - "🫄", - "🫄🏻", - "🫄🏻", - "🫄🏼", - "🫄🏼", - "🫄🏽", - "🫄🏽", - "🫄🏾", - "🫄🏾", - "🫄🏿", - "🫄🏿", - "🤰", - "🤰", - "🤰🏻", - "🤰🏻", - "🤰🏼", - "🤰🏼", - "🤰🏽", - "🤰🏽", - "🤰🏾", - "🤰🏾", - "🤰🏿", - "🤰🏿", - "🫃", - "🫃🏻", - "🫃🏻", - "🫃🏼", - "🫃🏼", - "🫃🏽", - "🫃🏽", - "🫃🏾", - "🫃🏾", - "🫃🏿", - "🫃🏿", - "🤱", - "🤱🏻", - "🤱🏻", - "🤱🏼", - "🤱🏼", - "🤱🏽", - "🤱🏽", - "🤱🏾", - "🤱🏾", - "🤱🏿", - "🤱🏿", - "🧑‍🍼", - "🧑🏻‍🍼", - "🧑🏻‍🍼", - "🧑🏼‍🍼", - "🧑🏼‍🍼", - "🧑🏽‍🍼", - "🧑🏽‍🍼", - "🧑🏾‍🍼", - "🧑🏾‍🍼", - "🧑🏿‍🍼", - "🧑🏿‍🍼", - "👩‍🍼", - "👩🏻‍🍼", - "👩🏻‍🍼", - "👩🏼‍🍼", - "👩🏼‍🍼", - "👩🏽‍🍼", - "👩🏽‍🍼", - "👩🏾‍🍼", - "👩🏾‍🍼", - "👩🏿‍🍼", - "👩🏿‍🍼", - "👨‍🍼", - "👨🏻‍🍼", - "👨🏻‍🍼", - "👨🏼‍🍼", - "👨🏼‍🍼", - "👨🏽‍🍼", - "👨🏽‍🍼", - "👨🏾‍🍼", - "👨🏾‍🍼", - "👨🏿‍🍼", - "👨🏿‍🍼", - "🙇", - "🙇", - "🙇🏻", - "🙇🏻", - "🙇🏼", - "🙇🏼", - "🙇🏽", - "🙇🏽", - "🙇🏾", - "🙇🏾", - "🙇🏿", - "🙇🏿", - "🙇‍♀️", - "🙇🏻‍♀️", - "🙇🏻‍♀️", - "🙇🏼‍♀️", - "🙇🏼‍♀️", - "🙇🏽‍♀️", - "🙇🏽‍♀️", - "🙇🏾‍♀️", - "🙇🏾‍♀️", - "🙇🏿‍♀️", - "🙇🏿‍♀️", - "🙇‍♂️", - "🙇🏻‍♂️", - "🙇🏻‍♂️", - "🙇🏼‍♂️", - "🙇🏼‍♂️", - "🙇🏽‍♂️", - "🙇🏽‍♂️", - "🙇🏾‍♂️", - "🙇🏾‍♂️", - "🙇🏿‍♂️", - "🙇🏿‍♂️", - "💁", - "💁", - "💁🏻", - "💁🏻", - "💁🏼", - "💁🏼", - "💁🏽", - "💁🏽", - "💁🏾", - "💁🏾", - "💁🏿", - "💁🏿", - "💁‍♀️", - "💁🏻‍♀️", - "💁🏻‍♀️", - "💁🏼‍♀️", - "💁🏼‍♀️", - "💁🏽‍♀️", - "💁🏽‍♀️", - "💁🏾‍♀️", - "💁🏾‍♀️", - "💁🏿‍♀️", - "💁🏿‍♀️", - "💁‍♂️", - "💁🏻‍♂️", - "💁🏻‍♂️", - "💁🏼‍♂️", - "💁🏼‍♂️", - "💁🏽‍♂️", - "💁🏽‍♂️", - "💁🏾‍♂️", - "💁🏾‍♂️", - "💁🏿‍♂️", - "💁🏿‍♂️", - "🙅", - "🙅", - "🙅🏻", - "🙅🏻", - "🙅🏼", - "🙅🏼", - "🙅🏽", - "🙅🏽", - "🙅🏾", - "🙅🏾", - "🙅🏿", - "🙅🏿", - "🙅‍♀️", - "🙅🏻‍♀️", - "🙅🏻‍♀️", - "🙅🏼‍♀️", - "🙅🏼‍♀️", - "🙅🏽‍♀️", - "🙅🏽‍♀️", - "🙅🏾‍♀️", - "🙅🏾‍♀️", - "🙅🏿‍♀️", - "🙅🏿‍♀️", - "🙅‍♂️", - "🙅🏻‍♂️", - "🙅🏻‍♂️", - "🙅🏼‍♂️", - "🙅🏼‍♂️", - "🙅🏽‍♂️", - "🙅🏽‍♂️", - "🙅🏾‍♂️", - "🙅🏾‍♂️", - "🙅🏿‍♂️", - "🙅🏿‍♂️", - "🙆", - "🙆🏻", - "🙆🏼", - "🙆🏽", - "🙆🏾", - "🙆🏿", - "🙆‍♀️", - "🙆🏻‍♀️", - "🙆🏻‍♀️", - "🙆🏼‍♀️", - "🙆🏼‍♀️", - "🙆🏽‍♀️", - "🙆🏽‍♀️", - "🙆🏾‍♀️", - "🙆🏾‍♀️", - "🙆🏿‍♀️", - "🙆🏿‍♀️", - "🙆‍♂️", - "🙆🏻‍♂️", - "🙆🏻‍♂️", - "🙆🏼‍♂️", - "🙆🏼‍♂️", - "🙆🏽‍♂️", - "🙆🏽‍♂️", - "🙆🏾‍♂️", - "🙆🏾‍♂️", - "🙆🏿‍♂️", - "🙆🏿‍♂️", - "🙋", - "🙋", - "🙋🏻", - "🙋🏻", - "🙋🏼", - "🙋🏼", - "🙋🏽", - "🙋🏽", - "🙋🏾", - "🙋🏾", - "🙋🏿", - "🙋🏿", - "🙋‍♀️", - "🙋🏻‍♀️", - "🙋🏻‍♀️", - "🙋🏼‍♀️", - "🙋🏼‍♀️", - "🙋🏽‍♀️", - "🙋🏽‍♀️", - "🙋🏾‍♀️", - "🙋🏾‍♀️", - "🙋🏿‍♀️", - "🙋🏿‍♀️", - "🙋‍♂️", - "🙋🏻‍♂️", - "🙋🏻‍♂️", - "🙋🏼‍♂️", - "🙋🏼‍♂️", - "🙋🏽‍♂️", - "🙋🏽‍♂️", - "🙋🏾‍♂️", - "🙋🏾‍♂️", - "🙋🏿‍♂️", - "🙋🏿‍♂️", - "🧏", - "🧏🏻", - "🧏🏻", - "🧏🏼", - "🧏🏼", - "🧏🏽", - "🧏🏽", - "🧏🏾", - "🧏🏾", - "🧏🏿", - "🧏🏿", - "🧏‍♀️", - "🧏🏻‍♀️", - "🧏🏻‍♀️", - "🧏🏼‍♀️", - "🧏🏼‍♀️", - "🧏🏽‍♀️", - "🧏🏽‍♀️", - "🧏🏾‍♀️", - "🧏🏾‍♀️", - "🧏🏿‍♀️", - "🧏🏿‍♀️", - "🧏‍♂️", - "🧏🏻‍♂️", - "🧏🏻‍♂️", - "🧏🏼‍♂️", - "🧏🏼‍♂️", - "🧏🏽‍♂️", - "🧏🏽‍♂️", - "🧏🏾‍♂️", - "🧏🏾‍♂️", - "🧏🏿‍♂️", - "🧏🏿‍♂️", - "🤦", - "🤦", - "🤦", - "🤦🏻", - "🤦🏻", - "🤦🏻", - "🤦🏼", - "🤦🏼", - "🤦🏼", - "🤦🏽", - "🤦🏽", - "🤦🏽", - "🤦🏾", - "🤦🏾", - "🤦🏾", - "🤦🏿", - "🤦🏿", - "🤦🏿", - "🤦‍♀️", - "🤦🏻‍♀️", - "🤦🏻‍♀️", - "🤦🏼‍♀️", - "🤦🏼‍♀️", - "🤦🏽‍♀️", - "🤦🏽‍♀️", - "🤦🏾‍♀️", - "🤦🏾‍♀️", - "🤦🏿‍♀️", - "🤦🏿‍♀️", - "🤦‍♂️", - "🤦🏻‍♂️", - "🤦🏻‍♂️", - "🤦🏼‍♂️", - "🤦🏼‍♂️", - "🤦🏽‍♂️", - "🤦🏽‍♂️", - "🤦🏾‍♂️", - "🤦🏾‍♂️", - "🤦🏿‍♂️", - "🤦🏿‍♂️", - "🤷", - "🤷", - "🤷🏻", - "🤷🏻", - "🤷🏼", - "🤷🏼", - "🤷🏽", - "🤷🏽", - "🤷🏾", - "🤷🏾", - "🤷🏿", - "🤷🏿", - "🤷‍♀️", - "🤷🏻‍♀️", - "🤷🏻‍♀️", - "🤷🏼‍♀️", - "🤷🏼‍♀️", - "🤷🏽‍♀️", - "🤷🏽‍♀️", - "🤷🏾‍♀️", - "🤷🏾‍♀️", - "🤷🏿‍♀️", - "🤷🏿‍♀️", - "🤷‍♂️", - "🤷🏻‍♂️", - "🤷🏻‍♂️", - "🤷🏼‍♂️", - "🤷🏼‍♂️", - "🤷🏽‍♂️", - "🤷🏽‍♂️", - "🤷🏾‍♂️", - "🤷🏾‍♂️", - "🤷🏿‍♂️", - "🤷🏿‍♂️", - "🙎", - "🙎", - "🙎🏻", - "🙎🏻", - "🙎🏼", - "🙎🏼", - "🙎🏽", - "🙎🏽", - "🙎🏾", - "🙎🏾", - "🙎🏿", - "🙎🏿", - "🙎‍♀️", - "🙎🏻‍♀️", - "🙎🏻‍♀️", - "🙎🏼‍♀️", - "🙎🏼‍♀️", - "🙎🏽‍♀️", - "🙎🏽‍♀️", - "🙎🏾‍♀️", - "🙎🏾‍♀️", - "🙎🏿‍♀️", - "🙎🏿‍♀️", - "🙎‍♂️", - "🙎🏻‍♂️", - "🙎🏻‍♂️", - "🙎🏼‍♂️", - "🙎🏼‍♂️", - "🙎🏽‍♂️", - "🙎🏽‍♂️", - "🙎🏾‍♂️", - "🙎🏾‍♂️", - "🙎🏿‍♂️", - "🙎🏿‍♂️", - "🙍", - "🙍🏻", - "🙍🏼", - "🙍🏽", - "🙍🏾", - "🙍🏿", - "🙍‍♀️", - "🙍🏻‍♀️", - "🙍🏻‍♀️", - "🙍🏼‍♀️", - "🙍🏼‍♀️", - "🙍🏽‍♀️", - "🙍🏽‍♀️", - "🙍🏾‍♀️", - "🙍🏾‍♀️", - "🙍🏿‍♀️", - "🙍🏿‍♀️", - "🙍‍♂️", - "🙍🏻‍♂️", - "🙍🏻‍♂️", - "🙍🏼‍♂️", - "🙍🏼‍♂️", - "🙍🏽‍♂️", - "🙍🏽‍♂️", - "🙍🏾‍♂️", - "🙍🏾‍♂️", - "🙍🏿‍♂️", - "🙍🏿‍♂️", - "💇", - "💇", - "💇🏻", - "💇🏻", - "💇🏼", - "💇🏼", - "💇🏽", - "💇🏽", - "💇🏾", - "💇🏾", - "💇🏿", - "💇🏿", - "💇‍♀️", - "💇🏻‍♀️", - "💇🏻‍♀️", - "💇🏼‍♀️", - "💇🏼‍♀️", - "💇🏽‍♀️", - "💇🏽‍♀️", - "💇🏾‍♀️", - "💇🏾‍♀️", - "💇🏿‍♀️", - "💇🏿‍♀️", - "💇‍♂️", - "💇🏻‍♂️", - "💇🏻‍♂️", - "💇🏼‍♂️", - "💇🏼‍♂️", - "💇🏽‍♂️", - "💇🏽‍♂️", - "💇🏾‍♂️", - "💇🏾‍♂️", - "💇🏿‍♂️", - "💇🏿‍♂️", - "💆", - "💆", - "💆🏻", - "💆🏻", - "💆🏼", - "💆🏼", - "💆🏽", - "💆🏽", - "💆🏾", - "💆🏾", - "💆🏿", - "💆🏿", - "💆‍♀️", - "💆🏻‍♀️", - "💆🏻‍♀️", - "💆🏼‍♀️", - "💆🏼‍♀️", - "💆🏽‍♀️", - "💆🏽‍♀️", - "💆🏾‍♀️", - "💆🏾‍♀️", - "💆🏿‍♀️", - "💆🏿‍♀️", - "💆‍♂️", - "💆🏻‍♂️", - "💆🏻‍♂️", - "💆🏼‍♂️", - "💆🏼‍♂️", - "💆🏽‍♂️", - "💆🏽‍♂️", - "💆🏾‍♂️", - "💆🏾‍♂️", - "💆🏿‍♂️", - "💆🏿‍♂️", - "🧖", - "🧖🏻", - "🧖🏻", - "🧖🏼", - "🧖🏼", - "🧖🏽", - "🧖🏽", - "🧖🏾", - "🧖🏾", - "🧖🏿", - "🧖🏿", - "🧖‍♀️", - "🧖🏻‍♀️", - "🧖🏻‍♀️", - "🧖🏼‍♀️", - "🧖🏼‍♀️", - "🧖🏽‍♀️", - "🧖🏽‍♀️", - "🧖🏾‍♀️", - "🧖🏾‍♀️", - "🧖🏿‍♀️", - "🧖🏿‍♀️", - "🧖‍♂️", - "🧖🏻‍♂️", - "🧖🏻‍♂️", - "🧖🏼‍♂️", - "🧖🏼‍♂️", - "🧖🏽‍♂️", - "🧖🏽‍♂️", - "🧖🏾‍♂️", - "🧖🏾‍♂️", - "🧖🏿‍♂️", - "🧖🏿‍♂️", - "💅", - "💅", - "💅🏻", - "💅🏼", - "💅🏽", - "💅🏾", - "💅🏿", - "🤳", - "🤳🏻", - "🤳🏼", - "🤳🏽", - "🤳🏾", - "🤳🏿", - "💃", - "💃", - "💃🏻", - "💃🏼", - "💃🏽", - "💃🏾", - "💃🏿", - "🕺", - "🕺", - "🕺🏻", - "🕺🏻", - "🕺🏼", - "🕺🏼", - "🕺🏽", - "🕺🏽", - "🕺🏿", - "🕺🏿", - "🕺🏾", - "🕺🏾", - "👯", - "👯", - "👯‍♀️", - "👯‍♂️", - "🕴️", - "🕴️", - "🕴🏻", - "🕴🏻", - "🕴🏻", - "🕴🏼", - "🕴🏼", - "🕴🏼", - "🕴🏽", - "🕴🏽", - "🕴🏽", - "🕴🏾", - "🕴🏾", - "🕴🏾", - "🕴🏿", - "🕴🏿", - "🕴🏿", - "🧑‍🦽", - "🧑🏻‍🦽", - "🧑🏻‍🦽", - "🧑🏼‍🦽", - "🧑🏼‍🦽", - "🧑🏽‍🦽", - "🧑🏽‍🦽", - "🧑🏾‍🦽", - "🧑🏾‍🦽", - "🧑🏿‍🦽", - "🧑🏿‍🦽", - "👩‍🦽", - "👩🏻‍🦽", - "👩🏻‍🦽", - "👩🏼‍🦽", - "👩🏼‍🦽", - "👩🏽‍🦽", - "👩🏽‍🦽", - "👩🏾‍🦽", - "👩🏾‍🦽", - "👩🏿‍🦽", - "👩🏿‍🦽", - "👨‍🦽", - "👨🏻‍🦽", - "👨🏻‍🦽", - "👨🏼‍🦽", - "👨🏼‍🦽", - "👨🏽‍🦽", - "👨🏽‍🦽", - "👨🏾‍🦽", - "👨🏾‍🦽", - "👨🏿‍🦽", - "👨🏿‍🦽", - "🧑‍🦼", - "🧑🏻‍🦼", - "🧑🏻‍🦼", - "🧑🏼‍🦼", - "🧑🏼‍🦼", - "🧑🏽‍🦼", - "🧑🏽‍🦼", - "🧑🏾‍🦼", - "🧑🏾‍🦼", - "🧑🏿‍🦼", - "🧑🏿‍🦼", - "👩‍🦼", - "👩🏻‍🦼", - "👩🏻‍🦼", - "👩🏼‍🦼", - "👩🏼‍🦼", - "👩🏽‍🦼", - "👩🏽‍🦼", - "👩🏾‍🦼", - "👩🏾‍🦼", - "👩🏿‍🦼", - "👩🏿‍🦼", - "👨‍🦼", - "👨🏻‍🦼", - "👨🏻‍🦼", - "👨🏼‍🦼", - "👨🏼‍🦼", - "👨🏽‍🦼", - "👨🏽‍🦼", - "👨🏾‍🦼", - "👨🏾‍🦼", - "👨🏿‍🦼", - "👨🏿‍🦼", - "🚶", - "🚶", - "🚶🏻", - "🚶🏻", - "🚶🏼", - "🚶🏼", - "🚶🏽", - "🚶🏽", - "🚶🏾", - "🚶🏾", - "🚶🏿", - "🚶🏿", - "🚶‍♀️", - "🚶🏻‍♀️", - "🚶🏻‍♀️", - "🚶🏼‍♀️", - "🚶🏼‍♀️", - "🚶🏽‍♀️", - "🚶🏽‍♀️", - "🚶🏾‍♀️", - "🚶🏾‍♀️", - "🚶🏿‍♀️", - "🚶🏿‍♀️", - "🚶‍♂️", - "🚶🏻‍♂️", - "🚶🏻‍♂️", - "🚶🏼‍♂️", - "🚶🏼‍♂️", - "🚶🏽‍♂️", - "🚶🏽‍♂️", - "🚶🏾‍♂️", - "🚶🏾‍♂️", - "🚶🏿‍♂️", - "🚶🏿‍♂️", - "🧑‍🦯", - "🧑🏻‍🦯", - "🧑🏻‍🦯", - "🧑🏼‍🦯", - "🧑🏼‍🦯", - "🧑🏽‍🦯", - "🧑🏽‍🦯", - "🧑🏾‍🦯", - "🧑🏾‍🦯", - "🧑🏿‍🦯", - "🧑🏿‍🦯", - "👩‍🦯", - "👩🏻‍🦯", - "👩🏻‍🦯", - "👩🏼‍🦯", - "👩🏼‍🦯", - "👩🏽‍🦯", - "👩🏽‍🦯", - "👩🏾‍🦯", - "👩🏾‍🦯", - "👩🏿‍🦯", - "👩🏿‍🦯", - "👨‍🦯", - "👨🏻‍🦯", - "👨🏻‍🦯", - "👨🏼‍🦯", - "👨🏼‍🦯", - "👨🏽‍🦯", - "👨🏽‍🦯", - "👨🏾‍🦯", - "👨🏾‍🦯", - "👨🏿‍🦯", - "👨🏿‍🦯", - "🧎", - "🧎🏻", - "🧎🏻", - "🧎🏼", - "🧎🏼", - "🧎🏽", - "🧎🏽", - "🧎🏾", - "🧎🏾", - "🧎🏿", - "🧎🏿", - "🧎‍♀️", - "🧎🏻‍♀️", - "🧎🏻‍♀️", - "🧎🏼‍♀️", - "🧎🏼‍♀️", - "🧎🏽‍♀️", - "🧎🏽‍♀️", - "🧎🏾‍♀️", - "🧎🏾‍♀️", - "🧎🏿‍♀️", - "🧎🏿‍♀️", - "🧎‍♂️", - "🧎🏻‍♂️", - "🧎🏻‍♂️", - "🧎🏼‍♂️", - "🧎🏼‍♂️", - "🧎🏽‍♂️", - "🧎🏽‍♂️", - "🧎🏾‍♂️", - "🧎🏾‍♂️", - "🧎🏿‍♂️", - "🧎🏿‍♂️", - "🏃", - "🏃", - "🏃🏻", - "🏃🏻", - "🏃🏼", - "🏃🏼", - "🏃🏽", - "🏃🏽", - "🏃🏾", - "🏃🏾", - "🏃🏿", - "🏃🏿", - "🏃‍♀️", - "🏃🏻‍♀️", - "🏃🏻‍♀️", - "🏃🏼‍♀️", - "🏃🏼‍♀️", - "🏃🏽‍♀️", - "🏃🏽‍♀️", - "🏃🏾‍♀️", - "🏃🏾‍♀️", - "🏃🏿‍♀️", - "🏃🏿‍♀️", - "🏃‍♂️", - "🏃🏻‍♂️", - "🏃🏻‍♂️", - "🏃🏼‍♂️", - "🏃🏼‍♂️", - "🏃🏽‍♂️", - "🏃🏽‍♂️", - "🏃🏾‍♂️", - "🏃🏾‍♂️", - "🏃🏿‍♂️", - "🏃🏿‍♂️", - "🧍", - "🧍🏻", - "🧍🏻", - "🧍🏼", - "🧍🏼", - "🧍🏽", - "🧍🏽", - "🧍🏾", - "🧍🏾", - "🧍🏿", - "🧍🏿", - "🧍‍♀️", - "🧍🏻‍♀️", - "🧍🏻‍♀️", - "🧍🏼‍♀️", - "🧍🏼‍♀️", - "🧍🏽‍♀️", - "🧍🏽‍♀️", - "🧍🏾‍♀️", - "🧍🏾‍♀️", - "🧍🏿‍♀️", - "🧍🏿‍♀️", - "🧍‍♂️", - "🧍🏻‍♂️", - "🧍🏻‍♂️", - "🧍🏼‍♂️", - "🧍🏼‍♂️", - "🧍🏽‍♂️", - "🧍🏽‍♂️", - "🧍🏾‍♂️", - "🧍🏾‍♂️", - "🧍🏿‍♂️", - "🧍🏿‍♂️", - "🧑‍🤝‍🧑", - "🧑🏻‍🤝‍🧑🏻", - "🧑🏻‍🤝‍🧑🏻", - "🧑🏻‍🤝‍🧑🏼", - "🧑🏻‍🤝‍🧑🏼", - "🧑🏻‍🤝‍🧑🏽", - "🧑🏻‍🤝‍🧑🏽", - "🧑🏻‍🤝‍🧑🏾", - "🧑🏻‍🤝‍🧑🏾", - "🧑🏻‍🤝‍🧑🏿", - "🧑🏻‍🤝‍🧑🏿", - "🧑🏼‍🤝‍🧑🏻", - "🧑🏼‍🤝‍🧑🏻", - "🧑🏼‍🤝‍🧑🏼", - "🧑🏼‍🤝‍🧑🏼", - "🧑🏼‍🤝‍🧑🏽", - "🧑🏼‍🤝‍🧑🏽", - "🧑🏼‍🤝‍🧑🏾", - "🧑🏼‍🤝‍🧑🏾", - "🧑🏼‍🤝‍🧑🏿", - "🧑🏼‍🤝‍🧑🏿", - "🧑🏽‍🤝‍🧑🏻", - "🧑🏽‍🤝‍🧑🏻", - "🧑🏽‍🤝‍🧑🏼", - "🧑🏽‍🤝‍🧑🏼", - "🧑🏽‍🤝‍🧑🏽", - "🧑🏽‍🤝‍🧑🏽", - "🧑🏽‍🤝‍🧑🏾", - "🧑🏽‍🤝‍🧑🏾", - "🧑🏽‍🤝‍🧑🏿", - "🧑🏽‍🤝‍🧑🏿", - "🧑🏾‍🤝‍🧑🏻", - "🧑🏾‍🤝‍🧑🏻", - "🧑🏾‍🤝‍🧑🏼", - "🧑🏾‍🤝‍🧑🏼", - "🧑🏾‍🤝‍🧑🏽", - "🧑🏾‍🤝‍🧑🏽", - "🧑🏾‍🤝‍🧑🏾", - "🧑🏾‍🤝‍🧑🏾", - "🧑🏾‍🤝‍🧑🏿", - "🧑🏾‍🤝‍🧑🏿", - "🧑🏿‍🤝‍🧑🏻", - "🧑🏿‍🤝‍🧑🏻", - "🧑🏿‍🤝‍🧑🏼", - "🧑🏿‍🤝‍🧑🏼", - "🧑🏿‍🤝‍🧑🏽", - "🧑🏿‍🤝‍🧑🏽", - "🧑🏿‍🤝‍🧑🏾", - "🧑🏿‍🤝‍🧑🏾", - "🧑🏿‍🤝‍🧑🏿", - "🧑🏿‍🤝‍🧑🏿", - "👫", - "👫🏻", - "👫🏻", - "👩🏻‍🤝‍👨🏼", - "👩🏻‍🤝‍👨🏼", - "👩🏻‍🤝‍👨🏽", - "👩🏻‍🤝‍👨🏽", - "👩🏻‍🤝‍👨🏾", - "👩🏻‍🤝‍👨🏾", - "👩🏻‍🤝‍👨🏿", - "👩🏻‍🤝‍👨🏿", - "👩🏼‍🤝‍👨🏻", - "👩🏼‍🤝‍👨🏻", - "👫🏼", - "👫🏼", - "👩🏼‍🤝‍👨🏽", - "👩🏼‍🤝‍👨🏽", - "👩🏼‍🤝‍👨🏾", - "👩🏼‍🤝‍👨🏾", - "👩🏼‍🤝‍👨🏿", - "👩🏼‍🤝‍👨🏿", - "👩🏽‍🤝‍👨🏻", - "👩🏽‍🤝‍👨🏻", - "👩🏽‍🤝‍👨🏼", - "👩🏽‍🤝‍👨🏼", - "👫🏽", - "👫🏽", - "👩🏽‍🤝‍👨🏾", - "👩🏽‍🤝‍👨🏾", - "👩🏽‍🤝‍👨🏿", - "👩🏽‍🤝‍👨🏿", - "👩🏾‍🤝‍👨🏻", - "👩🏾‍🤝‍👨🏻", - "👩🏾‍🤝‍👨🏼", - "👩🏾‍🤝‍👨🏼", - "👩🏾‍🤝‍👨🏽", - "👩🏾‍🤝‍👨🏽", - "👫🏾", - "👫🏾", - "👩🏾‍🤝‍👨🏿", - "👩🏾‍🤝‍👨🏿", - "👩🏿‍🤝‍👨🏻", - "👩🏿‍🤝‍👨🏻", - "👩🏿‍🤝‍👨🏼", - "👩🏿‍🤝‍👨🏼", - "👩🏿‍🤝‍👨🏽", - "👩🏿‍🤝‍👨🏽", - "👩🏿‍🤝‍👨🏾", - "👩🏿‍🤝‍👨🏾", - "👫🏿", - "👫🏿", - "👭", - "👭🏻", - "👭🏻", - "👩🏻‍🤝‍👩🏼", - "👩🏻‍🤝‍👩🏼", - "👩🏻‍🤝‍👩🏽", - "👩🏻‍🤝‍👩🏽", - "👩🏻‍🤝‍👩🏾", - "👩🏻‍🤝‍👩🏾", - "👩🏻‍🤝‍👩🏿", - "👩🏻‍🤝‍👩🏿", - "👩🏼‍🤝‍👩🏻", - "👩🏼‍🤝‍👩🏻", - "👭🏼", - "👭🏼", - "👩🏼‍🤝‍👩🏽", - "👩🏼‍🤝‍👩🏽", - "👩🏼‍🤝‍👩🏾", - "👩🏼‍🤝‍👩🏾", - "👩🏼‍🤝‍👩🏿", - "👩🏼‍🤝‍👩🏿", - "👩🏽‍🤝‍👩🏻", - "👩🏽‍🤝‍👩🏻", - "👩🏽‍🤝‍👩🏼", - "👩🏽‍🤝‍👩🏼", - "👭🏽", - "👭🏽", - "👩🏽‍🤝‍👩🏾", - "👩🏽‍🤝‍👩🏾", - "👩🏽‍🤝‍👩🏿", - "👩🏽‍🤝‍👩🏿", - "👩🏾‍🤝‍👩🏻", - "👩🏾‍🤝‍👩🏻", - "👩🏾‍🤝‍👩🏼", - "👩🏾‍🤝‍👩🏼", - "👩🏾‍🤝‍👩🏽", - "👩🏾‍🤝‍👩🏽", - "👭🏾", - "👭🏾", - "👩🏾‍🤝‍👩🏿", - "👩🏾‍🤝‍👩🏿", - "👩🏿‍🤝‍👩🏻", - "👩🏿‍🤝‍👩🏻", - "👩🏿‍🤝‍👩🏼", - "👩🏿‍🤝‍👩🏼", - "👩🏿‍🤝‍👩🏽", - "👩🏿‍🤝‍👩🏽", - "👩🏿‍🤝‍👩🏾", - "👩🏿‍🤝‍👩🏾", - "👭🏿", - "👭🏿", - "👬", - "👬🏻", - "👬🏻", - "👨🏻‍🤝‍👨🏼", - "👨🏻‍🤝‍👨🏼", - "👨🏻‍🤝‍👨🏽", - "👨🏻‍🤝‍👨🏽", - "👨🏻‍🤝‍👨🏾", - "👨🏻‍🤝‍👨🏾", - "👨🏻‍🤝‍👨🏿", - "👨🏻‍🤝‍👨🏿", - "👨🏼‍🤝‍👨🏻", - "👨🏼‍🤝‍👨🏻", - "👬🏼", - "👬🏼", - "👨🏼‍🤝‍👨🏽", - "👨🏼‍🤝‍👨🏽", - "👨🏼‍🤝‍👨🏾", - "👨🏼‍🤝‍👨🏾", - "👨🏼‍🤝‍👨🏿", - "👨🏼‍🤝‍👨🏿", - "👨🏽‍🤝‍👨🏻", - "👨🏽‍🤝‍👨🏻", - "👨🏽‍🤝‍👨🏼", - "👨🏽‍🤝‍👨🏼", - "👬🏽", - "👬🏽", - "👨🏽‍🤝‍👨🏾", - "👨🏽‍🤝‍👨🏾", - "👨🏽‍🤝‍👨🏿", - "👨🏽‍🤝‍👨🏿", - "👨🏾‍🤝‍👨🏻", - "👨🏾‍🤝‍👨🏻", - "👨🏾‍🤝‍👨🏼", - "👨🏾‍🤝‍👨🏼", - "👨🏾‍🤝‍👨🏽", - "👨🏾‍🤝‍👨🏽", - "👬🏾", - "👬🏾", - "👨🏾‍🤝‍👨🏿", - "👨🏾‍🤝‍👨🏿", - "👨🏿‍🤝‍👨🏻", - "👨🏿‍🤝‍👨🏻", - "👨🏿‍🤝‍👨🏼", - "👨🏿‍🤝‍👨🏼", - "👨🏿‍🤝‍👨🏽", - "👨🏿‍🤝‍👨🏽", - "👨🏿‍🤝‍👨🏾", - "👨🏿‍🤝‍👨🏾", - "👬🏿", - "👬🏿", - "💑", - "💑🏻", - "💑🏻", - "🧑🏻‍❤️‍🧑🏼", - "🧑🏻‍❤️‍🧑🏼", - "🧑🏻‍❤️‍🧑🏽", - "🧑🏻‍❤️‍🧑🏽", - "🧑🏻‍❤️‍🧑🏾", - "🧑🏻‍❤️‍🧑🏾", - "🧑🏻‍❤️‍🧑🏿", - "🧑🏻‍❤️‍🧑🏿", - "🧑🏼‍❤️‍🧑🏻", - "🧑🏼‍❤️‍🧑🏻", - "💑🏼", - "💑🏼", - "🧑🏼‍❤️‍🧑🏽", - "🧑🏼‍❤️‍🧑🏽", - "🧑🏼‍❤️‍🧑🏾", - "🧑🏼‍❤️‍🧑🏾", - "🧑🏼‍❤️‍🧑🏿", - "🧑🏼‍❤️‍🧑🏿", - "🧑🏽‍❤️‍🧑🏻", - "🧑🏽‍❤️‍🧑🏻", - "🧑🏽‍❤️‍🧑🏼", - "🧑🏽‍❤️‍🧑🏼", - "💑🏽", - "💑🏽", - "🧑🏽‍❤️‍🧑🏾", - "🧑🏽‍❤️‍🧑🏾", - "🧑🏽‍❤️‍🧑🏿", - "🧑🏽‍❤️‍🧑🏿", - "🧑🏾‍❤️‍🧑🏻", - "🧑🏾‍❤️‍🧑🏻", - "🧑🏾‍❤️‍🧑🏼", - "🧑🏾‍❤️‍🧑🏼", - "🧑🏾‍❤️‍🧑🏽", - "🧑🏾‍❤️‍🧑🏽", - "💑🏾", - "💑🏾", - "🧑🏾‍❤️‍🧑🏿", - "🧑🏾‍❤️‍🧑🏿", - "🧑🏿‍❤️‍🧑🏻", - "🧑🏿‍❤️‍🧑🏻", - "🧑🏿‍❤️‍🧑🏼", - "🧑🏿‍❤️‍🧑🏼", - "🧑🏿‍❤️‍🧑🏽", - "🧑🏿‍❤️‍🧑🏽", - "🧑🏿‍❤️‍🧑🏾", - "🧑🏿‍❤️‍🧑🏾", - "💑🏿", - "💑🏿", - "👩‍❤️‍👨", - "👩🏻‍❤️‍👨🏻", - "👩🏻‍❤️‍👨🏻", - "👩🏻‍❤️‍👨🏼", - "👩🏻‍❤️‍👨🏼", - "👩🏻‍❤️‍👨🏽", - "👩🏻‍❤️‍👨🏽", - "👩🏻‍❤️‍👨🏾", - "👩🏻‍❤️‍👨🏾", - "👩🏻‍❤️‍👨🏿", - "👩🏻‍❤️‍👨🏿", - "👩🏼‍❤️‍👨🏻", - "👩🏼‍❤️‍👨🏻", - "👩🏼‍❤️‍👨🏼", - "👩🏼‍❤️‍👨🏼", - "👩🏼‍❤️‍👨🏽", - "👩🏼‍❤️‍👨🏽", - "👩🏼‍❤️‍👨🏾", - "👩🏼‍❤️‍👨🏾", - "👩🏼‍❤️‍👨🏿", - "👩🏼‍❤️‍👨🏿", - "👩🏽‍❤️‍👨🏻", - "👩🏽‍❤️‍👨🏻", - "👩🏽‍❤️‍👨🏼", - "👩🏽‍❤️‍👨🏼", - "👩🏽‍❤️‍👨🏽", - "👩🏽‍❤️‍👨🏽", - "👩🏽‍❤️‍👨🏾", - "👩🏽‍❤️‍👨🏾", - "👩🏽‍❤️‍👨🏿", - "👩🏽‍❤️‍👨🏿", - "👩🏾‍❤️‍👨🏻", - "👩🏾‍❤️‍👨🏻", - "👩🏾‍❤️‍👨🏼", - "👩🏾‍❤️‍👨🏼", - "👩🏾‍❤️‍👨🏽", - "👩🏾‍❤️‍👨🏽", - "👩🏾‍❤️‍👨🏾", - "👩🏾‍❤️‍👨🏾", - "👩🏾‍❤️‍👨🏿", - "👩🏾‍❤️‍👨🏿", - "👩🏿‍❤️‍👨🏻", - "👩🏿‍❤️‍👨🏻", - "👩🏿‍❤️‍👨🏼", - "👩🏿‍❤️‍👨🏼", - "👩🏿‍❤️‍👨🏽", - "👩🏿‍❤️‍👨🏽", - "👩🏿‍❤️‍👨🏾", - "👩🏿‍❤️‍👨🏾", - "👩🏿‍❤️‍👨🏿", - "👩🏿‍❤️‍👨🏿", - "👩‍❤️‍👩", - "👩‍❤️‍👩", - "👩🏻‍❤️‍👩🏻", - "👩🏻‍❤️‍👩🏻", - "👩🏻‍❤️‍👩🏼", - "👩🏻‍❤️‍👩🏼", - "👩🏻‍❤️‍👩🏽", - "👩🏻‍❤️‍👩🏽", - "👩🏻‍❤️‍👩🏾", - "👩🏻‍❤️‍👩🏾", - "👩🏻‍❤️‍👩🏿", - "👩🏻‍❤️‍👩🏿", - "👩🏼‍❤️‍👩🏻", - "👩🏼‍❤️‍👩🏻", - "👩🏼‍❤️‍👩🏼", - "👩🏼‍❤️‍👩🏼", - "👩🏼‍❤️‍👩🏽", - "👩🏼‍❤️‍👩🏽", - "👩🏼‍❤️‍👩🏾", - "👩🏼‍❤️‍👩🏾", - "👩🏼‍❤️‍👩🏿", - "👩🏼‍❤️‍👩🏿", - "👩🏽‍❤️‍👩🏻", - "👩🏽‍❤️‍👩🏻", - "👩🏽‍❤️‍👩🏼", - "👩🏽‍❤️‍👩🏼", - "👩🏽‍❤️‍👩🏽", - "👩🏽‍❤️‍👩🏽", - "👩🏽‍❤️‍👩🏾", - "👩🏽‍❤️‍👩🏾", - "👩🏽‍❤️‍👩🏿", - "👩🏽‍❤️‍👩🏿", - "👩🏾‍❤️‍👩🏻", - "👩🏾‍❤️‍👩🏻", - "👩🏾‍❤️‍👩🏼", - "👩🏾‍❤️‍👩🏼", - "👩🏾‍❤️‍👩🏽", - "👩🏾‍❤️‍👩🏽", - "👩🏾‍❤️‍👩🏾", - "👩🏾‍❤️‍👩🏾", - "👩🏾‍❤️‍👩🏿", - "👩🏾‍❤️‍👩🏿", - "👩🏿‍❤️‍👩🏻", - "👩🏿‍❤️‍👩🏻", - "👩🏿‍❤️‍👩🏼", - "👩🏿‍❤️‍👩🏼", - "👩🏿‍❤️‍👩🏽", - "👩🏿‍❤️‍👩🏽", - "👩🏿‍❤️‍👩🏾", - "👩🏿‍❤️‍👩🏾", - "👩🏿‍❤️‍👩🏿", - "👩🏿‍❤️‍👩🏿", - "👨‍❤️‍👨", - "👨‍❤️‍👨", - "👨🏻‍❤️‍👨🏻", - "👨🏻‍❤️‍👨🏻", - "👨🏻‍❤️‍👨🏼", - "👨🏻‍❤️‍👨🏼", - "👨🏻‍❤️‍👨🏽", - "👨🏻‍❤️‍👨🏽", - "👨🏻‍❤️‍👨🏾", - "👨🏻‍❤️‍👨🏾", - "👨🏻‍❤️‍👨🏿", - "👨🏻‍❤️‍👨🏿", - "👨🏼‍❤️‍👨🏻", - "👨🏼‍❤️‍👨🏻", - "👨🏼‍❤️‍👨🏼", - "👨🏼‍❤️‍👨🏼", - "👨🏼‍❤️‍👨🏽", - "👨🏼‍❤️‍👨🏽", - "👨🏼‍❤️‍👨🏾", - "👨🏼‍❤️‍👨🏾", - "👨🏼‍❤️‍👨🏿", - "👨🏼‍❤️‍👨🏿", - "👨🏽‍❤️‍👨🏻", - "👨🏽‍❤️‍👨🏻", - "👨🏽‍❤️‍👨🏼", - "👨🏽‍❤️‍👨🏼", - "👨🏽‍❤️‍👨🏽", - "👨🏽‍❤️‍👨🏽", - "👨🏽‍❤️‍👨🏾", - "👨🏽‍❤️‍👨🏾", - "👨🏽‍❤️‍👨🏿", - "👨🏽‍❤️‍👨🏿", - "👨🏾‍❤️‍👨🏻", - "👨🏾‍❤️‍👨🏻", - "👨🏾‍❤️‍👨🏼", - "👨🏾‍❤️‍👨🏼", - "👨🏾‍❤️‍👨🏽", - "👨🏾‍❤️‍👨🏽", - "👨🏾‍❤️‍👨🏾", - "👨🏾‍❤️‍👨🏾", - "👨🏾‍❤️‍👨🏿", - "👨🏾‍❤️‍👨🏿", - "👨🏿‍❤️‍👨🏻", - "👨🏿‍❤️‍👨🏻", - "👨🏿‍❤️‍👨🏼", - "👨🏿‍❤️‍👨🏼", - "👨🏿‍❤️‍👨🏽", - "👨🏿‍❤️‍👨🏽", - "👨🏿‍❤️‍👨🏾", - "👨🏿‍❤️‍👨🏾", - "👨🏿‍❤️‍👨🏿", - "👨🏿‍❤️‍👨🏿", - "💏", - "💏🏻", - "💏🏻", - "🧑🏻‍❤️‍💋‍🧑🏼", - "🧑🏻‍❤️‍💋‍🧑🏼", - "🧑🏻‍❤️‍💋‍🧑🏽", - "🧑🏻‍❤️‍💋‍🧑🏽", - "🧑🏻‍❤️‍💋‍🧑🏾", - "🧑🏻‍❤️‍💋‍🧑🏾", - "🧑🏻‍❤️‍💋‍🧑🏿", - "🧑🏻‍❤️‍💋‍🧑🏿", - "🧑🏼‍❤️‍💋‍🧑🏻", - "🧑🏼‍❤️‍💋‍🧑🏻", - "💏🏼", - "💏🏼", - "🧑🏼‍❤️‍💋‍🧑🏽", - "🧑🏼‍❤️‍💋‍🧑🏽", - "🧑🏼‍❤️‍💋‍🧑🏾", - "🧑🏼‍❤️‍💋‍🧑🏾", - "🧑🏼‍❤️‍💋‍🧑🏿", - "🧑🏼‍❤️‍💋‍🧑🏿", - "🧑🏽‍❤️‍💋‍🧑🏻", - "🧑🏽‍❤️‍💋‍🧑🏻", - "🧑🏽‍❤️‍💋‍🧑🏼", - "🧑🏽‍❤️‍💋‍🧑🏼", - "💏🏽", - "💏🏽", - "🧑🏽‍❤️‍💋‍🧑🏾", - "🧑🏽‍❤️‍💋‍🧑🏾", - "🧑🏽‍❤️‍💋‍🧑🏿", - "🧑🏽‍❤️‍💋‍🧑🏿", - "🧑🏾‍❤️‍💋‍🧑🏻", - "🧑🏾‍❤️‍💋‍🧑🏻", - "🧑🏾‍❤️‍💋‍🧑🏼", - "🧑🏾‍❤️‍💋‍🧑🏼", - "🧑🏾‍❤️‍💋‍🧑🏽", - "🧑🏾‍❤️‍💋‍🧑🏽", - "💏🏾", - "💏🏾", - "🧑🏾‍❤️‍💋‍🧑🏿", - "🧑🏾‍❤️‍💋‍🧑🏿", - "🧑🏿‍❤️‍💋‍🧑🏻", - "🧑🏿‍❤️‍💋‍🧑🏻", - "🧑🏿‍❤️‍💋‍🧑🏼", - "🧑🏿‍❤️‍💋‍🧑🏼", - "🧑🏿‍❤️‍💋‍🧑🏽", - "🧑🏿‍❤️‍💋‍🧑🏽", - "🧑🏿‍❤️‍💋‍🧑🏾", - "🧑🏿‍❤️‍💋‍🧑🏾", - "💏🏿", - "💏🏿", - "👩‍❤️‍💋‍👨", - "👩🏻‍❤️‍💋‍👨🏻", - "👩🏻‍❤️‍💋‍👨🏻", - "👩🏻‍❤️‍💋‍👨🏼", - "👩🏻‍❤️‍💋‍👨🏼", - "👩🏻‍❤️‍💋‍👨🏽", - "👩🏻‍❤️‍💋‍👨🏽", - "👩🏻‍❤️‍💋‍👨🏾", - "👩🏻‍❤️‍💋‍👨🏾", - "👩🏻‍❤️‍💋‍👨🏿", - "👩🏻‍❤️‍💋‍👨🏿", - "👩🏼‍❤️‍💋‍👨🏻", - "👩🏼‍❤️‍💋‍👨🏻", - "👩🏼‍❤️‍💋‍👨🏼", - "👩🏼‍❤️‍💋‍👨🏼", - "👩🏼‍❤️‍💋‍👨🏽", - "👩🏼‍❤️‍💋‍👨🏽", - "👩🏼‍❤️‍💋‍👨🏾", - "👩🏼‍❤️‍💋‍👨🏾", - "👩🏼‍❤️‍💋‍👨🏿", - "👩🏼‍❤️‍💋‍👨🏿", - "👩🏽‍❤️‍💋‍👨🏻", - "👩🏽‍❤️‍💋‍👨🏻", - "👩🏽‍❤️‍💋‍👨🏼", - "👩🏽‍❤️‍💋‍👨🏼", - "👩🏽‍❤️‍💋‍👨🏽", - "👩🏽‍❤️‍💋‍👨🏽", - "👩🏽‍❤️‍💋‍👨🏾", - "👩🏽‍❤️‍💋‍👨🏾", - "👩🏽‍❤️‍💋‍👨🏿", - "👩🏽‍❤️‍💋‍👨🏿", - "👩🏾‍❤️‍💋‍👨🏻", - "👩🏾‍❤️‍💋‍👨🏻", - "👩🏾‍❤️‍💋‍👨🏼", - "👩🏾‍❤️‍💋‍👨🏼", - "👩🏾‍❤️‍💋‍👨🏽", - "👩🏾‍❤️‍💋‍👨🏽", - "👩🏾‍❤️‍💋‍👨🏾", - "👩🏾‍❤️‍💋‍👨🏾", - "👩🏾‍❤️‍💋‍👨🏿", - "👩🏾‍❤️‍💋‍👨🏿", - "👩🏿‍❤️‍💋‍👨🏻", - "👩🏿‍❤️‍💋‍👨🏻", - "👩🏿‍❤️‍💋‍👨🏼", - "👩🏿‍❤️‍💋‍👨🏼", - "👩🏿‍❤️‍💋‍👨🏽", - "👩🏿‍❤️‍💋‍👨🏽", - "👩🏿‍❤️‍💋‍👨🏾", - "👩🏿‍❤️‍💋‍👨🏾", - "👩🏿‍❤️‍💋‍👨🏿", - "👩🏿‍❤️‍💋‍👨🏿", - "👩‍❤️‍💋‍👩", - "👩‍❤️‍💋‍👩", - "👩🏻‍❤️‍💋‍👩🏻", - "👩🏻‍❤️‍💋‍👩🏻", - "👩🏻‍❤️‍💋‍👩🏼", - "👩🏻‍❤️‍💋‍👩🏼", - "👩🏻‍❤️‍💋‍👩🏽", - "👩🏻‍❤️‍💋‍👩🏽", - "👩🏻‍❤️‍💋‍👩🏾", - "👩🏻‍❤️‍💋‍👩🏾", - "👩🏻‍❤️‍💋‍👩🏿", - "👩🏻‍❤️‍💋‍👩🏿", - "👩🏼‍❤️‍💋‍👩🏻", - "👩🏼‍❤️‍💋‍👩🏻", - "👩🏼‍❤️‍💋‍👩🏼", - "👩🏼‍❤️‍💋‍👩🏼", - "👩🏼‍❤️‍💋‍👩🏽", - "👩🏼‍❤️‍💋‍👩🏽", - "👩🏼‍❤️‍💋‍👩🏾", - "👩🏼‍❤️‍💋‍👩🏾", - "👩🏼‍❤️‍💋‍👩🏿", - "👩🏼‍❤️‍💋‍👩🏿", - "👩🏽‍❤️‍💋‍👩🏻", - "👩🏽‍❤️‍💋‍👩🏻", - "👩🏽‍❤️‍💋‍👩🏼", - "👩🏽‍❤️‍💋‍👩🏼", - "👩🏽‍❤️‍💋‍👩🏽", - "👩🏽‍❤️‍💋‍👩🏽", - "👩🏽‍❤️‍💋‍👩🏾", - "👩🏽‍❤️‍💋‍👩🏾", - "👩🏽‍❤️‍💋‍👩🏿", - "👩🏽‍❤️‍💋‍👩🏿", - "👩🏾‍❤️‍💋‍👩🏻", - "👩🏾‍❤️‍💋‍👩🏻", - "👩🏾‍❤️‍💋‍👩🏼", - "👩🏾‍❤️‍💋‍👩🏼", - "👩🏾‍❤️‍💋‍👩🏽", - "👩🏾‍❤️‍💋‍👩🏽", - "👩🏾‍❤️‍💋‍👩🏾", - "👩🏾‍❤️‍💋‍👩🏾", - "👩🏾‍❤️‍💋‍👩🏿", - "👩🏾‍❤️‍💋‍👩🏿", - "👩🏿‍❤️‍💋‍👩🏻", - "👩🏿‍❤️‍💋‍👩🏻", - "👩🏿‍❤️‍💋‍👩🏼", - "👩🏿‍❤️‍💋‍👩🏼", - "👩🏿‍❤️‍💋‍👩🏽", - "👩🏿‍❤️‍💋‍👩🏽", - "👩🏿‍❤️‍💋‍👩🏾", - "👩🏿‍❤️‍💋‍👩🏾", - "👩🏿‍❤️‍💋‍👩🏿", - "👩🏿‍❤️‍💋‍👩🏿", - "👨‍❤️‍💋‍👨", - "👨‍❤️‍💋‍👨", - "👨‍❤️‍💋‍👨", - "👨🏻‍❤️‍💋‍👨🏻", - "👨🏻‍❤️‍💋‍👨🏻", - "👨🏻‍❤️‍💋‍👨🏼", - "👨🏻‍❤️‍💋‍👨🏼", - "👨🏻‍❤️‍💋‍👨🏽", - "👨🏻‍❤️‍💋‍👨🏽", - "👨🏻‍❤️‍💋‍👨🏾", - "👨🏻‍❤️‍💋‍👨🏾", - "👨🏻‍❤️‍💋‍👨🏿", - "👨🏻‍❤️‍💋‍👨🏿", - "👨🏼‍❤️‍💋‍👨🏻", - "👨🏼‍❤️‍💋‍👨🏻", - "👨🏼‍❤️‍💋‍👨🏼", - "👨🏼‍❤️‍💋‍👨🏼", - "👨🏼‍❤️‍💋‍👨🏽", - "👨🏼‍❤️‍💋‍👨🏽", - "👨🏼‍❤️‍💋‍👨🏾", - "👨🏼‍❤️‍💋‍👨🏾", - "👨🏼‍❤️‍💋‍👨🏿", - "👨🏼‍❤️‍💋‍👨🏿", - "👨🏽‍❤️‍💋‍👨🏻", - "👨🏽‍❤️‍💋‍👨🏻", - "👨🏽‍❤️‍💋‍👨🏼", - "👨🏽‍❤️‍💋‍👨🏼", - "👨🏽‍❤️‍💋‍👨🏽", - "👨🏽‍❤️‍💋‍👨🏽", - "👨🏽‍❤️‍💋‍👨🏾", - "👨🏽‍❤️‍💋‍👨🏾", - "👨🏽‍❤️‍💋‍👨🏿", - "👨🏽‍❤️‍💋‍👨🏿", - "👨🏾‍❤️‍💋‍👨🏻", - "👨🏾‍❤️‍💋‍👨🏻", - "👨🏾‍❤️‍💋‍👨🏼", - "👨🏾‍❤️‍💋‍👨🏼", - "👨🏾‍❤️‍💋‍👨🏽", - "👨🏾‍❤️‍💋‍👨🏽", - "👨🏾‍❤️‍💋‍👨🏾", - "👨🏾‍❤️‍💋‍👨🏾", - "👨🏾‍❤️‍💋‍👨🏿", - "👨🏾‍❤️‍💋‍👨🏿", - "👨🏿‍❤️‍💋‍👨🏻", - "👨🏿‍❤️‍💋‍👨🏻", - "👨🏿‍❤️‍💋‍👨🏼", - "👨🏿‍❤️‍💋‍👨🏼", - "👨🏿‍❤️‍💋‍👨🏽", - "👨🏿‍❤️‍💋‍👨🏽", - "👨🏿‍❤️‍💋‍👨🏾", - "👨🏿‍❤️‍💋‍👨🏾", - "👨🏿‍❤️‍💋‍👨🏿", - "👨🏿‍❤️‍💋‍👨🏿", - "👪", - "👨‍👩‍👦", - "👨‍👩‍👧", - "👨‍👩‍👧‍👦", - "👨‍👩‍👦‍👦", - "👨‍👩‍👧‍👧", - "👩‍👩‍👦", - "👩‍👩‍👧", - "👩‍👩‍👧‍👦", - "👩‍👩‍👦‍👦", - "👩‍👩‍👧‍👧", - "👨‍👨‍👦", - "👨‍👨‍👧", - "👨‍👨‍👧‍👦", - "👨‍👨‍👦‍👦", - "👨‍👨‍👧‍👧", - "👩‍👦", - "👩‍👧", - "👩‍👧‍👦", - "👩‍👦‍👦", - "👩‍👧‍👧", - "👨‍👦", - "👨‍👧", - "👨‍👧‍👦", - "👨‍👦‍👦", - "👨‍👧‍👧", - "🪢", - "🧶", - "🧵", - "🪡", - "🧥", - "🥼", - "🦺", - "👚", - "👕", - "👕", - "👖", - "🩲", - "🩳", - "👔", - "👗", - "👙", - "🩱", - "👘", - "🥻", - "🩴", - "🥿", - "🥿", - "👠", - "👡", - "👡", - "👢", - "👢", - "👞", - "👟", - "👟", - "🥾", - "🧦", - "🧤", - "🧣", - "🎩", - "🎩", - "🧢", - "👒", - "🎓", - "⛑️", - "⛑️", - "🪖", - "👑", - "💍", - "👝", - "👝", - "👛", - "👜", - "💼", - "🎒", - "🎒", - "🧳", - "👓", - "👓", - "🕶️", - "🥽", - "🌂", - "🩷", - "❤️", - "❤️", - "🧡", - "💛", - "💚", - "🩵", - "💙", - "💜", - "🖤", - "🩶", - "🤍", - "🤎", - "💔", - "❣️", - "❣️", - "💕", - "💞", - "💓", - "💓", - "💗", - "💗", - "💖", - "💘", - "💝", - "❤️‍🩹", - "❤️‍🔥", - "💟", - "☮️", - "☮️", - "✝️", - "✝️", - "☪️", - "🕉️", - "☸️", - "🪯", - "✡️", - "🔯", - "🕎", - "☯️", - "☦️", - "🛐", - "🛐", - "⛎", - "♈", - "♉", - "♊", - "♋", - "♌", - "♍", - "♎", - "♏", - "♏", - "♐", - "♑", - "♒", - "♓", - "🆔", - "⚛️", - "⚛️", - "🉑", - "☢️", - "☢️", - "☣️", - "☣️", - "📴", - "📳", - "🈶", - "🈚", - "🈸", - "🈺", - "🈷️", - "✴️", - "🆚", - "💮", - "🉐", - "㊙️", - "㊗️", - "🈴", - "🈵", - "🈹", - "🈲", - "🅰️", - "🅱️", - "🆎", - "🆑", - "🅾️", - "🆘", - "❌", - "❌", - "⭕", - "🛑", - "🛑", - "⛔", - "📛", - "🚫", - "🚫", - "💢", - "♨️", - "♨️", - "🚷", - "🚯", - "🚯", - "🚳", - "🚱", - "🔞", - "📵", - "🚭", - "❗", - "❕", - "❓", - "❓", - "❔", - "‼️", - "⁉️", - "🔅", - "🔆", - "〽️", - "⚠️", - "🚸", - "🔱", - "⚜️", - "🔰", - "♻️", - "✅", - "🈯", - "💹", - "❇️", - "✳️", - "❎", - "🌐", - "💠", - "Ⓜ️", - "Ⓜ️", - "🌀", - "💤", - "🏧", - "🚾", - "🚾", - "♿", - "🅿️", - "🛗", - "🈳", - "🈂️", - "🛂", - "🛃", - "🛄", - "🛅", - "🛜", - "🚹", - "🚹", - "🚺", - "🚺", - "🚼", - "🚻", - "🚮", - "🎦", - "📶", - "📶", - "🈁", - "🔣", - "🔣", - "ℹ️", - "ℹ️", - "🔤", - "🔡", - "🔠", - "🆖", - "🆗", - "🆙", - "🆒", - "🆕", - "🆓", - "0️⃣", - "1️⃣", - "2️⃣", - "3️⃣", - "4️⃣", - "5️⃣", - "6️⃣", - "7️⃣", - "8️⃣", - "9️⃣", - "🔟", - "🔢", - "#️⃣", - "*️⃣", - "*️⃣", - "⏏️", - "⏏️", - "▶️", - "⏸️", - "⏸️", - "⏯️", - "⏹️", - "⏺️", - "⏭️", - "⏭️", - "⏮️", - "⏮️", - "⏩", - "⏪", - "⏫", - "⏬", - "◀️", - "🔼", - "🔽", - "➡️", - "➡️", - "⬅️", - "⬅️", - "⬆️", - "⬆️", - "⬇️", - "⬇️", - "↗️", - "↘️", - "↙️", - "↖️", - "↖️", - "↕️", - "↕️", - "↔️", - "↪️", - "↩️", - "⤴️", - "⤵️", - "🔀", - "🔁", - "🔂", - "🔄", - "🔃", - "🎵", - "🎶", - "🎶", - "➕", - "➖", - "➗", - "✖️", - "🟰", - "♾️", - "💲", - "💱", - "™️", - "™️", - "©️", - "®️", - "〰️", - "➰", - "➿", - "🔚", - "🔚", - "🔙", - "🔙", - "🔛", - "🔛", - "🔝", - "🔝", - "🔜", - "🔜", - "✔️", - "✔️", - "☑️", - "🔘", - "⚪", - "⚫", - "🔴", - "🔵", - "🟤", - "🟣", - "🟢", - "🟡", - "🟠", - "🔺", - "🔻", - "🔸", - "🔹", - "🔶", - "🔷", - "🔳", - "🔲", - "▪️", - "▫️", - "◾", - "◽", - "◼️", - "◻️", - "⬛", - "⬜", - "🟧", - "🟦", - "🟥", - "🟫", - "🟪", - "🟩", - "🟨", - "🔈", - "🔇", - "🔇", - "🔉", - "🔊", - "🔔", - "🔕", - "📣", - "📣", - "📢", - "🗨️", - "🗨️", - "👁‍🗨", - "💬", - "💭", - "🗯️", - "🗯️", - "♠️", - "♠️", - "♣️", - "♣️", - "♥️", - "♥️", - "♦️", - "♦️", - "🃏", - "🃏", - "🎴", - "🀄", - "🕐", - "🕐", - "🕑", - "🕑", - "🕒", - "🕒", - "🕓", - "🕓", - "🕔", - "🕔", - "🕕", - "🕕", - "🕖", - "🕖", - "🕗", - "🕗", - "🕘", - "🕘", - "🕙", - "🕙", - "🕚", - "🕚", - "🕛", - "🕛", - "🕜", - "🕜", - "🕝", - "🕝", - "🕞", - "🕞", - "🕟", - "🕟", - "🕠", - "🕠", - "🕡", - "🕡", - "🕢", - "🕢", - "🕣", - "🕣", - "🕤", - "🕤", - "🕥", - "🕥", - "🕦", - "🕦", - "🕧", - "🕧", - "♀️", - "♂️", - "⚧", - "⚕️", - "🇿", - "🇾", - "🇽", - "🇼", - "🇻", - "🇺", - "🇹", - "🇸", - "🇷", - "🇶", - "🇵", - "🇴", - "🇳", - "🇲", - "🇱", - "🇰", - "🇯", - "🇮", - "🇭", - "🇬", - "🇫", - "🇪", - "🇩", - "🇨", - "🇧", - "🇦", - "🚗", - "🚗", - "🚕", - "🚙", - "🛻", - "🚐", - "🚌", - "🚎", - "🏎️", - "🏎️", - "🚓", - "🚑", - "🚒", - "🚚", - "🚛", - "🚜", - "🦯", - "🦽", - "🦼", - "🩼", - "🛴", - "🛴", - "🚲", - "🚲", - "🛵", - "🛵", - "🏍️", - "🏍️", - "🛺", - "🛞", - "🚨", - "🚔", - "🚍", - "🚘", - "🚖", - "🚡", - "🚠", - "🚟", - "🚃", - "🚋", - "🚋", - "🚞", - "🚝", - "🚄", - "🚅", - "🚅", - "🚈", - "🚂", - "🚂", - "🚆", - "🚇", - "🚊", - "🚉", - "✈️", - "🛫", - "🛬", - "🛩️", - "🛩️", - "💺", - "🛰️", - "🚀", - "🛸", - "🚁", - "🛶", - "🛶", - "⛵", - "🚤", - "🛥️", - "🛥️", - "🛳️", - "🛳️", - "⛴️", - "🚢", - "🛟", - "⚓", - "🪝", - "⛽", - "⛽", - "🚧", - "🚦", - "🚥", - "🚏", - "🚏", - "🗺️", - "🗺️", - "🗿", - "🗿", - "🗽", - "🗼", - "🏰", - "🏰", - "🏯", - "🏟️", - "🎡", - "🎢", - "🎠", - "⛲", - "⛱️", - "⛱️", - "🏖️", - "🏖️", - "🏝️", - "🏝️", - "🏜️", - "🌋", - "⛰️", - "🏔️", - "🏔️", - "🗻", - "🏕️", - "⛺", - "🏠", - "🏡", - "🏘️", - "🏘️", - "🏘️", - "🏚️", - "🏚️", - "🛖", - "🏗️", - "🏗️", - "🏭", - "🏢", - "🏬", - "🏣", - "🏤", - "🏥", - "🏦", - "🏨", - "🏪", - "🏫", - "🏩", - "💒", - "🏛️", - "⛪", - "🕌", - "🕍", - "🛕", - "🕋", - "⛩️", - "🛤️", - "🛤️", - "🛣️", - "🗾", - "🗾", - "🎑", - "🏞️", - "🏞️", - "🌅", - "🌄", - "🌠", - "🌠", - "🎇", - "🎆", - "🌇", - "🌇", - "🌇", - "🌆", - "🏙️", - "🌃", - "🌌", - "🌉", - "🌁" -]; diff --git a/font.gs b/font.gs deleted file mode 100644 index c04a1da..0000000 --- a/font.gs +++ /dev/null @@ -1,127 +0,0 @@ -# Usage: -# copy font.txt to your project directory -# include the font data in the font_data list -# list font_data = file ```font.txt```; -# generate your own font using font.py -# in inkscape, use these options: -# Input/Output > SVG output > Path data > Path string format = Absolute -# Input/Output > SVG output > Path data > Force repeat commands = Checked - -var font_offset = 0; -var font_x = 0; -var font_y = 0; -var font_scale = 1; -var font_x1 = 0; -var font_x2 = 240; -var font_char_spacing = 0; -var font_line_spacing = 0; -var font_linelen = 0; - -%define FONT_NAME font_data[font_offset+1] -%define FONT_CREATOR font_data[font_offset+2] -%define FONT_RIGHTS font_data[font_offset+3] -%define FONT_WIDTH font_data[font_offset+4] -%define FONT_HEIGHT font_data[font_offset+5] - -%define FONT_CALCULATE_WIDTH_FROM_LENGTH(LENGTH) \ - (LENGTH*(FONT_WIDTH+2+font_char_spacing)-(2+font_char_spacing))*font_scale -%define FONT_CALCULATE_WIDTH(TEXT) FONT_CALCULATE_WIDTH_FROM_LENGTH(length(TEXT)) - -proc font_render_char char { - switch_costume $char; - local x = ""; - local y = ""; - local i = font_offset+font_data[5+font_offset+costume_number()]; - forever { - if font_data[i] == "M" { - pen_up; - goto font_x+font_scale*font_data[i+1], font_y-font_scale*font_data[i+2]; - i += 3; - if x == "" { - x = x_position(); - y = y_position(); - } - } elif font_data[i] == "L" { - pen_down; - goto font_x+font_scale*font_data[i+1], font_y-font_scale*font_data[i+2]; - i += 3; - } elif font_data[i] == "H" { - pen_down; - set_x font_x+font_scale*font_data[i+1]; - i += 2; - } elif font_data[i] == "V" { - pen_down; - set_y font_y-font_scale*font_data[i+1]; - i += 2; - } elif font_data[i] == "Z" { - pen_down; - goto x, y; - i += 1; - } else { - pen_up; - stop_this_script; - } - } -} - -proc font_render_begin { - font_x = font_x1; - font_linelen = 0; -} - -proc font_render_text text { - local i = 1; - repeat length($text) { - font_render_char $text[i]; - font_x += (FONT_WIDTH+2+font_char_spacing)*font_scale; - i++; - } -} - -proc font_render_text_softwrap text { - local maxlen = (font_x2 - font_x1) // ((FONT_WIDTH+2+font_char_spacing)*font_scale); - local i = 1; - local font_linelen = 0; - local word = ""; - until i > length($text) { - until $text[i] == " " or i > length($text) { - word &= $text[i]; - i++; - } - if font_linelen + length(word) > maxlen { - font_y -= (FONT_HEIGHT+4+font_line_spacing)*font_scale; - font_x = font_x1; - font_linelen = 0; - } - local j = 1; - repeat length(word) { - font_render_char word[j]; - font_x += (FONT_WIDTH+2+font_char_spacing)*font_scale; - font_linelen += 1; - if font_x > font_x2 { - font_y -= (FONT_HEIGHT+4+font_line_spacing)*font_scale; - font_x = font_x1; - font_linelen = 0; - } - j++; - } - word = ""; - until $text[i] != " " or i > length($text) { - word &= $text[i]; - i++; - } - local j = 1; - repeat length(word) { - font_render_char word[j]; - font_x += (FONT_WIDTH+2+font_char_spacing)*font_scale; - font_linelen += 1; - if font_x > font_x2 { - font_y -= (FONT_HEIGHT+4+font_line_spacing)*font_scale; - font_x = font_x1; - font_linelen = 0; - } - j++; - } - word = ""; - } -} diff --git a/font.py b/font.py deleted file mode 100644 index 1447f0e..0000000 --- a/font.py +++ /dev/null @@ -1,90 +0,0 @@ -# pyright: reportAny=false -# pyright: reportUnusedCallResult=false - -import argparse -import re -import xml.etree.ElementTree -from dataclasses import dataclass -from pathlib import Path -from typing import cast - -ns = { - "svg": "http://www.w3.org/2000/svg", - "inkscape": "http://www.inkscape.org/namespaces/inkscape", - "dc": "http://purl.org/dc/elements/1.1/", - "cc": "http://creativecommons.org/ns#", - "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", -} - -CHARSET = "".join(map(chr, range(ord(" "), ord("~") + 1))) - -argparser = argparse.ArgumentParser() -argparser.add_argument("font", type=Path, help="Font .svg file to convert") -argparser.add_argument("output", type=Path, help="Output .txt file") - - -@dataclass -class Args: - font: Path - output: Path - - -args = Args(**argparser.parse_args().__dict__) -name = args.font.stem -root = xml.etree.ElementTree.parse(args.font).getroot() -width = int(cast(str, root.get("width"))) -height = int(cast(str, root.get("height"))) -creator = root.find(".//dc:creator/dc:Agent/dc:title", ns) or "" -rights = root.find(".//dc:rights/dc:Agent/dc:title", ns) or "" -chars: dict[str, list[str]] = {} - - -def modulate(d: list[str]) -> list[str]: - cmd: str = "" - i = 0 - while i < len(d): - if d[i].isalpha(): - cmd = d[i] - i += 1 - if cmd.upper() in "ML": - if cmd.isupper(): - d[i] = str(int(float(d[i])) % (width * 2)) - i += 2 - elif cmd.upper() == "H": - if cmd.isupper(): - d[i] = str(int(float(d[i])) % (width * 2)) - i += 1 - elif cmd.upper() == "V": - i += 1 - return d - - -for path in root.findall(".//svg:path", ns): - sd = cast(str, path.get("d")) - label = cast(str, path.get("{%s}label" % ns["inkscape"])) - if len(label) == 1: - chars[label] = modulate(re.split(r"[,\s]+", sd)) - -with args.output.open("w") as f: - - def print(*objs: object, sep: str = " ", end: str = "\n") -> None: - f.write(sep.join(map(str, objs)) + end) - - print(name) - print(creator) - print(rights) - print(width) - print(height) - - i = 0 - for ch in CHARSET: - d = chars.get(ch, []) - d.append("#") - print(6 + len(CHARSET) + i) - i += len(d) - for ch in CHARSET: - d: list[str] = chars.get(ch, ["#"]) - for x in d: - if str(x).islower() and x not in "Zz": - x = "d" + x - print(x) diff --git a/font.svg b/font.svg deleted file mode 100644 index 9487322..0000000 --- a/font.svg +++ /dev/null @@ -1,448 +0,0 @@ - - - -aspizu@protonmail.comMIT diff --git a/font.txt b/font.txt deleted file mode 100644 index 11aaec1..0000000 --- a/font.txt +++ /dev/null @@ -1,1755 +0,0 @@ -font - - -4 -8 -101 -102 -113 -124 -145 -177 -194 -230 -236 -252 -268 -286 -297 -304 -310 -316 -323 -352 -370 -393 -419 -435 -458 -487 -500 -543 -572 -583 -595 -605 -616 -626 -645 -679 -698 -728 -750 -767 -782 -795 -821 -837 -853 -869 -889 -897 -911 -922 -945 -963 -992 -1016 -1048 -1059 -1075 -1089 -1103 -1116 -1135 -1146 -1156 -1163 -1173 -1183 -1189 -1196 -1222 -1240 -1262 -1280 -1306 -1322 -1345 -1361 -1379 -1397 -1417 -1430 -1448 -1461 -1483 -1501 -1519 -1532 -1564 -1580 -1596 -1610 -1624 -1637 -1662 -1677 -1705 -1711 -1739 -# -M -2 -8 -V -8 -M -2 -0 -V -5 -# -M -3 -0 -V -2 -M -1 -0 -V -2 -# -M -4 -6 -H -0 -M -4 -2 -H -0 -M -3 -8 -V -0 -M -1 -8 -V -0 -# -M -2 --1 -V -9 -M -4 -1 -L -3 -0 -H -1 -L -0 -1 -V -2 -L -4 -5 -V -7 -L -3 -8 -H -1 -L -0 -7 -# -M -4 -6 -V -7 -M -0 -1 -V -2 -M -4 -0 -L -0 -8 -# -M -4 -5 -L -2 -8 -H -1 -L -0 -7 -V -4 -L -1 -3 -M -4 -1 -L -3 -0 -H -1 -L -0 -1 -V -2 -L -2 -4 -L -4 -8 -# -M -2 -0 -V -2 -# -M -4 --1 -H -3 -L -1 -1 -V -7 -L -3 -9 -H -4 -# -M -0 --1 -H -1 -L -3 -1 -V -7 -L -1 -9 -H -0 -# -M -0 -3 -L -4 -7 -M -4 -3 -L -0 -7 -M -2 -1 -V -5 -# -M -4 -4 -H -0 -M -2 -2 -V -6 -# -M -2 -7 -L -1 -10 -# -M -0 -4 -H -4 -# -M -2 -7 -V -8 -# -M -0 -9 -L -4 --1 -# -M -2 -4 -V -4 -M -1 -0 -H -3 -L -4 -1 -V -7 -L -3 -8 -H -1 -L -0 -7 -V -1 -L -1 -0 -# -M -0 -8 -H -2 -M -0 -1 -H -1 -L -2 -0 -V -8 -H -4 -# -M -0 -2 -V -1 -L -1 -0 -H -3 -L -4 -1 -V -3 -L -0 -7 -V -8 -H -4 -# -M -0 -0 -H -4 -L -1 -3 -H -3 -L -4 -4 -V -7 -L -3 -8 -H -1 -L -0 -7 -V -6 -# -M -4 -4 -V -8 -M -4 -0 -L -0 -4 -V -6 -H -4 -# -M -4 -0 -H -0 -V -3 -H -3 -L -4 -4 -V -7 -L -3 -8 -H -1 -L -0 -7 -# -M -4 -1 -L -3 -0 -H -1 -L -0 -1 -V -7 -L -1 -8 -H -3 -L -4 -7 -V -4 -L -3 -3 -H -0 -# -M -0 -1 -V -0 -H -4 -V -1 -L -1 -8 -# -M -0 -1 -L -1 -0 -H -3 -L -4 -1 -V -3 -L -3 -4 -H -1 -L -0 -5 -V -7 -L -1 -8 -H -3 -L -4 -7 -V -5 -L -3 -4 -H -1 -L -0 -3 -Z -# -M -0 -7 -L -1 -8 -H -3 -L -4 -7 -V -1 -L -3 -0 -H -1 -L -0 -1 -V -4 -L -1 -5 -H -4 -# -M -2 -7 -V -8 -M -2 -2 -V -3 -# -M -2 -7 -L -1 -10 -M -2 -2 -V -3 -# -M -4 -0 -L -0 -4 -L -4 -8 -# -M -0 -6 -H -4 -M -0 -3 -H -4 -# -M -0 -0 -L -4 -4 -L -0 -8 -# -M -2 -8 -V -8 -M -1 -0 -H -3 -L -4 -1 -V -3 -L -2 -5 -# -M -4 -3 -H -3 -L -2 -4 -V -6 -L -3 -7 -L -4 -6 -V -1 -L -3 -0 -H -1 -L -0 -1 -V -9 -L -1 -10 -H -3 -# -M -0 -6 -H -4 -M -0 -8 -V -6 -L -2 -0 -L -4 -6 -V -8 -# -M -3 -4 -H -0 -M -0 -0 -H -3 -L -4 -1 -V -3 -L -3 -4 -L -4 -5 -V -7 -L -3 -8 -H -0 -Z -# -M -4 -1 -L -3 -0 -H -1 -L -0 -1 -V -7 -L -1 -8 -H -3 -L -4 -7 -# -M -0 -0 -H -3 -L -4 -1 -V -7 -L -3 -8 -H -0 -Z -# -M -4 -4 -H -0 -M -4 -0 -H -0 -V -8 -H -4 -# -M -4 -4 -H -0 -M -4 -0 -H -0 -V -8 -# -M -4 -1 -L -3 -0 -H -1 -L -0 -1 -V -7 -L -1 -8 -H -3 -L -4 -7 -V -4 -H -2 -# -M -4 -4 -H -0 -M -4 -0 -V -8 -M -0 -0 -V -8 -# -M -2 -0 -V -8 -M -0 -8 -H -4 -M -0 -0 -H -4 -# -M -1 -0 -H -4 -V -7 -L -3 -8 -H -1 -L -0 -7 -# -M -2 -4 -H -0 -M -4 -8 -L -2 -4 -L -4 -0 -M -0 -0 -V -8 -# -M -0 -0 -V -8 -H -4 -# -M -0 -8 -V -0 -L -2 -3 -L -4 -0 -V -8 -# -M -0 -8 -V -0 -L -4 -8 -V -0 -# -M -0 -1 -L -1 -0 -H -3 -L -4 -1 -V -7 -L -3 -8 -H -1 -L -0 -7 -Z -# -M -0 -8 -V -0 -H -3 -L -4 -1 -V -3 -L -3 -4 -H -0 -# -M -4 -10 -L -3 -8 -M -0 -1 -L -1 -0 -H -3 -L -4 -1 -V -7 -L -3 -8 -H -1 -L -0 -7 -Z -# -M -4 -8 -L -2 -4 -M -0 -8 -V -0 -H -3 -L -4 -1 -V -3 -L -3 -4 -H -0 -# -M -4 -1 -L -3 -0 -H -1 -L -0 -1 -V -2 -L -2 -4 -H -3 -L -4 -5 -V -7 -L -3 -8 -H -1 -L -0 -7 -# -M -2 -0 -V -8 -M -0 -0 -H -4 -# -M -0 -0 -V -7 -L -1 -8 -H -3 -L -4 -7 -V -0 -# -M -0 -0 -V -4 -L -2 -8 -L -4 -4 -V -0 -# -M -0 -0 -V -8 -L -2 -5 -L -4 -8 -V -0 -# -M -4 -0 -L -0 -8 -M -0 -0 -L -4 -8 -# -M -4 -0 -V -2 -L -2 -5 -M -0 -0 -V -2 -L -2 -5 -V -8 -# -M -0 -0 -H -4 -L -0 -8 -H -4 -# -M -3 --1 -H -1 -V -10 -H -3 -# -M -0 --1 -L -4 -9 -# -M -1 --1 -H -3 -V -10 -H -1 -# -M -0 -4 -L -2 -0 -L -4 -4 -# -M -0 -9 -H -4 -# -M -1 --1 -L -3 -1 -# -M -0 -3 -L -1 -2 -H -3 -L -4 -3 -V -8 -H -1 -L -0 -7 -V -6 -L -1 -5 -H -4 -# -M -0 -0 -V -8 -H -3 -L -4 -7 -V -3 -L -3 -2 -H -0 -# -M -4 -3 -L -3 -2 -H -1 -L -0 -3 -V -7 -L -1 -8 -H -3 -L -4 -7 -# -M -4 -0 -V -8 -H -1 -L -0 -7 -V -3 -L -1 -2 -H -4 -# -M -0 -5 -H -4 -V -3 -L -3 -2 -H -1 -L -0 -3 -V -7 -L -1 -8 -H -3 -L -4 -7 -# -M -4 -3 -H -0 -M -4 -0 -H -3 -L -2 -1 -V -8 -# -M -1 -10 -H -3 -L -4 -9 -V -2 -H -1 -L -0 -3 -V -7 -L -1 -8 -H -4 -# -M -0 -2 -H -3 -L -4 -3 -V -8 -M -0 -0 -V -8 -# -M -2 -0 -V -0 -M -4 -8 -H -0 -M -0 -2 -H -2 -V -8 -# -M -3 -0 -V -0 -M -0 -2 -H -3 -V -9 -L -2 -10 -H -0 -# -M -2 -5 -H -0 -M -4 -2 -L -2 -5 -L -4 -8 -M -0 -0 -V -8 -# -M -0 -0 -H -2 -V -7 -L -3 -8 -H -4 -# -M -2 -2 -V -8 -M -0 -8 -V -2 -H -3 -L -4 -3 -V -8 -# -M -0 -8 -V -2 -H -3 -L -4 -3 -V -8 -# -M -0 -3 -V -7 -L -1 -8 -H -3 -L -4 -7 -V -3 -L -3 -2 -H -1 -Z -# -M -0 -10 -V -2 -H -3 -L -4 -3 -V -7 -L -3 -8 -H -0 -# -M -4 -10 -V -2 -H -1 -L -0 -3 -V -7 -L -1 -8 -H -4 -# -M -0 -8 -V -2 -H -3 -L -4 -3 -V -4 -# -M -4 -3 -L -3 -2 -H -1 -L -0 -3 -V -4 -L -1 -5 -H -3 -L -4 -6 -V -7 -L -3 -8 -H -1 -L -0 -7 -# -M -4 -2 -H -0 -M -2 -0 -V -7 -L -3 -8 -H -4 -# -M -0 -2 -V -7 -L -1 -8 -H -3 -L -4 -7 -V -2 -# -M -0 -2 -V -4 -L -2 -8 -L -4 -4 -V -2 -# -M -0 -2 -V -8 -L -2 -5 -L -4 -8 -V -2 -# -M -4 -2 -L -0 -8 -M -0 -2 -L -4 -8 -# -M -0 -2 -L -1 -6 -L -2 -8 -M -4 -2 -L -3 -6 -L -2 -8 -L -1 -9 -L -0 -10 -# -M -0 -2 -H -4 -V -3 -L -0 -7 -V -8 -H -4 -# -M -4 --1 -H -3 -L -2 -0 -V -3 -L -1 -4 -H -0 -H -1 -L -2 -5 -V -9 -L -3 -10 -H -4 -# -M -2 --1 -V -10 -# -M -0 --1 -H -1 -L -2 -0 -V -3 -L -3 -4 -H -4 -H -3 -L -2 -5 -V -9 -L -1 -10 -H -0 -# -M -0 -5 -V -4 -L -1 -3 -L -3 -5 -L -4 -4 -V -3 -# diff --git a/getopt.gs b/getopt.gs new file mode 100644 index 0000000..1042385 --- /dev/null +++ b/getopt.gs @@ -0,0 +1,166 @@ +# +# ── INPUT ──────────────────────────────────────────────────────────────────── +# Reads from the global list `shlex_args` (populated by shlex_split). +# +# ── USAGE ──────────────────────────────────────────────────────────────────── +# 1. Call shlex_split on your command string. +# 2. Call getopt_init to reset state. +# 3. Call getopt in a loop, passing your optstring (e.g. "ab:c"). +# A letter followed by ':' means that option requires an argument. +# 4. After the loop, optind points at the first non-option argument. +# +# onflag { +# shlex_split "-v -o file.txt -- foo bar"; +# getopt_init; +# getopt_result = ""; +# until getopt_result == -1 { +# getopt "vo:"; +# if getopt_result == "v" { say "verbose"; } +# if getopt_result == "o" { say "output: " & optarg; } +# if getopt_result == "?" { say "unknown: " & optopt; } +# } +# # shlex_args[optind] .. shlex_args[length shlex_args] are non-option args +# } +# +# ── OUTPUTS (globals) ──────────────────────────────────────────────────────── +# getopt_result — option char found, "?" for unknown, -1 when done +# optarg — argument value for options that take one (letter + ':') +# optopt — the raw option character just examined +# optind — index of next unprocessed item in shlex_args + +var getopt_result = ""; +var optarg = ""; +var optopt = ""; +var optind = 1; + +# ── private state ───────────────────────────────────────────────────────────── +# _go_subpos: position within the current cluster arg being parsed. +# 0 → need to fetch the next arg from shlex_args +# 2+ → mid-cluster (e.g. after '-' in "-xyz", 'x' is at pos 2) +var _go_subpos = 0; + +# ── getopt_init ─────────────────────────────────────────────────────────────── +# Reset all getopt state. Call before starting a new parse. +proc getopt_init { + optind = 1; + optarg = ""; + optopt = ""; + getopt_result = ""; + _go_subpos = 0; +} + +# ── getopt ──────────────────────────────────────────────────────────────────── +# proc getopt optstring +# +# optstring e.g. "ab:cd:" +# A plain letter is a flag. Letter + ':' requires an argument. +# +# Behaviours mirroring POSIX getopt: +# -a -b -c individual flags +# -abc cluster; equivalent to -a -b -c +# -o value option with argument (separate token) +# -ovalue option with argument (joined) +# -- ends option parsing; optind advances past it +# non-option arg ends option parsing (optind points at it) +proc getopt optstring { + local arg = ""; + local c = ""; + local ci = 0; + local found = 0; + local takes_arg = 0; + local vi = 0; + + # ── Phase 1: fetch next arg when not mid-cluster ────────────────────────── + if _go_subpos == 0 { + if optind > length shlex_args { + getopt_result = -1; + } else { + arg = shlex_args[optind]; + if arg == "--" { + # explicit end-of-options marker + optind += 1; + getopt_result = -1; + } elif length arg < 2 or arg[1] != "-" { + # non-option argument: stop here, leave optind pointing at it + getopt_result = -1; + } else { + # valid option cluster, first char at position 2 + _go_subpos = 2; + } + } + } + + # ── Phase 2: consume one option character from the current cluster ──────── + if _go_subpos > 0 { + arg = shlex_args[optind]; + c = arg[_go_subpos]; + optopt = c; + optarg = ""; + + # Search optstring for c; check if the next char is ':' + found = 0; + takes_arg = 0; + ci = 1; + until ci > length $optstring or found == 1 { + if $optstring[ci] == c { + found = 1; + if ci + 1 <= length $optstring { + if $optstring[ci + 1] == ":" { + takes_arg = 1; + } + } + } + ci += 1; + } + + if found == 0 { + # ── unknown option ──────────────────────────────────────────────── + getopt_result = "?"; + if _go_subpos >= length arg { + optind += 1; + _go_subpos = 0; + } else { + _go_subpos += 1; + } + + } elif takes_arg == 1 { + # ── option with argument ────────────────────────────────────────── + if _go_subpos < length arg { + # rest of the cluster is the value e.g. -ofoo → optarg="foo" + vi = _go_subpos + 1; + until vi > length arg { + optarg &= arg[vi]; + vi += 1; + } + optind += 1; + _go_subpos = 0; + getopt_result = c; + } else { + # value is the next item e.g. -o foo → optarg="foo" + optind += 1; + if optind > length shlex_args { + # missing required argument + getopt_result = "?"; + _go_subpos = 0; + } else { + optarg = shlex_args[optind]; + optind += 1; + _go_subpos = 0; + getopt_result = c; + } + } + + } else { + # ── flag option (no argument) ───────────────────────────────────── + getopt_result = c; + if _go_subpos >= length arg { + # end of this cluster, move to next arg + optind += 1; + _go_subpos = 0; + } else { + # more letters remain in the cluster + _go_subpos += 1; + } + } + } +} diff --git a/list.gs b/list.gs index 343077a..4ee2a6f 100644 --- a/list.gs +++ b/list.gs @@ -1,179 +1,305 @@ -# Sort `LIST` in ascending order using the insertion sorting algorithm. -%define INSERTION_SORT(LIST) \ - local i = 2; \ - until i > length(LIST) { \ - local isx = LIST[i]; \ - local j = i; \ - until j <= 1 or LIST[j - 1] <= isx { \ - LIST[j] = LIST[j - 1]; \ +%define LIST_SORT(LIST) \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end < 0 { \ + end = length(LIST) + end + 1; \ + } \ + local i = start + 1; \ + until i > end { \ + local key = LIST[i]; \ + local j = i - 1; \ + until j < start or LIST[j] <= key { \ + LIST[j + 1] = LIST[j]; \ j--; \ } \ - LIST[j] = isx; \ + LIST[j + 1] = key; \ i++; \ } -# Sort `LIST` of type `TYPE` in ascending order of the value of `FIELD` using the -# insertion sorting algorithm. -%define INSERTION_SORT_BY_FIELD(TYPE,LIST,FIELD) \ - local i = 2; \ - until i > length(LIST) { \ - local TYPE isfx = LIST[i]; \ - local j = i; \ - until j <= 1 or LIST[j - 1]FIELD <= isfx FIELD { \ - LIST[j] = LIST[j - 1]; \ +%define LIST_SORT(LIST, TYPE, KEY) \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end < 0 { \ + end = length(LIST) + end + 1; \ + } \ + local i = start + 1; \ + until i > end { \ + local TYPE key = LIST[i]; \ + local j = i - 1; \ + until j < start or LIST[j].KEY <= key.KEY { \ + LIST[j + 1] = LIST[j]; \ j--; \ } \ - LIST[j] = isfx; \ + LIST[j + 1] = key; \ i++; \ } -# Count the number of elements in `LIST` that satisfy `CMP`, and store the result in -# `STORE`. local `i` is the index of the current element. -%define COUNT(LIST,CMP,STORE) \ - local STORE = 0; \ - local i = 1; \ - repeat length(LIST) { \ - if CMP { \ - STORE += 1; \ +%define LIST_JOIN(LIST) \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end < 0 { \ + end = length(LIST) + end + 1; \ + } \ + local out = ""; \ + local i = start; \ + repeat end - start + 1 { \ + if i != start { \ + out &= $sep; \ } \ + out &= LIST[i]; \ i++; \ - } + } \ + return out; -# Sum the elements in `LIST` that satisfy `CMP`, and store the result in `STORE`. -# local `i` is the index of the current element. -%define SUM(LIST,CMP,STORE) \ - local STORE = 0; \ - local i = 1; \ - repeat length(LIST) { \ - if CMP { \ - STORE += LIST[i]; \ +%define LIST_JOIN(LIST, KEY) \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end < 0 { \ + end = length(LIST) + end + 1; \ + } \ + local out = ""; \ + local i = start; \ + repeat end - start + 1 { \ + if i != start { \ + out &= $sep; \ } \ + out &= LIST[i].KEY; \ i++; \ - } + } \ + return out; -# Find the largest element in `LIST` that satisfies `CMP`, and store the result in -# `STORE`. local `i` is the index of the current element. -%define FINDMAX(LIST,CMP,STORE) \ - local STORE = "-Infinity"; \ - local i = 1; \ - repeat length(LIST) { \ - if CMP { \ - if LIST[i] > STORE { \ - STORE = LIST[i]; \ - } \ +%define LIST_SUM(LIST) \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end < 0 { \ + end = length(LIST) + end + 1; \ + } \ + local out = 0; \ + local i = start; \ + repeat end - start + 1 { \ + out += LIST[i]; \ + i++; \ + } \ + return out; + +%define LIST_SUM(LIST, KEY) \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end < 0 { \ + end = length(LIST) + end + 1; \ + } \ + local out = 0; \ + local i = start; \ + repeat end - start + 1 { \ + out += LIST[i].KEY; \ + i++; \ + } \ + return out; + +%define LIST_MIN(LIST) \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end < 0 { \ + end = length(LIST) + end + 1; \ + } \ + local out = 1/0; \ + local i = start; \ + repeat end - start + 1 { \ + if LIST[i] < out { \ + out = LIST[i]; \ } \ i++; \ - } + } \ + return out; -# Find the smallest element in `LIST` that satisfies `CMP`, and store the result in -# `STORE`. local `i` is the index of the current element. -%define FINDMIN(LIST,CMP,STORE) \ - local STORE = "Infinity"; \ - local i = 1; \ - repeat length(LIST) { \ - if CMP { \ - if LIST[i] < STORE { \ - STORE = LIST[i]; \ - } \ +%define LIST_MIN(LIST, KEY) \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end < 0 { \ + end = length(LIST) + end + 1; \ + } \ + local out = 1/0; \ + local i = start; \ + repeat end - start + 1 { \ + if LIST[i].KEY < out { \ + out = LIST[i].KEY; \ } \ i++; \ - } + } \ + return out; -# Reverse `LIST` in place. -%define REVERSE(LIST) \ - local i = 1; \ - local j = length(LIST); \ - repeat length(LIST) / 2 { \ - local x = LIST[i]; \ - LIST[i] = LIST[j]; \ - LIST[j] = x; \ +%define LIST_MAX(LIST) \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end < 0 { \ + end = length(LIST) + end + 1; \ + } \ + local out = -1/0; \ + local i = start; \ + repeat end - start + 1 { \ + if LIST[i] > out { \ + out = LIST[i]; \ + } \ i++; \ - j--; \ - } + } \ + return out; -# Copy `SRC` to `DEST`. -%define COPY(SRC,DEST) \ - delete DEST; \ - local i = 1; \ - repeat length(SRC) { \ - add SRC[i] to DEST; \ +%define LIST_MAX(LIST, KEY) \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end < 0 { \ + end = length(LIST) + end + 1; \ + } \ + local out = -1/0; \ + local i = start; \ + repeat end - start + 1 { \ + if LIST[i].KEY > out { \ + out = LIST[i].KEY; \ + } \ i++; \ + } \ + return out; + +%define LIST_REVERSE(LIST) \ + local lo = $start; \ + local hi = $end; \ + if lo < 0 { \ + lo = length(LIST) + lo + 1; \ + } \ + if hi < 0 { \ + hi = length(LIST) + hi + 1; \ + } \ + until lo >= hi { \ + local tmp = LIST[lo]; \ + LIST[lo] = LIST[hi]; \ + LIST[hi] = tmp; \ + lo++; \ + hi--; \ } -# Extend `DEST` with the elements of `SRC`. -%define EXTEND(SRC,DEST) \ - local i = 1; \ - repeat length(SRC) { \ - add SRC[i] to DEST; \ - i++; \ +%define LIST_REVERSE(TYPE, LIST) \ + local lo = $start; \ + local hi = $end; \ + if lo < 0 { \ + lo = length(LIST) + lo + 1; \ + } \ + if hi < 0 { \ + hi = length(LIST) + hi + 1; \ + } \ + until lo >= hi { \ + local TYPE tmp = LIST[lo]; \ + LIST[lo] = LIST[hi]; \ + LIST[hi] = tmp; \ + lo++; \ + hi--; \ } -# Remove duplicate elements from `LIST`. -%define UNIQUE(LIST) \ - local i = 1; \ - until i > length(LIST) { \ - local j = i + 1; \ - until j > length(LIST) { \ - if LIST[i] == LIST[j] { \ - delete LIST[j]; \ - } else { \ - j++; \ - } \ - } \ +%define LIST_COPY(SRC, DST) \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(SRC) + start + 1; \ + } \ + if end < 0 { \ + end = length(SRC) + end + 1; \ + } \ + local i = start; \ + repeat end - start + 1 { \ + add SRC[i] to DST; \ i++; \ } -# Sum the field `FIELD` in `LIST` that satisfy `CMP`, and store the result in `STORE`. -%define SUM_BY_FIELD(LIST,FIELD,CMP,STORE) \ - local STORE = 0; \ +%define LIST_EXTEND(SRC, DST) \ local i = 1; \ - repeat length(LIST) { \ - if CMP { \ - STORE += LIST[i]FIELD; \ - } \ + repeat length SRC { \ + add SRC[i] to DST; \ i++; \ } -# TODO [BLOCKED BY]: https://github.com/aspizu/goboscript/issues/71 -# Find the largest `FIELD` value in `LIST` of type `TYPE` that satisfies `CMP` and store -# the result in `STORE`. -%define FINDMAX_BY_FIELD(TYPE,LIST,FIELD,CMP,STORE) \ - local TYPE STORE; \ - STORE FIELD = "-Infinity"; \ - local i = 1; \ - repeat length(LIST) { \ - if CMP { \ - if LIST[i]FIELD > STORE FIELD { \ - STORE = LIST[i]; \ - } \ - } \ +%define LIST_EXTEND(SRC, DST) \ + local start = $start; \ + local end = $end; \ + if start < 0 { \ + start = length(SRC) + start + 1; \ + } \ + if end < 0 { \ + end = length(SRC) + end + 1; \ + } \ + local i = start; \ + repeat end - start + 1 { \ + add SRC[i] to DST; \ i++; \ } -# TODO [BLOCKED BY]: https://github.com/aspizu/goboscript/issues/71 -# Find the smallest `FIELD` value in `LIST` of type `TYPE` that satisfies `CMP` and -# store the result in `STORE`. -%define FINDMIN_BY_FIELD(TYPE,LIST,FIELD,CMP,STORE) \ - local TYPE STORE; \ - STORE FIELD = "Infinity"; \ - local i = 1; \ - repeat length(LIST) { \ - if CMP { \ - if LIST[i]FIELD < STORE FIELD { \ - STORE = LIST[i]; \ +%define LIST_UNIQUE(LIST) \ + local start = $start; \ + local end_ = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end_ < 0 { \ + end_ = length(LIST) + end_ + 1; \ + } \ + local i = start; \ + until i > end_ { \ + local j = i + 1; \ + until j > end_ { \ + if LIST[i] == LIST[j] { \ + delete LIST[j]; \ + end_--; \ + } else { \ + j++; \ } \ } \ i++; \ } -# Remove duplicate elements from `LIST` by field `FIELD`. -%define UNIQUE_BY_FIELD(LIST,FIELD) \ - local i = 1; \ - until i > length(LIST) { \ +%define LIST_UNIQUE(LIST, TYPE, KEY) \ + local start = $start; \ + local end_ = $end; \ + if start < 0 { \ + start = length(LIST) + start + 1; \ + } \ + if end_ < 0 { \ + end_ = length(LIST) + end_ + 1; \ + } \ + local i = start; \ + until i > end_ { \ local j = i + 1; \ - until j > length(LIST) { \ - if LIST[i] FIELD == LIST[j] FIELD { \ + until j > end_ { \ + if LIST[i].KEY == LIST[j].KEY { \ delete LIST[j]; \ + end_--; \ } else { \ j++; \ } \ diff --git a/math.gs b/math.gs index e77d17e..c28dacc 100644 --- a/math.gs +++ b/math.gs @@ -1,71 +1,63 @@ %define PI 3.141592653589793 + %define E 2.718281828459045 -%define SQRT2 1.4142135623730951 -# Return the minimum of `A` and `B`. -%define MIN(A,B) ((A) - ((A) - (B)) * ((A) > (B))) +%define MIN(A,B) ((A)+(((A)>(B))*((B)-(A)))) -# Return the maximum of `A` and `B`. -%define MAX(A,B) ((A) + ((B) - (A)) * ((A) < (B))) +%define MAX(A,B) ((A)+(((A)<(B))*((B)-(A)))) -# Combine RGB values into a single value for use with the `set_pen_color` block. -%define RGB(R,G,B) (((R) * 65536) + ((G) * 256) + (B)) +%define RGB(R, G, B) (((R)*65536)+((G)*256)+(B)) -# Combine RGBA values into a single value for use with the `set_pen_color` block. -%define RGBA(R,G,B,A) (((R) * 65536) + ((G) * 256) + (B) + ((A) * 16777216)) +%define RGBA(R, G, B, A) (((R)*65536)+((G)*256)+(B)+((A)*16777216)) -# Parse a hexadecimal value. %define HEX(VALUE) (("0x"&(VALUE))+0) -# Parse a binary value. %define BIN(VALUE) (("0b"&(VALUE))+0) -# Parse a octal value. %define OCT(VALUE) (("0o"&(VALUE))+0) +%define SIGN(VALUE) (((VALUE)>0)-((VALUE)<0)) + %define ACOSH(X) ln((X)+sqrt((X)*(X)-1)) + %define ASINH(X) ln((X)+sqrt((X)*(X)+1)) + %define ATANH(X) ln((1+(X))/(1-(X)))/2 + %define COSH(X) ((antiln(X)+antiln(-(X)))/2) + %define SINH(X) ((antiln(X)-antiln(-(X)))/2) -%define TANH(X) ((antiln(X)-antiln(-(X)))/(antiln(X)+antiln(-(X)))) -# Return the distance between the points `(X1,Y1)` and `(X2,Y2)`. -%define DIST(X1,Y1,X2,Y2) sqrt(((X2)-(X1))*((X2)-(X1))+((Y2)-(Y1))*((Y2)-(Y1))) +%define TANH(X) ((antiln(X)-antiln(-(X)))/(antiln(X)+antiln(-(X)))) -# Return the magnitude of the vector `(X,Y)`. %define MAG(X,Y) sqrt((X)*(X)+(Y)*(Y)) -# Return `BASE` raised to the power of `EXP`. +%define DIST(X1, Y1, X2, Y2) MAG(X2-X1,Y2-Y1) + +%define RAD(DEG) ((DEG) * 0.017453292519943295) + +%define DEG(RAD) ((RAD) * 57.29577951308232) + %define POW(BASE,EXP) antiln(ln(BASE)*(EXP)) -# Gamma correct `VALUE` with power 2.2 -%define GAMMA(VALUE) antiln(ln(VALUE)/2.2) +%define ROOT(BASE,N) antiln(ln(BASE)/(N)) -# Clamp `VALUE` above zero. (Returns 0 for `VALUE` < 0) -%define POSITIVE_CLAMP(VALUE) (((VALUE)>0)*(VALUE)) +%define LOG(VAL,BASE) (ln(VAL)/ln(BASE)) -# Clamp `VALUE` below zero. (Returns 0 for `VALUE` > 0) -%define NEGATIVE_CLAMP(VALUE) (((VALUE)<0)*(VALUE)) +%define LERP(T,OUT0,OUT1) ((OUT0)+(T)*((OUT1)-(OUT0))) -# Clamp `VALUE` between `MIN` and `MAX`. -# (Returns `MIN` for `VALUE` < `MIN`, `MAX` for `VALUE` > `MAX`) -%define CLAMP(VALUE,MIN,MAX) (((VALUE)>(MIN))*((MAX)+((VALUE)-(MAX))*((VALUE)<(MAX)))) +%define INVLERP(VAL,IN0,IN1) (((VAL)-(IN0))/((IN1)-(IN0))) -# Return the `N`th bit of `V`'s binary representation. -%define BIT(N,V) (((V) // antiln((N) * ln 2) % 2)) +%define REMAP(T,IN0,IN1,OUT0,OUT1) (LERP(INVLERP(IN0,IN1,T),OUT0,OUT1)) -# Linearly interpolate between `A` and `B` by `T`. -%define LERP(A,B,T) ((A)+((B)-(A))*(T)) +%define CLAMP(VAL,MIN,MAX) ((MAX)-(((MAX)-((((VAL)-(MIN))*((VAL)>(MIN)))+ (MIN)))*((VAL)<(MAX)))) -# Work out the ratio of `VAL` from `A` to `B`. -%define INVLERP(VAL,A,B) ((VAL) - (A)) / ((B) - (A)) +%define POSITIVE_CLAMP(VAL) (((VAL)>0)*(VAL)) -# Re-maps a `V` from the range `A` to `B` to the range `C` to `D`. -%define MAP(A,B,C,D,V) (((V)-(B))*((D)-(C))/((A)-(B))+(C)) +%define NEGATIVE_CLAMP(VALUE) (((VALUE)<0)*(VALUE)) -# Convert degrees to radians. -%define RAD(DEG) ((DEG) * 0.017453292519943295) +%define RANDOM() random("0.0", "1.0") -# Convert radians to degrees. -%define DEG(RAD) ((RAD) * 57.29577951308232) +%define RANDOM_ANGLE() random("0.0", "360.0") + +%define APPROX(A,B,TOLERANCE) (abs((B)-(A)) < (TOLERANCE)) diff --git a/md5.gs b/md5.gs new file mode 100644 index 0000000..3d7bfd4 --- /dev/null +++ b/md5.gs @@ -0,0 +1,246 @@ +# +# DEPENDS ON: the bitwise library providing: +# XOR32, AND32, OR32, NOT32, ADD32 (macros) +# rol32(a, b) (function) +# xor4, and4, or4 (lookup lists, must be pre-populated) +# +# USAGE: +# 1. Populate md5_input with one byte per item. +# 2. Call md5. +# 3. Read 16 bytes from md5_output. +# +# INPUT LIST: md5_input — one byte (0‥255) per item +# OUTPUT LIST: md5_output — 16 bytes, little-endian (H0 H1 H2 H3) + +list md5_input; +list md5_output; + +proc md5_input_encode_ascii text { + BYTES_ENCODE_ASCII(md5_input) +} + +func md5_output_decode_hex(start=1, end=-1) { + BYTES_DECODE_HEX(md5_output) +} + +# ── private state ───────────────────────────────────────────────────────────── +list _md5_M; # 16 x 32-bit words for the current 512-bit chunk +list _md5_padded; # padded copy of md5_input + +var _md5_H0 = 0; # hash state words +var _md5_H1 = 0; +var _md5_H2 = 0; +var _md5_H3 = 0; + +var _md5_a = 0; # working variables +var _md5_b = 0; +var _md5_c = 0; +var _md5_d = 0; +var _md5_F = 0; # round function output / accumulator +var _md5_g = 0; # message word index for current round +var _md5_i = 0; # round counter +var _md5_temp = 0; +var _md5_chunk = 0; +var _md5_nchunks = 0; + +# ── _md5_init_tables ────────────────────────────────────────────────────────── +list _md5_K = [ # 64 round constants floor(2^32 * |sin(i+1)|) + 0xd76aa478, 0xe8c7b756, + 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, + 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, + 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, + 0xa679438e, 0x49b40821, + # Round 2 (i = 16..31) + 0xf61e2562, 0xc040b340, + 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, + 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, + 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, + 0x676f02d9, 0x8d2a4c8a, + # Round 3 (i = 32..47) + 0xfffa3942, 0x8771f681, + 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, + 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, + 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, + 0x1fa27cf8, 0xc4ac5665, + # Round 4 (i = 48..63) + 0xf4292244, 0x432aff97, + 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, + 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, + 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, + 0x2ad7d2bb, 0xeb86d391 +]; + +list _md5_s = [ # 64 per-round left-rotate amounts + # Round 1 + 7, 12, 17, 22, + 7, 12, 17, 22, + 7, 12, 17, 22, + 7, 12, 17, 22, + # Round 2 + 5, 9, 14, 20, + 5, 9, 14, 20, + 5, 9, 14, 20, + 5, 9, 14, 20, + # Round 3 + 4, 11, 16, 23, + 4, 11, 16, 23, + 4, 11, 16, 23, + 4, 11, 16, 23, + # Round 4 + 6, 10, 15, 21, + 6, 10, 15, 21, + 6, 10, 15, 21, + 6, 10, 15, 21 +]; + +# ── _md5_pad_msg ────────────────────────────────────────────────────────────── +# Copies md5_input into _md5_padded then applies RFC 1321 Section 3.1-3.2 padding: +# 1. Append 0x80. +# 2. Append 0x00 bytes until length ≡ 56 (mod 64). +# 3. Append the original bit-length as a 64-bit little-endian integer. +# +# The bit-length is split into two 32-bit halves to stay within JS double +# precision: lo = (msglen % 2^29) * 8, hi = msglen // 2^29 +proc _md5_pad_msg { + local msglen = length md5_input; + local bitlen_lo = (msglen % 0x20000000) * 8; + local bitlen_hi = msglen // 0x20000000; + local i = 1; + + delete _md5_padded; + + repeat msglen { + add md5_input[i] to _md5_padded; + i += 1; + } + + add 0x80 to _md5_padded; + + until length _md5_padded % 64 == 56 { + add 0 to _md5_padded; + } + + # low 32 bits of bit-length + add bitlen_lo % 0x100 to _md5_padded; + add (bitlen_lo // 0x100) % 0x100 to _md5_padded; + add (bitlen_lo // 0x10000) % 0x100 to _md5_padded; + add (bitlen_lo // 0x1000000) % 0x100 to _md5_padded; + # high 32 bits of bit-length + add bitlen_hi % 0x100 to _md5_padded; + add (bitlen_hi // 0x100) % 0x100 to _md5_padded; + add (bitlen_hi // 0x10000) % 0x100 to _md5_padded; + add (bitlen_hi // 0x1000000) % 0x100 to _md5_padded; +} + +# ── _md5_process_chunk ──────────────────────────────────────────────────────── +# Processes one 512-bit (64-byte) chunk. +# base: 1-based start index into _md5_padded. +proc _md5_process_chunk base { + local wi = 0; + local bi = 0; + + # Unpack 64 bytes -> 16 little-endian 32-bit words in _md5_M + delete _md5_M; + wi = 0; + repeat 16 { + bi = $base + wi * 4; + add _md5_padded[bi] + + _md5_padded[bi + 1] * 0x100 + + _md5_padded[bi + 2] * 0x10000 + + _md5_padded[bi + 3] * 0x1000000 + to _md5_M; + wi += 1; + } + + # Initialise working variables from current hash state + _md5_a = _md5_H0; + _md5_b = _md5_H1; + _md5_c = _md5_H2; + _md5_d = _md5_H3; + + # 64 rounds + _md5_i = 0; + repeat 64 { + if _md5_i < 16 { + # Round 1 — F(b,c,d) = (b AND c) OR (NOT b AND d) + _md5_F = or32(and32(_md5_b, _md5_c), and32(not32(_md5_b), _md5_d)); + _md5_g = _md5_i; + } elif _md5_i < 32 { + # Round 2 — G(b,c,d) = (d AND b) OR (NOT d AND c) + _md5_F = or32(and32(_md5_d, _md5_b), and32(not32(_md5_d), _md5_c)); + _md5_g = (5 * _md5_i + 1) % 16; + } elif _md5_i < 48 { + # Round 3 — H(b,c,d) = b XOR c XOR d + _md5_F = xor32(xor32(_md5_b, _md5_c), _md5_d); + _md5_g = (3 * _md5_i + 5) % 16; + } else { + # Round 4 — I(b,c,d) = c XOR (b OR NOT d) + _md5_F = xor32(_md5_c, or32(_md5_b, not32(_md5_d))); + _md5_g = (7 * _md5_i) % 16; + } + + # temp = b + ROL32(a + F + K[i] + M[g], s[i]) + _md5_F = add32( + add32(add32(_md5_a, _md5_F), _md5_K[_md5_i + 1]), + _md5_M[_md5_g + 1]); + _md5_temp = _md5_d; + _md5_d = _md5_c; + _md5_c = _md5_b; + _md5_b = add32(_md5_b, rol32(_md5_F, _md5_s[_md5_i + 1])); + _md5_a = _md5_temp; + + _md5_i += 1; + } + + # Add working variables back into hash state + _md5_H0 = add32(_md5_H0, _md5_a); + _md5_H1 = add32(_md5_H1, _md5_b); + _md5_H2 = add32(_md5_H2, _md5_c); + _md5_H3 = add32(_md5_H3, _md5_d); +} + +# ── _md5_emit_word ──────────────────────────────────────────────────────────── +# Appends a 32-bit word to md5_output as 4 little-endian bytes. +proc _md5_emit_word w { + add $w % 0x100 to md5_output; + add ($w // 0x100) % 0x100 to md5_output; + add ($w // 0x10000) % 0x100 to md5_output; + add ($w // 0x1000000) % 0x100 to md5_output; +} + +# ── md5 ─────────────────────────────────────────────────────────────────────── +# Entry point. Reads md5_input, writes 16 bytes to md5_output. +proc md5 { + _md5_pad_msg; + + # RFC 1321 Section 3.3 — initial hash values + _md5_H0 = 0x67452301; + _md5_H1 = 0xefcdab89; + _md5_H2 = 0x98badcfe; + _md5_H3 = 0x10325476; + + _md5_nchunks = length _md5_padded // 64; + _md5_chunk = 0; + repeat _md5_nchunks { + _md5_process_chunk _md5_chunk * 64 + 1; + _md5_chunk += 1; + } + + delete md5_output; + _md5_emit_word _md5_H0; + _md5_emit_word _md5_H1; + _md5_emit_word _md5_H2; + _md5_emit_word _md5_H3; +} diff --git a/sha256.gs b/sha256.gs new file mode 100644 index 0000000..0b0995c --- /dev/null +++ b/sha256.gs @@ -0,0 +1,258 @@ +# sha256.gs — SHA-256 (FIPS 180-4) for goboscript +# +# DEPENDS ON: bitwise library providing: +# XOR32, AND32, OR32, NOT32, ADD32 (macros) +# rol32(a, b) (function) +# xor4, and4, or4 (lookup lists, pre-populated) +# +# USAGE: +# 1. Populate sha256_input with one byte (0-255) per item. +# 2. Call sha256. +# 3. Read 32 bytes from sha256_output (big-endian, standard byte order). +# +# INPUT LIST: sha256_input — one byte per item +# OUTPUT LIST: sha256_output — 32 bytes, big-endian + +list sha256_input; +list sha256_output; + +proc sha256_input_encode_ascii text { + BYTES_ENCODE_ASCII(sha256_input) +} + +func sha256_output_decode_hex(start=1, end=-1) { + BYTES_DECODE_HEX(sha256_output) +} + +# ── private state ───────────────────────────────────────────────────────────── +list _sha_W; # 64-word message schedule +list _sha_padded; # padded copy of sha256_input + +var _sha_H0 = 0; +var _sha_H1 = 0; +var _sha_H2 = 0; +var _sha_H3 = 0; +var _sha_H4 = 0; +var _sha_H5 = 0; +var _sha_H6 = 0; +var _sha_H7 = 0; + +var _sha_a = 0; +var _sha_b = 0; +var _sha_c = 0; +var _sha_d = 0; +var _sha_e = 0; +var _sha_f = 0; +var _sha_g = 0; +var _sha_h = 0; + +var _sha_i = 0; +var _sha_T1 = 0; +var _sha_T2 = 0; +var _sha_S0 = 0; +var _sha_S1 = 0; +var _sha_ch = 0; +var _sha_maj = 0; +var _sha_chunk = 0; +var _sha_nchunks = 0; + +# ── SHA-256 helpers (using ror32 via rol32) ─────────────────────────────────── +# ror32(x, n) = rol32(x, 32-n) +# These are inlined as macros for speed. + +# BSIG0(x) = ROTR2(x) XOR ROTR13(x) XOR ROTR22(x) +%define SHA_BSIG0(X) xor32(xor32(rol32((X),30),rol32((X),19)),rol32((X),10)) +# BSIG1(x) = ROTR6(x) XOR ROTR11(x) XOR ROTR25(x) +%define SHA_BSIG1(X) xor32(xor32(rol32((X),26),rol32((X),21)),rol32((X),7)) +# SSIG0(x) = ROTR7(x) XOR ROTR18(x) XOR SHR3(x) +%define SHA_SSIG0(X) xor32(xor32(rol32((X),25),rol32((X),14)),(X)//8) +# SSIG1(x) = ROTR17(x) XOR ROTR19(x) XOR SHR10(x) +%define SHA_SSIG1(X) xor32(xor32(rol32((X),15),rol32((X),13)),(X)//1024) +# CH(e,f,g) = (e AND f) XOR (NOT e AND g) +%define SHA_CH(E,F,G) xor32(and32((E),(F)),and32(not32(E),(G))) +# MAJ(a,b,c) = (a AND b) XOR (a AND c) XOR (b AND c) +%define SHA_MAJ(A,B,C) xor32(xor32(and32((A),(B)),and32((A),(C))),and32((B),(C))) + +# ── _sha_init_K ─────────────────────────────────────────────────────────────── +list _sha_K = [ # 64 round constants + 0x428a2f98, 0x71374491, + 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, + 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, + 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, + 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, + 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, + 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, + 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, + 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, + 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, + 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, + 0xbef9a3f7, 0xc67178f2 +]; + +# ── _sha_pad_msg ────────────────────────────────────────────────────────────── +# SHA-256 padding: same structure as MD5 but big-endian length field. +proc _sha_pad_msg { + local msglen = length sha256_input; + local bitlen_lo = (msglen % 0x20000000) * 8; + local bitlen_hi = msglen // 0x20000000; + local i = 1; + + delete _sha_padded; + + repeat msglen { + add sha256_input[i] to _sha_padded; + i += 1; + } + + add 0x80 to _sha_padded; + + until length _sha_padded % 64 == 56 { + add 0 to _sha_padded; + } + + # 64-bit bit-length, big-endian (high word first) + add (bitlen_hi // 0x1000000) % 0x100 to _sha_padded; + add (bitlen_hi // 0x10000) % 0x100 to _sha_padded; + add (bitlen_hi // 0x100) % 0x100 to _sha_padded; + add bitlen_hi % 0x100 to _sha_padded; + add (bitlen_lo // 0x1000000) % 0x100 to _sha_padded; + add (bitlen_lo // 0x10000) % 0x100 to _sha_padded; + add (bitlen_lo // 0x100) % 0x100 to _sha_padded; + add bitlen_lo % 0x100 to _sha_padded; +} + +# ── _sha_process_chunk ──────────────────────────────────────────────────────── +proc _sha_process_chunk base { + local wi = 0; + local bi = 0; + + # Unpack 16 big-endian 32-bit words from the 64-byte chunk + delete _sha_W; + wi = 0; + repeat 16 { + bi = $base + wi * 4; + add _sha_padded[bi] * 0x1000000 + + _sha_padded[bi + 1] * 0x10000 + + _sha_padded[bi + 2] * 0x100 + + _sha_padded[bi + 3] + to _sha_W; + wi += 1; + } + + # Extend to 64 words + wi = 17; + repeat 48 { + add add32(add32(add32( + SHA_SSIG1(_sha_W[wi - 2]), + _sha_W[wi - 7]), + SHA_SSIG0(_sha_W[wi - 15])), + _sha_W[wi - 16]) + to _sha_W; + wi += 1; + } + + # Initialise working variables + _sha_a = _sha_H0; + _sha_b = _sha_H1; + _sha_c = _sha_H2; + _sha_d = _sha_H3; + _sha_e = _sha_H4; + _sha_f = _sha_H5; + _sha_g = _sha_H6; + _sha_h = _sha_H7; + + # 64 rounds + _sha_i = 1; + repeat 64 { + _sha_T1 = add32(add32(add32(add32( + _sha_h, + SHA_BSIG1(_sha_e)), + SHA_CH(_sha_e, _sha_f, _sha_g)), + _sha_K[_sha_i]), + _sha_W[_sha_i]); + _sha_T2 = add32(SHA_BSIG0(_sha_a), SHA_MAJ(_sha_a, _sha_b, _sha_c)); + + _sha_h = _sha_g; + _sha_g = _sha_f; + _sha_f = _sha_e; + _sha_e = add32(_sha_d, _sha_T1); + _sha_d = _sha_c; + _sha_c = _sha_b; + _sha_b = _sha_a; + _sha_a = add32(_sha_T1, _sha_T2); + + _sha_i += 1; + } + + _sha_H0 = add32(_sha_H0, _sha_a); + _sha_H1 = add32(_sha_H1, _sha_b); + _sha_H2 = add32(_sha_H2, _sha_c); + _sha_H3 = add32(_sha_H3, _sha_d); + _sha_H4 = add32(_sha_H4, _sha_e); + _sha_H5 = add32(_sha_H5, _sha_f); + _sha_H6 = add32(_sha_H6, _sha_g); + _sha_H7 = add32(_sha_H7, _sha_h); +} + +# ── _sha_emit_word ───────────────────────────────────────────────────────────── +# Appends a 32-bit word to sha256_output as 4 big-endian bytes. +proc _sha_emit_word w { + add ($w // 0x1000000) % 0x100 to sha256_output; + add ($w // 0x10000) % 0x100 to sha256_output; + add ($w // 0x100) % 0x100 to sha256_output; + add $w % 0x100 to sha256_output; +} + +# ── sha256 ──────────────────────────────────────────────────────────────────── +# Entry point. Reads sha256_input, writes 32 bytes to sha256_output. +proc sha256 { + _sha_pad_msg; + + # FIPS 180-4 §5.3.3 — initial hash values (first 32 bits of fractional + # parts of square roots of the first 8 primes) + _sha_H0 = 0x6a09e667; + _sha_H1 = 0xbb67ae85; + _sha_H2 = 0x3c6ef372; + _sha_H3 = 0xa54ff53a; + _sha_H4 = 0x510e527f; + _sha_H5 = 0x9b05688c; + _sha_H6 = 0x1f83d9ab; + _sha_H7 = 0x5be0cd19; + + _sha_nchunks = length _sha_padded // 64; + _sha_chunk = 0; + repeat _sha_nchunks { + _sha_process_chunk _sha_chunk * 64 + 1; + _sha_chunk += 1; + } + + delete sha256_output; + _sha_emit_word _sha_H0; + _sha_emit_word _sha_H1; + _sha_emit_word _sha_H2; + _sha_emit_word _sha_H3; + _sha_emit_word _sha_H4; + _sha_emit_word _sha_H5; + _sha_emit_word _sha_H6; + _sha_emit_word _sha_H7; +} diff --git a/shlex.gs b/shlex.gs new file mode 100644 index 0000000..0993a99 --- /dev/null +++ b/shlex.gs @@ -0,0 +1,104 @@ +# +# USAGE +# Include this file in your project and call: +# +# parse_args "git commit -m 'fix bug' --author=\"Jane\""; +# +# Parsed tokens are stored in the global list `args`: +# args[1] => "git" +# args[2] => "commit" +# args[3] => "-m" +# args[4] => "fix bug" +# args[5] => "--author=Jane" +# +# SYNTAX SUPPORTED +# Unquoted tokens — delimited by spaces +# Single quotes — everything inside is literal, no escapes +# Double quotes — spaces preserved; backslash escapes work inside +# Backslash — outside quotes, escapes the next character (e.g. '\ ' => ' ') +# Adjacent quoting — foo"bar"'baz' => foobarbaz (quotes can be concatenated) +# +# GLOBAL OUTPUTS +# list args — holds one token per index after parse_args returns + +list shlex_args; + + +# ── parse_args ──────────────────────────────────────────────────────────────── +# proc parse_args str +# str — the raw input string to tokenise +# +# Clears `args` before filling it. Unclosed quotes consume until end-of-string +# (same lenient behaviour as most interactive shells). + +proc shlex_split str { + delete shlex_args; + + local _pa_i = 1; + local _pa_len = length $str; + local _pa_cur = ""; + local _pa_in_sq = 0; + local _pa_in_dq = 0; + + until _pa_i > _pa_len { + local _pa_c = $str[_pa_i]; + + # ── inside single quotes ────────────────────────────────────────────── + # Nothing is special except the closing quote. + if _pa_in_sq == 1 { + if _pa_c == "'" { + _pa_in_sq = 0; + } else { + _pa_cur &= _pa_c; + } + + # ── inside double quotes ────────────────────────────────────────────── + # Backslash escapes the next character; everything else is literal. + } elif _pa_in_dq == 1 { + if _pa_c == "\"" { + _pa_in_dq = 0; + } elif _pa_c == "\\" { + _pa_i += 1; + if _pa_i <= _pa_len { + _pa_cur &= $str[_pa_i]; + } + } else { + _pa_cur &= _pa_c; + } + + # ── unquoted ────────────────────────────────────────────────────────── + } elif _pa_c == "'" { + # Enter single-quote mode (may continue current token). + _pa_in_sq = 1; + + } elif _pa_c == "\"" { + # Enter double-quote mode (may continue current token). + _pa_in_dq = 1; + + } elif _pa_c == "\\" { + # Backslash outside quotes: take the next character literally. + _pa_i += 1; + if _pa_i <= _pa_len { + _pa_cur &= $str[_pa_i]; + } + + } elif _pa_c == " " { + # Space: flush current token if non-empty. + if length _pa_cur > 0 { + add _pa_cur to shlex_args; + _pa_cur = ""; + } + + } else { + # Ordinary character. + _pa_cur &= _pa_c; + } + + _pa_i += 1; + } + + # Flush the final token (handles no-trailing-space and unclosed quotes). + if length _pa_cur > 0 { + add _pa_cur to shlex_args; + } +} diff --git a/string.gs b/string.gs index d65c89f..779fef9 100644 --- a/string.gs +++ b/string.gs @@ -6,117 +6,102 @@ list strbuf; -# Slice $text from $start to $end, $end is exclusive. $start and $end are 1-based. -func slice(text, start, end) { - delete strbuf; - repeat $end - $start { - add $text[$start + length(strbuf)] to strbuf; +# Returns a substring of $text from $start to $end (inclusive). +# Negative indices count from the end of the string (-1 = last character). +# If $start or $end are out of bounds, they are clamped to the string length. +# If the range is invalid, an empty string is returned. +# +# @param {string} text - The string to slice. +# @param {number} start - The start index (default: 1). +# @param {number} end - The end index, inclusive (default: -1). +# @returns {string} The substring, or "" if the range is invalid. +# +# @example str_slice("hello", 2, 4) => "ell" +# @example str_slice("hello", -3) => "llo" +# @example str_slice("hello", 2) => "ello" +# @example str_slice("hello") => "hello" +func str_slice(text, start=1, end=-1) { + local start = $start; + local end = $end; + if start < 0 { + start = length($text) + start + 1; + } + if end < 0 { + end = length($text) + end + 1; + } + if start < 1 { + start = 1; + } + if end > length($text) { + end = length($text); + } + if end < 1 or start > length($text) or end < start { + return ""; } - return strbuf; -} - -# Conditional macro to check if $text starts with $prefix. -%define ENDSWITH(TEXT,SUFFIX) \ - (slice((TEXT), 1 + (length(TEXT) - length(SUFFIX)), 1 + length(TEXT)) == (SUFFIX)) - -# Conditional macro to check if $text starts with $prefix. -%define STARTSWITH(TEXT,PREFIX) \ - (slice((TEXT), 1, 1 + length(PREFIX)) == (PREFIX)) - -# Remove $prefix from the beginning of $text. -%define REMOVEPREFIX(TEXT,PREFIX) (splice((TEXT), 1, length(PREFIX), "")) - -# Remove $suffix from the end of $text. -%define REMOVESUFFIX(TEXT,SUFFIX) \ - (splice(TEXT, 1 + (length(TEXT) - length(SUFFIX)), length(SUFFIX), "")) - -# Replace all occurrences of $subtext with $repl in $text. -func replace(text, subtext, repl) { - local i = 1; - local result = ""; delete strbuf; - until i > length($text) { - add $text[i] to strbuf; - if contains(strbuf, $subtext) { - repeat length($subtext) { - delete strbuf["last"]; - } - result &= strbuf & $repl; - delete strbuf; - } - i++; + repeat end - start + 1 { + add $text[start + length(strbuf)] to strbuf; } - return result & strbuf; + return strbuf; } -# Replace first $n occurrences of $subtext with $repl in $text. -func replacen(text, subtext, repl, n) { - local i = 1; - local n = 0; - local result = ""; - delete strbuf; - until i > length($text) { - add $text[i] to strbuf; - if contains(strbuf, $subtext) { - if n < $n { - repeat length($subtext) { - delete strbuf["last"]; - } - result &= strbuf & $repl; - } else { - result &= strbuf; - } - delete strbuf; - n++; - } - i++; - } - return result & strbuf; +# Returns true if $text ends with the given $suffix, false otherwise. +# The check is NOT case-sensitive. +# +# @param {string} text - The string to check. +# @param {string} suffix - The suffix to look for at the end of $text. +# @returns {boolean} True if $text ends with $suffix, false otherwise. +# +# @example str_ends_with("hello", "lo") => true +# @example str_ends_with("hello", "he") => false +# @example str_ends_with("hello", "") => true +func str_ends_with(text, suffix) { + if $suffix == "" { return true; } + return str_slice($text, -length($suffix)) == $suffix; } -# Replace the $n-th occurrence of $subtext with $repl in $text. -func replacenth(text, subtext, repl, n) { - local i = 1; - local n = 1; - local result = ""; - delete strbuf; - until i > length($text) { - add $text[i] to strbuf; - if contains(strbuf, $subtext) { - if n == $n { - repeat length($subtext) { - delete strbuf["last"]; - } - result &= strbuf & $repl; - } else { - result &= strbuf; - } - delete strbuf; - n++; - } - i++; - } - return result & strbuf; +# Returns true if $text begins with the given $prefix, false otherwise. +# The check is NOT case-sensitive. +# +# @param {string} text - The string to check. +# @param {string} prefix - The prefix to look for at the start of $text. +# @returns {boolean} True if $text starts with $prefix, false otherwise. +# +# @example str_starts_with("hello", "he") => true +# @example str_starts_with("hello", "lo") => false +# @example str_starts_with("hello", "") => true +func str_starts_with(text, prefix) { + return str_slice($text, 1, length($prefix)) == $prefix; } -# Remove $len characters from $text starting at $start and insert $repl in its place. -func splice(text, start, len, repl) { - delete strbuf; - repeat $start - 1 { - add $text[1+length(strbuf)] to strbuf; - } - local result = strbuf & $repl; +# Returns a copy of $text with its characters in reverse order. +# +# @param {string} text - The string to reverse. +# @returns {string} The reversed string. +# +# @example str_reverse("hello") => "olleh" +# @example str_reverse("abcd") => "dcba" +# @example str_reverse("") => "" +func str_reverse(text) { delete strbuf; - local i = $start + $len; - repeat 1 + (length($text) - ($start + $len)) { - add $text[i] to strbuf; + local i = 1; + repeat length($text) { + add $text[1+length($text)-i] to strbuf; i++; } - return result & strbuf; + return strbuf; } -# Transform ASCII letters in $text to uppercase. -func uppercase(text) { +# Returns a copy of $text with all ASCII lowercase letters converted to uppercase. +# Non-alphabetic characters are left unchanged. +# +# @param {string} text - The string to convert. +# @returns {string} The uppercased string. +# +# @example str_upper("hello") => "HELLO" +# @example str_upper("Hello!") => "HELLO!" +# @example str_upper("123") => "123" +func str_upper(text) { delete strbuf; repeat length($text) { local i = 1; @@ -132,8 +117,16 @@ func uppercase(text) { return strbuf; } -# Transform ASCII letters in $text to lowercase. -func lowercase(text) { +# Returns a copy of $text with all ASCII uppercase letters converted to lowercase. +# Non-alphabetic characters are left unchanged. +# +# @param {string} text - The string to convert. +# @returns {string} The lowercased string. +# +# @example str_lower("HELLO") => "hello" +# @example str_lower("Hello!") => "hello!" +# @example str_lower("123") => "123" +func str_lower(text) { delete strbuf; repeat length($text) { local i = 1; @@ -149,8 +142,16 @@ func lowercase(text) { return strbuf; } -# Transform the first character in $text to uppercase, and the rest to lowercase -func capitalize(text) { +# Returns a copy of $text with the first character uppercased and all +# remaining characters lowercased. Non-alphabetic characters are unchanged. +# +# @param {string} text - The string to capitalize. +# @returns {string} The capitalized string. +# +# @example str_capitalize("hello") => "Hello" +# @example str_capitalize("HELLO") => "Hello" +# @example str_capitalize("hELLO wORLD") => "Hello world" +func str_capitalize(text) { delete strbuf; local i = 1; until $text[1] == ASCII_UPPERCASE[i] or i > 26 { @@ -175,39 +176,85 @@ func capitalize(text) { return strbuf; } -# Return the index of the first occurrence of $char in $text, or 0 if not found. -func findchar(text, char) { +# Returns a copy of $text in title case: the first letter of each word is +# uppercased and subsequent letters are lowercased. A "word" is defined as +# a sequence of ASCII alphabetic characters; non-alpha characters act as +# word boundaries and are passed through unchanged. +# +# @param {string} text - The string to convert to title case. +# @returns {string} The title-cased string. +# +# @example str_title("hello world") => "Hello World" +# @example str_title("HELLO WORLD") => "Hello World" +# @example str_title("it's a test") => "It'S A Test" +func str_title(text) { + local result = ""; local i = 1; + local boundary = false; repeat length($text) { - if $text[i] == $char { - return i; + local j = 1; + until $text[i] == ASCII_UPPERCASE[j] or j > 26 { + j++; + } + if j > 26 { + boundary = false; + result &= $text[i]; + } else { + if boundary == false { + boundary = true; + result &= ASCII_UPPERCASE[j]; + } else { + result &= ASCII_LOWERCASE[j]; + } } i++; } - return 0; + return result; } -# Return the index of the last occurrence of $char in $text, or 0 if not found. -func rfindchar(text, char) { - local i = length($text); - repeat length($text) { - if $text[i] == $char { - return i; - } - i--; +# Returns a new string consisting of $text repeated $n times. +# If $n is 0 or negative, an empty string is returned. +# +# @param {string} text - The string to repeat. +# @param {number} n - The number of times to repeat $text. +# @returns {string} The repeated string. +# +# @example str_repeat("ab", 3) => "ababab" +# @example str_repeat("hi", 1) => "hi" +# @example str_repeat("x", 0) => "" +func str_repeat(text, n) { + local result = ""; + repeat $n { + result &= $text; } - return 0; + return result; } -# Return true if all characters in $text are alphanumeric and there is at least one -# character. -func isalnum(text) { - if length($text) == 0 { +# Returns true if strings $a and $b are equal (same length and identical +# characters), false otherwise. Uses costume-switching to perform an +# ordinal character-by-character comparison: each character is mapped to +# its corresponding ASCII costume index, allowing exact case-sensitive +# matching for all printable ASCII characters. +# Requires costumes to be defined with: +# costumes "blank.svg" as "@ascii/"; +# +# @param {string} a - The first string to compare. +# @param {string} b - The second string to compare. +# @returns {boolean} True if $a and $b are identical, false otherwise. +# +# @example str_eq("hello", "hello") => true +# @example str_eq("hello", "Hello") => false +# @example str_eq("abc", "ab") => false +func str_eq(a, b) { + if length($a) != length($b) { return false; } local i = 1; - repeat length($text) { - if $text[i] not in ASCII_UPPERCASE & ASCII_DIGITS { + repeat length($a) { + switch_costume $a; + local c = costume_number(); + switch_costume $b; + if c != costume_number() { return false; } i++; @@ -215,27 +262,120 @@ func isalnum(text) { return true; } -# Return true if all characters in $text are alphabetic and there is at least one -# character. -func isalpha(text) { - if length($text) == 0 { - return false; +# Splits $text into a list of substrings separated by $sep and stores the +# result in the list `str_split`. Consecutive separators produce +# empty-string entries. If $sep does not appear, `str_split` contains +# only $text as its single item. +# +# @param {string} text - The string to split. +# @param {string} sep - The separator character (default: " "). +# @returns {void} Results are stored in the list `str_split`. +# +# @example str_split "a,b,c", ","; => str_split = ["a", "b", "c"] +# @example str_split "hello"; => str_split = ["hello"] +# @example str_split "a,,b", ","; => str_split = ["a", "", "b"] +list str_split; + +proc str_split text, sep=" " { + delete str_split; + delete strbuf; + local i = 1; + repeat length($text) { + if $text[i] == $sep { + add strbuf to str_split; + delete strbuf; + } else { + add $text[i] to strbuf; + } + i++; } + add strbuf to str_split; +} + +# Splits $text into individual lines using LF (\n) as line +# endings and stores the result in the list `str_split_lines`. +# +# @param {string} text - The string to split into lines. +# @returns {void} Results are stored in the list `str_split_lines`. +# +# @example str_split_lines "a\nb\nc"; => str_split_lines = ["a", "b", "c"] +# @example str_split_lines "end\n"; => str_split_lines = ["end"] +list str_split_lines; + +proc str_split_lines text { + delete str_split_lines; + delete strbuf; local i = 1; repeat length($text) { - if $text[i] not in ASCII_UPPERCASE { - return false; + if $text[i] in "\n" { + add strbuf to str_split_lines; + delete strbuf; + } else { + add $text[i] to strbuf; } i++; } - return true; + if strbuf == "" {} else { + add strbuf to str_split_lines; + } +} + +# Returns $text truncated to at most $maxlength characters. If truncation +# is necessary, the returned string ends with "..." and its total length +# equals $maxlength (i.e. $maxlength - 3 characters of original text plus +# the three-character ellipsis). If $text is already within the limit, it +# is returned unchanged. +# +# @param {string} text - The string to truncate. +# @param {number} maxlength - The maximum allowed length of the result. +# @returns {string} The original string, or a truncated string ending in "...". +# +# @example str_truncate("hello world", 8) => "hello..." +# @example str_truncate("hi", 10) => "hi" +# @example str_truncate("abcdefg", 7) => "abcdefg" +func str_truncate(text, maxlength) { + if length($text) > $maxlength { + return str_slice($text, 1, $maxlength - 3) & "..."; + } else { + return $text; + } } -# Conditional macro to check if $text is a digit. -%define ISDIGIT(TEXT) (round(TEXT) == (TEXT)) +# Counts how many characters in $text are also present in the $chars set. +# Each character position in $text is checked independently; $chars acts +# as an unordered set of allowed characters, not a substring pattern. +# +# @param {string} text - The string to scan. +# @param {string} chars - A string of characters to count occurrences of. +# @returns {number} The total count of characters in $text that appear in $chars. +# +# @example str_count_char("hello", "lo") => 3 (l, l, o) +# @example str_count_char("aabbcc", "ac") => 4 +# @example str_count_char("abc", "xyz") => 0 +func str_count_char(text, chars) { + local i = 1; + local count = 0; + repeat length($text) { + if $text[i] in $chars { + count++; + } + i++; + } + return count; +} -# Remove leading characters in $text that are in $chars. -func lstrip(text, chars) { +# Returns a copy of $text with leading characters that appear in $chars +# removed. Stripping stops as soon as a character not in $chars is found. +# By default, strips ASCII whitespace (space, tab, newline, carriage return). +# +# @param {string} text - The string to strip. +# @param {string} chars - Characters to remove from the left (default: " \t\n\r"). +# @returns {string} The left-stripped string. +# +# @example str_lstrip(" hello") => "hello" +# @example str_lstrip("xxhello", "x") => "hello" +# @example str_lstrip("hello ") => "hello " +func str_lstrip(text, chars=" \t\n\r") { local i = 1; until $text[i] not in $chars or i > length($text) { i++; @@ -248,10 +388,20 @@ func lstrip(text, chars) { return strbuf; } -# Remove trailing characters in $text that are in $chars. -func rstrip(text, chars) { +# Returns a copy of $text with trailing characters that appear in $chars +# removed. Stripping stops as soon as a character not in $chars is found +# scanning from the right. By default, strips ASCII whitespace. +# +# @param {string} text - The string to strip. +# @param {string} chars - Characters to remove from the right (default: " \t\n\r"). +# @returns {string} The right-stripped string. +# +# @example str_rstrip("hello ") => "hello" +# @example str_rstrip("helloxx", "x") => "hello" +# @example str_rstrip(" hello") => " hello" +func str_rstrip(text, chars=" \t\n\r") { local i = length($text); - until $text[i] not in $chars or i == 1 { + until $text[i] not in $chars or i == 0 { i--; } delete strbuf; @@ -261,10 +411,20 @@ func rstrip(text, chars) { return strbuf; } -# Remove leading and trailing characters in $text that are in $chars. -func strip(text, chars) { +# Returns a copy of $text with both leading and trailing characters that +# appear in $chars removed. Equivalent to applying str_lstrip then +# str_rstrip. By default, strips ASCII whitespace. +# +# @param {string} text - The string to strip. +# @param {string} chars - Characters to remove from both ends (default: " \t\n\r"). +# @returns {string} The stripped string. +# +# @example str_strip(" hello ") => "hello" +# @example str_strip("xxhelloxx", "x") => "hello" +# @example str_strip("hello") => "hello" +func str_strip(text, chars=" \t\n\r") { local i = 1; - until $text[i] not in $chars or i > length($text) { + until i > length($text) or $text[i] not in $chars { i++; } delete strbuf; @@ -272,167 +432,425 @@ func strip(text, chars) { add $text[i] to strbuf; i++; } - until strbuf["last"] not in $chars { + until length(strbuf) == 0 or strbuf["last"] not in $chars { delete strbuf["last"]; } return strbuf; } -list split; -# Split $text into list `split`, separated by character $sep. -proc split text, sep { - delete split; - delete strbuf; +# Returns true if $text is non-empty and every character is an ASCII +# letter (A–Z, a–z) or ASCII digit (0–9). Returns false for empty strings +# or strings containing any other character. +# +# @param {string} text - The string to test. +# @returns {boolean} True if $text is non-empty and entirely alphanumeric. +# +# @example str_is_alnum("abc123") => true +# @example str_is_alnum("abc!") => false +# @example str_is_alnum("") => false +func str_is_alnum(text) { + if length($text) == 0 { + return false; + } local i = 1; repeat length($text) { - if $text[i] == $sep { - add strbuf to split; - delete strbuf; - } else { - add $text[i] to strbuf; + if $text[i] not in ASCII_UPPERCASE & ASCII_DIGITS { + return false; } i++; } - add strbuf to split; + return true; } -# Split $text into list `split`, separated by newlines. -proc splitlines text { - delete split; - delete strbuf; +# Returns true if $text is non-empty and every character is an ASCII +# letter (A–Z or a–z). Returns false for empty strings or strings +# containing digits, punctuation, or other non-alpha characters. +# +# @param {string} text - The string to test. +# @returns {boolean} True if $text is non-empty and entirely alphabetic. +# +# @example str_is_alpha("hello") => true +# @example str_is_alpha("hello1") => false +# @example str_is_alpha("") => false +func str_is_alpha(text) { + if length($text) == 0 { + return false; + } local i = 1; repeat length($text) { - if $text[i] in "\r\n" { - add strbuf to split; - delete strbuf; - } else { - add $text[i] to strbuf; + if $text[i] not in ASCII_UPPERCASE { + return false; } i++; } - if strbuf == "" {} else { - add strbuf to split; - } + return true; } -# Reverse $text. -func reverse(text) { - delete strbuf; +# Returns true if $text represents an integer or decimal number (i.e. it +# round-trips through the round() function unchanged). Returns false for +# strings containing non-numeric content. +# +# @param {string} text - The string to test. +# @returns {boolean} True if $text is a valid numeric value. +# +# @example str_is_digit("42") => true +# @example str_is_digit("3.14") => false +# @example str_is_digit("hello") => false +func str_is_digit(text) { + return round($text) == $text; +} + +# Returns the 1-based index of the first occurrence of $char in $text, +# scanning left to right. Returns 0 if $char is not found. +# Only single-character values for $char are meaningful. +# +# @param {string} text - The string to search within. +# @param {string} char - The character to search for. +# @returns {number} The 1-based index of the first match, or 0 if not found. +# +# @example str_find_char("hello", "l") => 3 +# @example str_find_char("hello", "z") => 0 +# @example str_find_char("abca", "a") => 1 +func str_find_char(text, char) { local i = 1; repeat length($text) { - add $text[1+length($text)-i] to strbuf; + if $text[i] == $char { + return i; + } i++; } - return strbuf; + return 0; } -# Repeat $text $n times. -func repeatstr(text, n) { - local result = ""; - repeat $n { - result &= $text; +# Returns the 1-based index of the last occurrence of $char in $text, +# scanning right to left. Returns 0 if $char is not found. +# Only single-character values for $char are meaningful. +# +# @param {string} text - The string to search within. +# @param {string} char - The character to search for. +# @returns {number} The 1-based index of the last match, or 0 if not found. +# +# @example str_rfind_char("hello", "l") => 4 +# @example str_rfind_char("hello", "z") => 0 +# @example str_rfind_char("abca", "a") => 4 +func str_rfind_char(text, char) { + local i = length($text); + repeat length($text) { + if $text[i] == $char { + return i; + } + i--; } - return result; + return 0; } -# Return a titlecased version of $text: words start with uppercase characters, -# all remaining cased characters are lowercase. -func titlecase(text) { - local result = ""; +# Returns a new string formed by removing $len characters from $text +# starting at position $start (1-based) and optionally inserting $repl +# in their place. If $len is Infinity (the default), all characters from +# $start to the end of $text are removed. If $repl is "" (the default), +# nothing is inserted (pure deletion). +# +# @param {string} text - The original string. +# @param {number} start - The 1-based index at which to begin removal. +# @param {number} len - Number of characters to remove (default: Infinity). +# @param {string} repl - Replacement string to insert (default: ""). +# @returns {string} The modified string. +# +# @example str_splice("hello world", 6) => "hello" +# @example str_splice("hello world", 6, 5) => "hello " +# @example str_splice("hello world", 6, 5, "!") => "hello !" +func str_splice(text, start, len="Infinity", repl="") { + return str_slice($text, 1, $start - 1) & $repl & str_slice($text, $start + $len); +} + +# Returns a copy of $text with every non-overlapping occurrence of +# $subtext replaced by $repl, scanning left to right. Overlapping +# matches are not detected; after a match the scan resumes immediately +# after the replaced region. +# +# @param {string} text - The original string. +# @param {string} subtext - The substring to search for. +# @param {string} repl - The replacement string. +# @returns {string} The string with all occurrences replaced. +# +# @example str_replace("aabbaa", "aa", "X") => "XbbX" +# @example str_replace("hello", "l", "r") => "herro" +# @example str_replace("hello", "z", "r") => "hello" +func str_replace(text, subtext, repl) { local i = 1; - local boundary = false; - repeat length($text) { - local j = 1; - until $text[i] == ASCII_UPPERCASE[j] or j > 26 { - j++; - } - if j > 26 { - boundary = false; - result &= $text[i]; - } else { - if boundary == false { - boundary = true; - result &= ASCII_UPPERCASE[j]; - } else { - result &= ASCII_LOWERCASE[j]; + local result = ""; + delete strbuf; + until i > length($text) { + add $text[i] to strbuf; + if contains(strbuf, $subtext) { + repeat length($subtext) { + delete strbuf["last"]; } + result &= strbuf & $repl; + delete strbuf; } i++; } - return result; + return result & strbuf; } -# Join `LIST` elements into a string, separated by `SEP` and store the result in a local -# variable `STORE`. -%define JOIN(LIST,SEP,STORE) \ - local STORE = ""; \ - local i = 1; \ - repeat length(LIST) { \ - STORE &= LIST[i]; \ - if i < length(LIST) { \ - STORE &= (SEP); \ - } \ - i++; \ - } - -# Join `LIST` by `FIELD` with `SEP` separator and store the result in a local variable -# `STORE`. -%define JOIN_BY_FIELD(LIST,FIELD,SEP,STORE) \ - local STORE = ""; \ - local i = 1; \ - repeat length(LIST) { \ - STORE &= LIST[i]FIELD; \ - if i < length(LIST) { \ - STORE &= (SEP); \ - } \ - i++; \ - } - -func truncate(text, maxlength) { - if length($text) > $maxlength { - return slice($text, 1, $maxlength-4) & "..."; - } else { - return $text; +# Returns a copy of $text with the first $n non-overlapping occurrences of +# $subtext replaced by $repl, scanning left to right. Occurrences beyond +# the $n-th are left unchanged. Passing $n = 0 returns $text unmodified. +# +# @param {string} text - The original string. +# @param {string} subtext - The substring to search for. +# @param {string} repl - The replacement string. +# @param {number} n - Maximum number of replacements to perform. +# @returns {string} The string with up to $n occurrences replaced. +# +# @example str_replacen("aabbaa", "aa", "X", 1) => "Xbbaa" +# @example str_replacen("aabbaa", "aa", "X", 2) => "XbbX" +# @example str_replacen("hello", "l", "r", 0) => "hello" +func str_replacen(text, subtext, repl, n) { + local i = 1; + local n = 0; + local result = ""; + delete strbuf; + until i > length($text) { + add $text[i] to strbuf; + if contains(strbuf, $subtext) { + if n < $n { + repeat length($subtext) { + delete strbuf["last"]; + } + result &= strbuf & $repl; + } else { + result &= strbuf; + } + delete strbuf; + n++; + } + i++; } + return result & strbuf; } -func casecmp(a, b) { - if length($a) != length($b) { - return false; - } +# Returns a copy of $text with only the $n-th occurrence (1-based) of +# $subtext replaced by $repl, scanning left to right. All other +# occurrences are left unchanged. If there are fewer than $n occurrences, +# $text is returned unmodified. +# +# @param {string} text - The original string. +# @param {string} subtext - The substring to search for. +# @param {string} repl - The replacement string. +# @param {number} n - The 1-based index of the occurrence to replace. +# @returns {string} The string with the $n-th occurrence replaced. +# +# @example str_replacenth("aabbaa", "aa", "X", 1) => "Xbbaa" +# @example str_replacenth("aabbaa", "aa", "X", 2) => "aabbX" +# @example str_replacenth("hello", "l", "r", 2) => "helro" +func str_replacenth(text, subtext, repl, n) { local i = 1; - repeat length($a) { - switch_costume $a; - local c = costume_number(); - switch_costume $b; - if c != costume_number() { - return false; + local n = 1; + local result = ""; + delete strbuf; + until i > length($text) { + add $text[i] to strbuf; + if contains(strbuf, $subtext) { + if n == $n { + repeat length($subtext) { + delete strbuf["last"]; + } + result &= strbuf & $repl; + } else { + result &= strbuf; + } + delete strbuf; + n++; } i++; } - return true; + return result & strbuf; +} + +# Returns $text with the leading $prefix removed, if present. +# If $text does not start with $prefix, it is returned unchanged. +# The check is NOT case-sensitive. +# +# @param {string} text - The string to process. +# @param {string} prefix - The prefix to remove. +# @returns {string} $text without the leading $prefix, or $text unchanged. +# +# @example str_remove_prefix("hello world", "hello ") => "world" +# @example str_remove_prefix("hello world", "world") => "hello world" +# @example str_remove_prefix("hello", "") => "hello" +func str_remove_prefix(text, prefix) { + if str_starts_with($text, $prefix) { + return str_slice($text, 1 + length($prefix)); + } + return $text; } -func countchar(text, char) { +# Returns $text with the trailing $suffix removed, if present. +# If $text does not end with $suffix, it is returned unchanged. +# The check is NOT case-sensitive. +# +# @param {string} text - The string to process. +# @param {string} suffix - The suffix to remove. +# @returns {string} $text without the trailing $suffix, or $text unchanged. +# +# @example str_remove_suffix("hello world", " world") => "hello" +# @example str_remove_suffix("hello world", "hello") => "hello world" +# @example str_remove_suffix("hello", "") => "hello" +func str_remove_suffix(text, suffix) { + if str_ends_with($text, $suffix) { + return str_slice($text, 1, 0 - length($suffix)); + } + return $text; +} + +# Returns the 1-based index of the first occurrence of $subtext in $text, +# scanning left to right using a naive O(n*m) search. Returns 0 if +# $subtext is not found or if $subtext is longer than $text. +# +# @param {string} text - The string to search within. +# @param {string} subtext - The substring to search for. +# @returns {number} The 1-based starting index of the first match, or 0. +# +# @example str_find("hello world", "world") => 7 +# @example str_find("hello world", "xyz") => 0 +# @example str_find("aabaa", "aa") => 1 +func str_find(text, subtext) { + local n = length($text); + local m = length($subtext); + if m > n { return 0; } + local i = 1; - local count = 0; - repeat length($text) { - if $text[i] == $char { - count++; + until i > n - m + 1 { + if str_slice($text, i, i + m - 1) == $subtext { + return i; } i++; } - return count; + return 0; } -func countchars(text, chars) { - local i = 1; - local count = 0; +# Returns a copy of $text centered in a string of length $width. +# If $width is less than or equal to the length of $text, a copy of +# $text is returned unchanged. The default fill character is a space. +# +# @param {string} text - The string to center. +# @param {number} width - The total width of the resulting string. +# @param {string} fillchar - The character to use for padding (default: " "). +# @returns {string} The centered string. +# +# @example str_center("hello", 10) => " hello " +# @example str_center("hello", 10, "-") => "--hello--" +# @example str_center("hello", 5) => "hello" +func str_center(text, width, fillchar=" ") { + if $width <= length($text) { + return $text; + } + local total_padding = $width - length($text); + local left_padding = total_padding // 2; + local right_padding = total_padding - left_padding; + delete strbuf; + repeat left_padding { + add $fillchar to strbuf; + } repeat length($text) { - if $text[i] in $chars { + add $text[1 + length(strbuf) - left_padding] to strbuf; + } + repeat right_padding { + add $fillchar to strbuf; + } + return strbuf; +} + +# Returns a copy of $text left-justified in a string of length $width. +# The string is padded on the right with $fillchar. If $width is less +# than or equal to the length of $text, a copy of $text is returned unchanged. +# +# @param {string} text - The string to left-justify. +# @param {number} width - The total width of the resulting string. +# @param {string} fillchar - The character to use for padding (default: " "). +# @returns {string} The left-justified string. +# +# @example str_ljust("hello", 10) => "hello " +# @example str_ljust("hello", 10, "-") => "hello-----" +# @example str_ljust("hello", 5) => "hello" +func str_ljust(text, width, fillchar=" ") { + if $width <= length($text) { + return $text; + } + delete strbuf; + repeat length($text) { + add $text[1 + length(strbuf)] to strbuf; + } + repeat $width - length($text) { + add $fillchar to strbuf; + } + return strbuf; +} + +# Returns a copy of $text right-justified in a string of length $width. +# The string is padded on the left with $fillchar. If $width is less +# than or equal to the length of $text, a copy of $text is returned unchanged. +# +# @param {string} text - The string to right-justify. +# @param {number} width - The total width of the resulting string. +# @param {string} fillchar - The character to use for padding (default: " "). +# @returns {string} The right-justified string. +# +# @example str_rjust("hello", 10) => " hello" +# @example str_rjust("hello", 10, "-") => "-----hello" +# @example str_rjust("hello", 5) => "hello" +func str_rjust(text, width, fillchar=" ") { + if $width <= length($text) { + return $text; + } + delete strbuf; + repeat $width - length($text) { + add $fillchar to strbuf; + } + repeat length($text) { + add $text[1 + length(strbuf) - ($width - length($text))] to strbuf; + } + return strbuf; +} + +# Counts the number of non-overlapping occurrences of $sub in $text. +# - returns 0 if $sub is not found +# - returns length($text) + 1 for an empty $sub +# +# @param {string} text - The string to search within. +# @param {string} sub - The substring to count. +# @returns {number} The number of non-overlapping occurrences. +# +# @example str_count("this is it", "is") => 2 +# @example str_count("aaaa", "aa") => 2 +# @example str_count("banana", "an") => 2 +# @example str_count("hello", "xyz") => 0 +# @example str_count("abc", "") => 4 +func str_count(text, sub) { + local count = 0; + local i = 1; + local j = 0; + local candidate = ""; + + if length($sub) == 0 { + return length($text) + 1; + } + + until i > length($text) - length($sub) + 1 { + candidate = ""; + j = 0; + repeat length($sub) { + j++; + candidate &= $text[i + j - 1]; + } + if candidate == $sub { count++; + i += length($sub); + } else { + i++; } - i++; } return count; } diff --git a/test/base64.test.gs b/test/base64.test.gs new file mode 100644 index 0000000..74a1d16 --- /dev/null +++ b/test/base64.test.gs @@ -0,0 +1,85 @@ +%include ../base64.gs + +proc test { + # ── Encode tests ──────────────────────────────────────────────── + + delete base64_buffer; + base64_buffer_append ""; + expect "base64_encode('')", base64_encode(BASE64_CHARSET), to_be: ""; + + delete base64_buffer; + base64_buffer_append "f"; + expect "base64_encode('f')", base64_encode(BASE64_CHARSET), to_be: "Zg=="; + + delete base64_buffer; + base64_buffer_append "fo"; + expect "base64_encode('fo')", base64_encode(BASE64_CHARSET), to_be: "Zm8="; + + delete base64_buffer; + base64_buffer_append "foo"; + expect "base64_encode('foo')", base64_encode(BASE64_CHARSET), to_be: "Zm9v"; + + delete base64_buffer; + base64_buffer_append "foob"; + expect "base64_encode('foob')", base64_encode(BASE64_CHARSET), to_be: "Zm9vYg=="; + + delete base64_buffer; + base64_buffer_append "fooba"; + expect "base64_encode('fooba')", base64_encode(BASE64_CHARSET), to_be: "Zm9vYmE="; + + delete base64_buffer; + base64_buffer_append "foobar"; + expect "base64_encode('foobar')", base64_encode(BASE64_CHARSET), to_be: "Zm9vYmFy"; + + delete base64_buffer; + base64_buffer_append "Many hands make light work."; + expect "base64_encode('Many hands make light work.')", base64_encode(BASE64_CHARSET), to_be: "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu"; + + # ── Decode tests ──────────────────────────────────────────────── + + base64_build_lut BASE64_CHARSET; + + delete base64_buffer; + base64_decode "Zg=="; + expect "base64_decode('Zg==')", base64_buffer_to_str(), to_be: "f"; + + delete base64_buffer; + base64_decode "Zm8="; + expect "base64_decode('Zm8=')", base64_buffer_to_str(), to_be: "fo"; + + delete base64_buffer; + base64_decode "Zm9v"; + expect "base64_decode('Zm9v')", base64_buffer_to_str(), to_be: "foo"; + + delete base64_buffer; + base64_decode "Zm9vYg=="; + expect "base64_decode('Zm9vYg==')", base64_buffer_to_str(), to_be: "foob"; + + delete base64_buffer; + base64_decode "Zm9vYmE="; + expect "base64_decode('Zm9vYmE=')", base64_buffer_to_str(), to_be: "fooba"; + + delete base64_buffer; + base64_decode "Zm9vYmFy"; + expect "base64_decode('Zm9vYmFy')", base64_buffer_to_str(), to_be: "foobar"; + + delete base64_buffer; + base64_decode "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu"; + expect "base64_decode('TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu')", base64_buffer_to_str(), to_be: "Many hands make light work."; + + # ── Round-trip tests ───────────────────────────────────────────── + + delete base64_buffer; + base64_buffer_append "Hello, World!"; + local encoded = base64_encode(BASE64_CHARSET); + delete base64_buffer; + base64_decode encoded; + expect "round-trip 'Hello, World!'", base64_buffer_to_str(), to_be: "Hello, World!"; + + delete base64_buffer; + base64_buffer_append "abc"; + encoded = base64_encode(BASE64_CHARSET); + delete base64_buffer; + base64_decode encoded; + expect "round-trip 'abc'", base64_buffer_to_str(), to_be: "abc"; +} diff --git a/test/bitwise.test.gs b/test/bitwise.test.gs new file mode 100644 index 0000000..c8c66b7 --- /dev/null +++ b/test/bitwise.test.gs @@ -0,0 +1,86 @@ +%include ../bitwise.gs + +proc test { + # xor8 (func) — chosen so result is 0xFF (255), a good boundary check + expect "xor8(0xA3, 0x5C)", xor8(_(0xA3), _(0x5C)), to_be: "255"; + + # xor16 (func) + expect "xor16(0xBEEF, 0xDEAD)", xor16(_(0xBEEF), _(0xDEAD)), to_be: "24642"; + + # xor32 (func) + expect "xor32(0x12345678, 0x9ABCDEF0)", xor32(_(0x12345678), _(0x9ABCDEF0)), to_be: "2290649224"; + + # and8 (func) + expect "and8(0xE7, 0x3C)", and8(_(0xE7), _(0x3C)), to_be: "36"; + + # and16 (func) + expect "and16(0xFACE, 0xBEEF)", and16(_(0xFACE), _(0xBEEF)), to_be: "47822"; + + # and32 (func) + expect "and32(0xCAFEBABE, 0xDEADBEEF)", and32(_(0xCAFEBABE), _(0xDEADBEEF)), to_be: "3400317614"; + + # or8 (func) + expect "or8(0x81, 0x42)", or8(_(0x81), _(0x42)), to_be: "195"; + + # or16 (func) + expect "or16(0x1337, 0xC0DE)", or16(_(0x1337), _(0xC0DE)), to_be: "54271"; + + # or32 (func) + expect "or32(0xC0DE0000, 0x0000CAFE)", or32(_(0xC0DE0000), _(0x0000CAFE)), to_be: "3235826430"; + + # NOT4 (macro) + expect "NOT4(0x0)", NOT4(0x0), to_be: "15"; + expect "NOT4(0xF)", NOT4(0xF), to_be: "0"; + expect "NOT4(0xA)", NOT4(0xA), to_be: "5"; + expect "NOT4(0x5)", NOT4(0x5), to_be: "10"; + + # not8 (func) + expect "not8(0x00)", not8(_(0x00)), to_be: "255"; + expect "not8(0xFF)", not8(_(0xFF)), to_be: "0"; + expect "not8(0xA5)", not8(_(0xA5)), to_be: "90"; # 0x5A + expect "not8(0xF0)", not8(_(0xF0)), to_be: "15"; # 0x0F + + # not16 (func) + expect "not16(0x0000)", not16(_(0x0000)), to_be: "65535"; + expect "not16(0xFFFF)", not16(_(0xFFFF)), to_be: "0"; + expect "not16(0xA5A5)", not16(_(0xA5A5)), to_be: "23130"; # 0x5A5A + expect "not16(0xDEAD)", not16(_(0xDEAD)), to_be: "8530"; # 0x2152 + + # not32 (func) + expect "not32(0x00000000)", not32(_(0x00000000)), to_be: "4294967295"; + expect "not32(0xFFFFFFFF)", not32(_(0xFFFFFFFF)), to_be: "0"; + expect "not32(0xDEADBEEF)", not32(_(0xDEADBEEF)), to_be: "559038736"; # 0x21524110 + expect "not32(0xA5A5A5A5)", not32(_(0xA5A5A5A5)), to_be: "1515870810"; # 0x5A5A5A5A + + # ADD32 (macro) + expect "ADD32(1, 1)", ADD32(1, 1), to_be: "2"; + expect "ADD32(0xFFFFFFFF, 1) wraps", ADD32(0xFFFFFFFF, 1), to_be: "0"; + expect "ADD32(0x80000000, 0x80000000) wraps", ADD32(0x80000000, 0x80000000), to_be: "0"; + expect "ADD32(0xDEADBEEF, 0x12345678)", ADD32(0xDEADBEEF, 0x12345678), to_be: "4041348455"; # 0xF0E21567 + + # add32 (func) + expect "add32(0, 0)", add32(_(0), _(0)), to_be: "0"; + expect "add32(1, 1)", add32(_(1), _(1)), to_be: "2"; + expect "add32(0xFFFFFFFF, 1) wraps", add32(_(0xFFFFFFFF), _(1)), to_be: "0"; + expect "add32(0x80000000, 0x80000000) wraps", add32(_(0x80000000), _(0x80000000)), to_be: "0"; + expect "add32(0xDEADBEEF, 0x12345678)", add32(_(0xDEADBEEF), _(0x12345678)), to_be: "4041348455"; + expect "add32(0xCAFEBABE, 0xDEADBEEF)", add32(_(0xCAFEBABE), _(0xDEADBEEF)), to_be: "2846652845"; # 0xA9AC79AD + + # ROL32 (macro, single step) + # NOTE: ROL32 has a bug — (A) > 0xFFFFFFFF is always 0, so the MSB carry + # is never captured. The two tests below expose it. + expect "ROL32(1)", ROL32(1), to_be: "2"; + expect "ROL32(0x40000000)", ROL32(0x40000000), to_be: "2147483648"; # MSB 0 → safe + expect "ROL32(0x80000000) carry bug", ROL32(0x80000000), to_be: "1"; # FAILS: gives 0 + expect "ROL32(0xDEADBEEF) carry bug", ROL32(0xDEADBEEF), to_be: "2932443615"; # 0xBD5B7DDF — FAILS: gives 0xBD5B7DDE + + # rol32 (func) + expect "rol32(1, 0) identity", rol32(_(1), _(0)), to_be: "1"; + expect "rol32(1, 1)", rol32(_(1), _(1)), to_be: "2"; + expect "rol32(1, 31)", rol32(_(1), _(31)), to_be: "2147483648"; # 0x80000000 + expect "rol32(0x12345678, 8)", rol32(_(0x12345678), _(8)), to_be: "878082066"; # 0x34567812 + expect "rol32(1, 32) mod wraps to identity", rol32(_(1), _(32)), to_be: "1"; + expect "rol32(0x80000000, 1) carry bug", rol32(_(0x80000000), _(1)), to_be: "1"; # FAILS: gives 0 + expect "rol32(0xDEADBEEF, 4) carry bug", rol32(_(0xDEADBEEF), _(4)), to_be: "3940282109"; # 0xEADBEEFD — FAILS + +} diff --git a/test/blank.svg b/test/blank.svg deleted file mode 100644 index 9f67e78..0000000 --- a/test/blank.svg +++ /dev/null @@ -1,9 +0,0 @@ - - diff --git a/test/getopt.test.gs b/test/getopt.test.gs new file mode 100644 index 0000000..1fec23c --- /dev/null +++ b/test/getopt.test.gs @@ -0,0 +1,125 @@ +%include ../shlex.gs +%include ../getopt.gs + +proc test { + # ── 1. single flag ──────────────────────────────────────────────────────── + shlex_split "-v"; + getopt_init; + getopt "v"; + expect "1. result", getopt_result, to_be: "v"; + getopt "v"; + expect "1. done", getopt_result, to_be: -1; + + # ── 2. multiple separate flags ──────────────────────────────────────────── + shlex_split "-a -b -c"; + getopt_init; + getopt "abc"; + expect "2. first", getopt_result, to_be: "a"; + getopt "abc"; + expect "2. second", getopt_result, to_be: "b"; + getopt "abc"; + expect "2. third", getopt_result, to_be: "c"; + getopt "abc"; + expect "2. done", getopt_result, to_be: -1; + + # ── 3. clustered flags ──────────────────────────────────────────────────── + shlex_split "-abc"; + getopt_init; + getopt "abc"; + expect "3. first", getopt_result, to_be: "a"; + getopt "abc"; + expect "3. second", getopt_result, to_be: "b"; + getopt "abc"; + expect "3. third", getopt_result, to_be: "c"; + getopt "abc"; + expect "3. done", getopt_result, to_be: -1; + + # ── 4. option with argument, separate token ─────────────────────────────── + shlex_split "-o file.txt"; + getopt_init; + getopt "o:"; + expect "4. result", getopt_result, to_be: "o"; + expect "4. optarg", optarg, to_be: "file.txt"; + getopt "o:"; + expect "4. done", getopt_result, to_be: -1; + + # ── 5. option with argument, joined ────────────────────────────────────── + shlex_split "-ofile.txt"; + getopt_init; + getopt "o:"; + expect "5. result", getopt_result, to_be: "o"; + expect "5. optarg", optarg, to_be: "file.txt"; + getopt "o:"; + expect "5. done", getopt_result, to_be: -1; + + # ── 6. mixed flags and option-with-arg ──────────────────────────────────── + shlex_split "-v -o out.txt -n"; + getopt_init; + getopt "vno:"; + expect "6. v", getopt_result, to_be: "v"; + getopt "vno:"; + expect "6. o", getopt_result, to_be: "o"; + expect "6. optarg", optarg, to_be: "out.txt"; + getopt "vno:"; + expect "6. n", getopt_result, to_be: "n"; + getopt "vno:"; + expect "6. done", getopt_result, to_be: -1; + + # ── 7. cluster ending with option-with-arg joined ───────────────────────── + # -voval → -v then -o val + shlex_split "-voval"; + getopt_init; + getopt "vo:"; + expect "7. v", getopt_result, to_be: "v"; + getopt "vo:"; + expect "7. o", getopt_result, to_be: "o"; + expect "7. optarg", optarg, to_be: "val"; + getopt "vo:"; + expect "7. done", getopt_result, to_be: -1; + + # ── 8. -- stops option parsing ──────────────────────────────────────────── + shlex_split "-v -- -n"; + getopt_init; + getopt "vn"; + expect "8. v", getopt_result, to_be: "v"; + getopt "vn"; + expect "8. done", getopt_result, to_be: -1; + expect "8. optind points past --", optind, to_be: 3; + + # ── 9. non-option arg stops parsing ────────────────────────────────────── + shlex_split "-v foo -n"; + getopt_init; + getopt "vn"; + expect "9. v", getopt_result, to_be: "v"; + getopt "vn"; + expect "9. done", getopt_result, to_be: -1; + expect "9. optind", optind, to_be: 2; + + # ── 10. unknown option returns ? and sets optopt ────────────────────────── + shlex_split "-z"; + getopt_init; + getopt "v"; + expect "10. result", getopt_result, to_be: "?"; + expect "10. optopt", optopt, to_be: "z"; + + # ── 11. missing required argument returns ? ─────────────────────────────── + shlex_split "-o"; + getopt_init; + getopt "o:"; + expect "11. result", getopt_result, to_be: "?"; + + # ── 12. no args at all ──────────────────────────────────────────────────── + shlex_split ""; + getopt_init; + getopt "v"; + expect "12. done", getopt_result, to_be: -1; + + # ── 13. optind lands on first non-option positional ─────────────────────── + shlex_split "-a -b foo bar"; + getopt_init; + getopt "ab"; + getopt "ab"; + getopt "ab"; + expect "13. optind", optind, to_be: 3; + expect "13. first pos", shlex_args[optind], to_be: "foo"; +} diff --git a/test/list.test.gs b/test/list.test.gs new file mode 100644 index 0000000..f270d5a --- /dev/null +++ b/test/list.test.gs @@ -0,0 +1,621 @@ +%include ../list.gs + +struct xy { x=0, y=0 } + +list mylist = []; +list mylist2 = []; +list xy mypts = []; +list xy mypts2 = []; + +proc unique_mylist start=1, end=-1 { + LIST_UNIQUE(mylist) +} + +proc unique_mypts start=1, end=-1 { + LIST_UNIQUE(mypts, xy, x) +} + +proc test_unique_basic { + delete mylist; + add 1 to mylist; + add 2 to mylist; + add 2 to mylist; + add 3 to mylist; + add 3 to mylist; + add 3 to mylist; + unique_mylist; + expect "unique basic length", length(mylist), to_be: "3"; + expect "unique basic [1]", mylist[1], to_be: "1"; + expect "unique basic [2]", mylist[2], to_be: "2"; + expect "unique basic [3]", mylist[3], to_be: "3"; +} + +proc test_unique_no_duplicates { + delete mylist; + add 1 to mylist; + add 2 to mylist; + add 3 to mylist; + unique_mylist; + expect "unique no dupes length", length(mylist), to_be: "3"; + expect "unique no dupes [1]", mylist[1], to_be: "1"; + expect "unique no dupes [2]", mylist[2], to_be: "2"; + expect "unique no dupes [3]", mylist[3], to_be: "3"; +} + +proc test_unique_all_duplicates { + delete mylist; + add 5 to mylist; + add 5 to mylist; + add 5 to mylist; + unique_mylist; + expect "unique all dupes length", length(mylist), to_be: "1"; + expect "unique all dupes [1]", mylist[1], to_be: "5"; +} + +proc test_unique_partial { + delete mylist; + add 9 to mylist; + add 2 to mylist; + add 2 to mylist; + add 3 to mylist; + add 9 to mylist; + unique_mylist start:2, end:4; + expect "unique partial [1] untouched", mylist[1], to_be: "9"; + expect "unique partial length", length(mylist), to_be: "4"; + expect "unique partial [2]", mylist[2], to_be: "2"; + expect "unique partial [3]", mylist[3], to_be: "3"; + expect "unique partial [4] untouched", mylist[4], to_be: "9"; +} + +proc test_unique_negative_indices { + delete mylist; + add 9 to mylist; + add 2 to mylist; + add 2 to mylist; + add 3 to mylist; + add 9 to mylist; + unique_mylist start:2, end:-2; + expect "unique neg [1] untouched", mylist[1], to_be: "9"; + expect "unique neg length", length(mylist), to_be: "4"; + expect "unique neg [2]", mylist[2], to_be: "2"; + expect "unique neg [3]", mylist[3], to_be: "3"; + expect "unique neg [4] untouched", mylist[4], to_be: "9"; +} + +proc test_unique_key { + delete mypts; + local xy p = xy{}; + p.x = 1; p.y = 10; add p to mypts; + p.x = 2; p.y = 20; add p to mypts; + p.x = 2; p.y = 99; add p to mypts; + p.x = 3; p.y = 30; add p to mypts; + unique_mypts; + expect "unique key length", length(mypts), to_be: "3"; + expect "unique key [1].x", mypts[1].x, to_be: "1"; + expect "unique key [2].x", mypts[2].x, to_be: "2"; + expect "unique key [2].y kept first", mypts[2].y, to_be: "20"; + expect "unique key [3].x", mypts[3].x, to_be: "3"; +} + +proc sort_mylist start=1, end=-1 { + LIST_SORT(mylist) +} + +proc sort_mypts start=1, end=-1 { + LIST_SORT(mypts, xy, x) +} + +proc test_sort_basic { + delete mylist; + add 3 to mylist; + add 1 to mylist; + add 4 to mylist; + add 2 to mylist; + sort_mylist; + expect "sort basic [1]", mylist[1], to_be: "1"; + expect "sort basic [2]", mylist[2], to_be: "2"; + expect "sort basic [3]", mylist[3], to_be: "3"; + expect "sort basic [4]", mylist[4], to_be: "4"; +} + +proc test_sort_partial { + delete mylist; + add 9 to mylist; + add 3 to mylist; + add 1 to mylist; + add 2 to mylist; + add 9 to mylist; + sort_mylist start:2, end:4; + expect "sort partial [1] untouched", mylist[1], to_be: "9"; + expect "sort partial [2]", mylist[2], to_be: "1"; + expect "sort partial [3]", mylist[3], to_be: "2"; + expect "sort partial [4]", mylist[4], to_be: "3"; + expect "sort partial [5] untouched", mylist[5], to_be: "9"; +} + +proc test_sort_negative_indices { + delete mylist; + add 9 to mylist; + add 4 to mylist; + add 2 to mylist; + add 3 to mylist; + add 9 to mylist; + sort_mylist start:2, end:-2; + expect "sort neg [1] untouched", mylist[1], to_be: "9"; + expect "sort neg [2]", mylist[2], to_be: "2"; + expect "sort neg [3]", mylist[3], to_be: "3"; + expect "sort neg [4]", mylist[4], to_be: "4"; + expect "sort neg [5] untouched", mylist[5], to_be: "9"; +} + +proc test_sort_key { + delete mypts; + local xy p = xy{}; + p.x = 5; p.y = 0; add p to mypts; + p.x = 1; p.y = 0; add p to mypts; + p.x = 3; p.y = 0; add p to mypts; + sort_mypts; + expect "sort key [1].x", mypts[1].x, to_be: "1"; + expect "sort key [2].x", mypts[2].x, to_be: "3"; + expect "sort key [3].x", mypts[3].x, to_be: "5"; +} + +proc test_sort_already_sorted { + delete mylist; + add 1 to mylist; + add 2 to mylist; + add 3 to mylist; + sort_mylist; + expect "sort already sorted [1]", mylist[1], to_be: "1"; + expect "sort already sorted [2]", mylist[2], to_be: "2"; + expect "sort already sorted [3]", mylist[3], to_be: "3"; +} + +proc test_sort_single_element { + delete mylist; + add 42 to mylist; + sort_mylist; + expect "sort single element", mylist[1], to_be: "42"; +} + +# ── LIST_JOIN ──────────────────────────────────────────────────────────────── + +func join_mylist(start=1, end=-1, sep=",") { + LIST_JOIN(mylist) +} + +func join_mypts(start=1, end=-1, sep=",") { + LIST_JOIN(mypts, x) +} + +proc test_join_basic { + delete mylist; + add "a" to mylist; + add "b" to mylist; + add "c" to mylist; + expect "join basic", join_mylist(), to_be: "a,b,c"; +} + +proc test_join_sep { + delete mylist; + add "x" to mylist; + add "y" to mylist; + add "z" to mylist; + expect "join sep", join_mylist(sep:" | "), to_be: "x | y | z"; +} + +proc test_join_partial { + delete mylist; + add "a" to mylist; + add "b" to mylist; + add "c" to mylist; + add "d" to mylist; + expect "join partial", join_mylist(start:2, end:3), to_be: "b,c"; +} + +proc test_join_negative_indices { + delete mylist; + add "a" to mylist; + add "b" to mylist; + add "c" to mylist; + add "d" to mylist; + expect "join neg indices", join_mylist(start:2, end:-2), to_be: "b,c"; +} + +proc test_join_single { + delete mylist; + add "only" to mylist; + expect "join single", join_mylist(), to_be: "only"; +} + +proc test_join_key { + delete mypts; + local xy p = xy{}; + p.x = 1; p.y = 0; add p to mypts; + p.x = 2; p.y = 0; add p to mypts; + p.x = 3; p.y = 0; add p to mypts; + expect "join key", join_mypts(), to_be: "1,2,3"; +} + +# ── LIST_SUM ───────────────────────────────────────────────────────────────── + +func sum_mylist(start=1, end=-1) { + LIST_SUM(mylist) +} + +func sum_mypts(start=1, end=-1) { + LIST_SUM(mypts, x) +} + +proc test_sum_basic { + delete mylist; + add 1 to mylist; + add 2 to mylist; + add 3 to mylist; + add 4 to mylist; + expect "sum basic", sum_mylist(), to_be: "10"; +} + +proc test_sum_partial { + delete mylist; + add 1 to mylist; + add 2 to mylist; + add 3 to mylist; + add 4 to mylist; + expect "sum partial", sum_mylist(start:2, end:3), to_be: "5"; +} + +proc test_sum_negative_indices { + delete mylist; + add 1 to mylist; + add 2 to mylist; + add 3 to mylist; + add 4 to mylist; + expect "sum neg indices", sum_mylist(start:2, end:-2), to_be: "5"; +} + +proc test_sum_key { + delete mypts; + local xy p = xy{}; + p.x = 10; p.y = 0; add p to mypts; + p.x = 20; p.y = 0; add p to mypts; + p.x = 30; p.y = 0; add p to mypts; + expect "sum key", sum_mypts(), to_be: "60"; +} + +# ── LIST_MIN ───────────────────────────────────────────────────────────────── + +func min_mylist(start=1, end=-1) { + LIST_MIN(mylist) +} + +func min_mypts(start=1, end=-1) { + LIST_MIN(mypts, x) +} + +proc test_min_basic { + delete mylist; + add 3 to mylist; + add 1 to mylist; + add 4 to mylist; + add 2 to mylist; + expect "min basic", min_mylist(), to_be: "1"; +} + +proc test_min_partial { + delete mylist; + add 1 to mylist; + add 5 to mylist; + add 3 to mylist; + add 1 to mylist; + expect "min partial", min_mylist(start:2, end:3), to_be: "3"; +} + +proc test_min_negative_indices { + delete mylist; + add 1 to mylist; + add 5 to mylist; + add 3 to mylist; + add 1 to mylist; + expect "min neg indices", min_mylist(start:2, end:-2), to_be: "3"; +} + +proc test_min_key { + delete mypts; + local xy p = xy{}; + p.x = 7; p.y = 0; add p to mypts; + p.x = 2; p.y = 0; add p to mypts; + p.x = 5; p.y = 0; add p to mypts; + expect "min key", min_mypts(), to_be: "2"; +} + +# ── LIST_MAX ───────────────────────────────────────────────────────────────── + +func max_mylist(start=1, end=-1) { + LIST_MAX(mylist) +} + +func max_mypts(start=1, end=-1) { + LIST_MAX(mypts, x) +} + +proc test_max_basic { + delete mylist; + add 3 to mylist; + add 1 to mylist; + add 4 to mylist; + add 2 to mylist; + expect "max basic", max_mylist(), to_be: "4"; +} + +proc test_max_partial { + delete mylist; + add 9 to mylist; + add 2 to mylist; + add 5 to mylist; + add 9 to mylist; + expect "max partial", max_mylist(start:2, end:3), to_be: "5"; +} + +proc test_max_negative_indices { + delete mylist; + add 9 to mylist; + add 2 to mylist; + add 5 to mylist; + add 9 to mylist; + expect "max neg indices", max_mylist(start:2, end:-2), to_be: "5"; +} + +proc test_max_key { + delete mypts; + local xy p = xy{}; + p.x = 7; p.y = 0; add p to mypts; + p.x = 2; p.y = 0; add p to mypts; + p.x = 5; p.y = 0; add p to mypts; + expect "max key", max_mypts(), to_be: "7"; +} + +# ── LIST_REVERSE ───────────────────────────────────────────────────────────── + +proc reverse_mylist start=1, end=-1 { + LIST_REVERSE(mylist) +} + +proc reverse_mypts start=1, end=-1 { + LIST_REVERSE(xy, mypts) +} + +proc test_reverse_basic { + delete mylist; + add 1 to mylist; + add 2 to mylist; + add 3 to mylist; + add 4 to mylist; + reverse_mylist; + expect "reverse basic [1]", mylist[1], to_be: "4"; + expect "reverse basic [2]", mylist[2], to_be: "3"; + expect "reverse basic [3]", mylist[3], to_be: "2"; + expect "reverse basic [4]", mylist[4], to_be: "1"; +} + +proc test_reverse_partial { + delete mylist; + add 1 to mylist; + add 2 to mylist; + add 3 to mylist; + add 4 to mylist; + add 5 to mylist; + reverse_mylist start:2, end:4; + expect "reverse partial [1] untouched", mylist[1], to_be: "1"; + expect "reverse partial [2]", mylist[2], to_be: "4"; + expect "reverse partial [3]", mylist[3], to_be: "3"; + expect "reverse partial [4]", mylist[4], to_be: "2"; + expect "reverse partial [5] untouched", mylist[5], to_be: "5"; +} + +proc test_reverse_negative_indices { + delete mylist; + add 1 to mylist; + add 2 to mylist; + add 3 to mylist; + add 4 to mylist; + add 5 to mylist; + reverse_mylist start:2, end:-2; + expect "reverse neg [1] untouched", mylist[1], to_be: "1"; + expect "reverse neg [2]", mylist[2], to_be: "4"; + expect "reverse neg [3]", mylist[3], to_be: "3"; + expect "reverse neg [4]", mylist[4], to_be: "2"; + expect "reverse neg [5] untouched", mylist[5], to_be: "5"; +} + +proc test_reverse_single { + delete mylist; + add 42 to mylist; + reverse_mylist; + expect "reverse single", mylist[1], to_be: "42"; +} + +proc test_reverse_typed { + delete mypts; + local xy p = xy{}; + p.x = 1; p.y = 10; add p to mypts; + p.x = 2; p.y = 20; add p to mypts; + p.x = 3; p.y = 30; add p to mypts; + reverse_mypts; + expect "reverse typed [1].x", mypts[1].x, to_be: "3"; + expect "reverse typed [2].x", mypts[2].x, to_be: "2"; + expect "reverse typed [3].x", mypts[3].x, to_be: "1"; + expect "reverse typed [1].y", mypts[1].y, to_be: "30"; +} + +# ── LIST_COPY ──────────────────────────────────────────────────────────────── + +proc copy_mylist_to_mylist2 start=1, end=-1 { + LIST_COPY(mylist, mylist2) +} + +proc test_copy_basic { + delete mylist; + delete mylist2; + add 10 to mylist; + add 20 to mylist; + add 30 to mylist; + copy_mylist_to_mylist2; + expect "copy basic length", length(mylist2), to_be: "3"; + expect "copy basic [1]", mylist2[1], to_be: "10"; + expect "copy basic [2]", mylist2[2], to_be: "20"; + expect "copy basic [3]", mylist2[3], to_be: "30"; +} + +proc test_copy_partial { + delete mylist; + delete mylist2; + add 10 to mylist; + add 20 to mylist; + add 30 to mylist; + add 40 to mylist; + copy_mylist_to_mylist2 start:2, end:3; + expect "copy partial length", length(mylist2), to_be: "2"; + expect "copy partial [1]", mylist2[1], to_be: "20"; + expect "copy partial [2]", mylist2[2], to_be: "30"; +} + +proc test_copy_negative_indices { + delete mylist; + delete mylist2; + add 10 to mylist; + add 20 to mylist; + add 30 to mylist; + add 40 to mylist; + copy_mylist_to_mylist2 start:2, end:-2; + expect "copy neg length", length(mylist2), to_be: "2"; + expect "copy neg [1]", mylist2[1], to_be: "20"; + expect "copy neg [2]", mylist2[2], to_be: "30"; +} + +proc test_copy_appends { + delete mylist; + delete mylist2; + add 1 to mylist; + add 2 to mylist; + add 99 to mylist2; + copy_mylist_to_mylist2; + expect "copy appends length", length(mylist2), to_be: "3"; + expect "copy appends [1]", mylist2[1], to_be: "99"; + expect "copy appends [2]", mylist2[2], to_be: "1"; + expect "copy appends [3]", mylist2[3], to_be: "2"; +} + +# ── LIST_EXTEND ────────────────────────────────────────────────────────────── + +proc extend_mylist_to_mylist2 start=1, end=-1 { + LIST_EXTEND(mylist, mylist2) +} + +proc test_extend_basic { + delete mylist; + delete mylist2; + add 1 to mylist; + add 2 to mylist; + add 3 to mylist; + extend_mylist_to_mylist2; + expect "extend basic length", length(mylist2), to_be: "3"; + expect "extend basic [1]", mylist2[1], to_be: "1"; + expect "extend basic [2]", mylist2[2], to_be: "2"; + expect "extend basic [3]", mylist2[3], to_be: "3"; +} + +proc test_extend_partial { + delete mylist; + delete mylist2; + add 10 to mylist; + add 20 to mylist; + add 30 to mylist; + add 40 to mylist; + extend_mylist_to_mylist2 start:2, end:3; + expect "extend partial length", length(mylist2), to_be: "2"; + expect "extend partial [1]", mylist2[1], to_be: "20"; + expect "extend partial [2]", mylist2[2], to_be: "30"; +} + +proc test_extend_negative_indices { + delete mylist; + delete mylist2; + add 10 to mylist; + add 20 to mylist; + add 30 to mylist; + add 40 to mylist; + extend_mylist_to_mylist2 start:2, end:-2; + expect "extend neg length", length(mylist2), to_be: "2"; + expect "extend neg [1]", mylist2[1], to_be: "20"; + expect "extend neg [2]", mylist2[2], to_be: "30"; +} + +proc test_extend_appends { + delete mylist; + delete mylist2; + add 7 to mylist; + add 8 to mylist; + add 99 to mylist2; + extend_mylist_to_mylist2; + expect "extend appends length", length(mylist2), to_be: "3"; + expect "extend appends [1]", mylist2[1], to_be: "99"; + expect "extend appends [2]", mylist2[2], to_be: "7"; + expect "extend appends [3]", mylist2[3], to_be: "8"; +} + +# ── RUN ALL ────────────────────────────────────────────────────────────────── + +proc test { + test_sort_basic; + test_sort_partial; + test_sort_negative_indices; + test_sort_key; + test_sort_already_sorted; + test_sort_single_element; + + test_join_basic; + test_join_sep; + test_join_partial; + test_join_negative_indices; + test_join_single; + test_join_key; + + test_sum_basic; + test_sum_partial; + test_sum_negative_indices; + test_sum_key; + + test_min_basic; + test_min_partial; + test_min_negative_indices; + test_min_key; + + test_max_basic; + test_max_partial; + test_max_negative_indices; + test_max_key; + + test_reverse_basic; + test_reverse_partial; + test_reverse_negative_indices; + test_reverse_single; + test_reverse_typed; + + test_copy_basic; + test_copy_partial; + test_copy_negative_indices; + test_copy_appends; + + test_extend_basic; + test_extend_partial; + test_extend_negative_indices; + test_extend_appends; + + test_unique_basic; + test_unique_no_duplicates; + test_unique_all_duplicates; + test_unique_partial; + test_unique_negative_indices; + test_unique_key; +} diff --git a/test/math.test.gs b/test/math.test.gs new file mode 100644 index 0000000..c0765bf --- /dev/null +++ b/test/math.test.gs @@ -0,0 +1,145 @@ +%include ../math.gs + +proc test { + expect "PI", PI, to_be: "3.141592653589793"; + expect "E", E, to_be: "2.718281828459045"; + + # MIN / MAX — boundary inversion, negatives, equality + expect "MIN(-1, 1)", MIN(_(-1), _(1)), to_be: "-1"; + expect "MIN(-2, -1)", MIN(_(-2), _(-1)), to_be: "-2"; + expect "MIN(1, 1)", MIN(_(1), _(1)), to_be: "1"; + expect "MAX(-1, 1)", MAX(_(-1), _(1)), to_be: "1"; + expect "MAX(-2, -1)", MAX(_(-2), _(-1)), to_be: "-1"; + expect "MAX(1, 1)", MAX(_(1), _(1)), to_be: "1"; + + # RGB / RGBA — black, white, primaries, alpha boundary + expect "RGB(0, 0, 0)", RGB(_(0), _(0), _(0)), to_be: "0"; + expect "RGB(255, 255, 255)", RGB(_(255), _(255), _(255)), to_be: "16777215"; + expect "RGB(255, 0, 0)", RGB(_(255), _(0), _(0)), to_be: "16711680"; + expect "RGB(0, 255, 0)", RGB(_(0), _(255), _(0)), to_be: "65280"; + expect "RGB(0, 0, 255)", RGB(_(0), _(0), _(255)), to_be: "255"; + expect "RGBA(0, 0, 0, 0)", RGBA(_(0), _(0), _(0), _(0)), to_be: "0"; + expect "RGBA(255, 255, 255, 255)", RGBA(_(255), _(255), _(255), _(255)), to_be: "4294967295"; + expect "RGBA(0, 0, 0, 255)", RGBA(_(0), _(0), _(0), _(255)), to_be: "4278190080"; + expect "RGBA(255, 255, 255, 0)", RGBA(_(255), _(255), _(255), _(0)), to_be: "16777215"; + expect "RGBA(1, 2, 3, 4)", RGBA(_(1), _(2), _(3), _(4)), to_be: "67305987"; + + # HEX / BIN / OCT — zero, single digit, multi-byte + expect "HEX('0')", HEX(_("0")), to_be: "0"; + expect "HEX('FF')", HEX(_("FF")), to_be: "255"; + expect "HEX('FF0000')", HEX(_("FF0000")), to_be: "16711680"; + expect "BIN('0')", BIN(_("0")), to_be: "0"; + expect "BIN('1')", BIN(_("1")), to_be: "1"; + expect "BIN('10')", BIN(_("10")), to_be: "2"; + expect "BIN('11111111')", BIN(_("11111111")), to_be: "255"; + expect "OCT('0')", OCT(_("0")), to_be: "0"; + expect "OCT('7')", OCT(_("7")), to_be: "7"; + expect "OCT('10')", OCT(_("10")), to_be: "8"; + expect "OCT('377')", OCT(_("377")), to_be: "255"; + + # SIGN — positive, zero, negative, fractional, infinity + expect "SIGN(1)", SIGN(_(1)), to_be: "1"; + expect "SIGN(0)", SIGN(_(0)), to_be: "0"; + expect "SIGN(-1)", SIGN(_(-1)), to_be: "-1"; + expect "SIGN(0.001)", SIGN(_(0.001)), to_be: "1"; + expect "SIGN(Infinity)", SIGN(_("Infinity")), to_be: "1"; + + # Hyperbolic trig — zero, identity, symmetry + expect "ACOSH(1)", ACOSH(_(1)), to_be: "0"; + expect "ACOSH(2)", ACOSH(_(2)), to_be: "1.3169578969248166"; + expect "ASINH(0)", ASINH(_(0)), to_be: "0"; + expect "ASINH(1)", ASINH(_(1)), to_be: "0.8813735870195429"; + expect "ASINH(-1)", ASINH(_(-1)), to_be: "-0.8813735870195428"; + expect "ATANH(0)", ATANH(_(0)), to_be: "0"; + expect "ATANH(0.5)", ATANH(_(0.5)), to_be: "0.5493061443340548"; + expect "ATANH(-0.5)",ATANH(_(-0.5)),to_be: "-0.5493061443340548"; + expect "ATANH(0.99)",ATANH(_(0.99)),to_be: "2.6466524123622457"; + expect "COSH(0)", COSH(_(0)), to_be: "1"; + expect "COSH(1)", COSH(_(1)), to_be: "1.5430806348152437"; + expect "COSH(-1)", COSH(_(-1)), to_be: "1.5430806348152437"; # even function + expect "SINH(0)", SINH(_(0)), to_be: "0"; + expect "SINH(1)", SINH(_(1)), to_be: "1.1752011936438014"; + expect "SINH(-1)", SINH(_(-1)), to_be: "-1.1752011936438014"; # odd function + expect "TANH(0)", TANH(_(0)), to_be: "0"; + expect "TANH(1)", TANH(_(1)), to_be: "0.7615941559557649"; + expect "TANH(-1)", TANH(_(-1)), to_be: "-0.7615941559557649"; + expect "TANH(10)", TANH(_(10)), to_be: "0.9999999958776927"; # near-1 saturation + + # MAG / DIST — zero, axis-aligned, Pythagorean triple, negatives + expect "MAG(0, 0)", MAG(_(0), _(0)), to_be: "0"; + expect "MAG(3, 4)", MAG(_(3), _(4)), to_be: "5"; + expect "MAG(-3, -4)", MAG(_(-3), _(-4)), to_be: "5"; + expect "DIST(0, 0, 0, 0)", DIST(_(0), _(0), _(0), _(0)), to_be: "0"; + expect "DIST(0, 0, 3, 4)", DIST(_(0), _(0), _(3), _(4)), to_be: "5"; + expect "DIST(-1, -1, 2, 3)", DIST(_(-1), _(-1), _(2), _(3)), to_be: "5"; + expect "DIST(2, 3, 2, 7)", DIST(_(2), _(3), _(2), _(7)), to_be: "4"; # vertical + + # RAD / DEG — zero, full circle, inverse relationship + expect "RAD(0)", RAD(_(0)), to_be: "0"; + expect "RAD(180)", RAD(_(180)), to_be: "3.141592653589793"; + expect "RAD(360)", RAD(_(360)), to_be: "6.283185307179586"; + expect "RAD(-90)", RAD(_(-90)), to_be: "-1.5707963267948966"; + expect "DEG(0)", DEG(_(0)), to_be: "0"; + expect "DEG(PI)", DEG(_(PI)), to_be: "180"; + expect "DEG(2*PI)", DEG(_(2*PI)), to_be: "360"; + expect "DEG(-PI/2)", DEG(_(-PI/2)),to_be: "-90"; + + # POW / ROOT — identity, zero exp, fractional, inverse pair + expect "POW(2, 0)", POW(_(2), _(0)), to_be: "1"; + expect "POW(2, 10)", POW(_(2), _(10)), to_be: "1024"; + expect "POW(4, 0.5)", POW(_(4), _(0.5)), to_be: "2"; + expect "POW(1, 100)", POW(_(1), _(100)), to_be: "1"; + expect "ROOT(4, 2)", ROOT(_(4), _(2)), to_be: "2"; + expect "ROOT(8, 3)", ROOT(_(8), _(3)), to_be: "2"; + expect "ROOT(1, 5)", ROOT(_(1), _(5)), to_be: "1"; + + # LOG — log(1)=0, log(base)=1, powers + expect "LOG(1, 10)", LOG(_(1), _(10)), to_be: "0"; + expect "LOG(10, 10)", LOG(_(10), _(10)), to_be: "1"; + expect "LOG(1000, 10)", LOG(_(1000), _(10)), to_be: "2.9999999999999996"; + expect "LOG(E, E)", LOG(_(E), _(E)), to_be: "1"; + expect "LOG(1024, 2)", LOG(_(1024), _(2)), to_be: "10"; + + # LERP — endpoints, midpoint, negative range + expect "LERP(0, 0, 10)", LERP(_(0), _(0), _(10)), to_be: "0"; + expect "LERP(1, 0, 10)", LERP(_(1), _(0), _(10)), to_be: "10"; + expect "LERP(0.5, 0, 10)", LERP(_(0.5), _(0), _(10)), to_be: "5"; + expect "LERP(0.5, -10, 10)",LERP(_(0.5), _(-10), _(10)),to_be: "0"; + + # INVLERP — inverse of LERP, endpoints, midpoint + expect "INVLERP(0, 0, 10)", INVLERP(_(0), _(0), _(10)), to_be: "0"; + expect "INVLERP(10, 0, 10)", INVLERP(_(10), _(0), _(10)), to_be: "1"; + expect "INVLERP(5, 0, 10)", INVLERP(_(5), _(0), _(10)), to_be: "0.5"; + expect "INVLERP(0, -10, 10)",INVLERP(_(0), _(-10), _(10)),to_be: "0.5"; + + # REMAP — endpoint preservation, midpoint, range flip + expect "REMAP(0, 0, 1, 0, 100)", REMAP(_(0), _(0), _(1), _(0), _(100)), to_be: "0"; + expect "REMAP(1, 0, 1, 0, 100)", REMAP(_(1), _(0), _(1), _(0), _(100)), to_be: "100"; + expect "REMAP(0.5, 0, 1, 0, 100)", REMAP(_(0.5), _(0), _(1), _(0), _(100)), to_be: "50"; + expect "REMAP(5, 0, 10, -1, 1)", REMAP(_(5), _(0), _(10), _(-1), _(1)), to_be: "0"; + + # CLAMP — within, below, above, boundary exact + expect "CLAMP(5, 0, 10)", CLAMP(_(5), _(0), _(10)), to_be: "5"; + expect "CLAMP(-5, 0, 10)", CLAMP(_(-5), _(0), _(10)), to_be: "0"; + expect "CLAMP(15, 0, 10)", CLAMP(_(15), _(0), _(10)), to_be: "10"; + expect "CLAMP(0, 0, 10)", CLAMP(_(0), _(0), _(10)), to_be: "0"; # lower boundary + expect "CLAMP(10, 0, 10)", CLAMP(_(10), _(0), _(10)), to_be: "10"; # upper boundary + + # POSITIVE_CLAMP / NEGATIVE_CLAMP — zero crossing, fractional + expect "POSITIVE_CLAMP(5)", POSITIVE_CLAMP(_(5)), to_be: "5"; + expect "POSITIVE_CLAMP(-5)", POSITIVE_CLAMP(_(-5)), to_be: "0"; + expect "POSITIVE_CLAMP(0)", POSITIVE_CLAMP(_(0)), to_be: "0"; + expect "POSITIVE_CLAMP(-0.001)",POSITIVE_CLAMP(_(-0.001)),to_be: "0"; + expect "NEGATIVE_CLAMP(-5)", NEGATIVE_CLAMP(_(-5)), to_be: "-5"; + expect "NEGATIVE_CLAMP(5)", NEGATIVE_CLAMP(_(5)), to_be: "0"; + expect "NEGATIVE_CLAMP(0)", NEGATIVE_CLAMP(_(0)), to_be: "0"; + expect "NEGATIVE_CLAMP(0.001)",NEGATIVE_CLAMP(_(0.001)),to_be: "0"; + + # APPROX — equal, within epsilon, just outside, negative span + expect "APPROX(1, 1, 0.0001)", APPROX(_(1), _(1), _(0.0001)), to_be: "1"; + expect "APPROX(1, 1.00001, 0.0001)", APPROX(_(1), _(1.00001), _(0.0001)), to_be: "1"; + expect "APPROX(1, 1.001, 0.0001)", APPROX(_(1), _(1.001), _(0.0001)), to_be: "0"; + expect "APPROX(0, 1, 1)", APPROX(_(0), _(1), _(1)), to_be: "0"; # exactly at boundary + expect "APPROX(-1, 1, 3)", APPROX(_(-1), _(1), _(3)), to_be: "1"; + expect "APPROX(-1, 1, 1)", APPROX(_(-1), _(1), _(1)), to_be: "0"; +} diff --git a/test/md5.test.gs b/test/md5.test.gs new file mode 100644 index 0000000..929b4aa --- /dev/null +++ b/test/md5.test.gs @@ -0,0 +1,10 @@ +%include std/bitwise.gs +%include std/bytes.gs +%include std/md5.gs + +proc test { + delete md5_input; + md5_input_encode_ascii "aspizu"; + md5; + expect "md5('aspizu')", md5_output_decode_hex(), to_be: "3E82F1CFE9773B2887D827976C75E6E7"; +} diff --git a/test/sha256.test.gs b/test/sha256.test.gs new file mode 100644 index 0000000..0361f01 --- /dev/null +++ b/test/sha256.test.gs @@ -0,0 +1,10 @@ +%include std/bitwise.gs +%include std/bytes.gs +%include std/sha256.gs + +proc test { + delete sha256_input; + sha256_input_encode_ascii "aspizu"; + sha256; + expect "sha256('aspizu')", sha256_output_decode_hex(), to_be: "D9A064F15C829582610A8C0A7C3C06A8F01B9DF383D78544451AAC3EBB57E0E3"; +} diff --git a/test/shlex.test.gs b/test/shlex.test.gs new file mode 100644 index 0000000..8c1b7ca --- /dev/null +++ b/test/shlex.test.gs @@ -0,0 +1,64 @@ +%include ../shlex.gs + +proc test { + # 1. basic whitespace splitting + shlex_split "one two three"; + expect "1. shlex_args[1]", shlex_args[1], to_be: "one"; + expect "1. shlex_args[2]", shlex_args[2], to_be: "two"; + expect "1. shlex_args[3]", shlex_args[3], to_be: "three"; + + # 2. single quotes preserve spaces + shlex_split "'hello world' foo"; + expect "2. shlex_args[1]", shlex_args[1], to_be: "hello world"; + expect "2. shlex_args[2]", shlex_args[2], to_be: "foo"; + + # 3. double quotes preserve spaces + shlex_split "\"hello world\" foo"; + expect "3. shlex_args[1]", shlex_args[1], to_be: "hello world"; + expect "3. shlex_args[2]", shlex_args[2], to_be: "foo"; + + # 4. backslash escapes a space outside quotes + shlex_split "hello\\ world foo"; + expect "4. shlex_args[1]", shlex_args[1], to_be: "hello world"; + expect "4. shlex_args[2]", shlex_args[2], to_be: "foo"; + + # 5. adjacent quoting concatenates into one token + shlex_split "foo\"bar\"'baz'"; + expect "5. shlex_args[1]", shlex_args[1], to_be: "foobarbaz"; + expect "5. length", length shlex_args, to_be: 1; + + # 6. backslash escape inside double quotes + shlex_split "\"say \\\"hi\\\"\""; + expect "6. shlex_args[1]", shlex_args[1], to_be: "say \"hi\""; + + # 7. single quotes treat backslash as literal + shlex_split "'back\\slash'"; + expect "7. shlex_args[1]", shlex_args[1], to_be: "back\\slash"; + + # 8. multiple spaces between tokens are collapsed + shlex_split "a b c"; + expect "8. shlex_args[1]", shlex_args[1], to_be: "a"; + expect "8. shlex_args[2]", shlex_args[2], to_be: "b"; + expect "8. shlex_args[3]", shlex_args[3], to_be: "c"; + expect "8. length", length shlex_args, to_be: 3; + + # 9. empty single-quoted string produces an empty token + shlex_split "a '' b"; + expect "9. shlex_args[1]", shlex_args[1], to_be: "a"; + expect "9. shlex_args[2]", shlex_args[2], to_be: ""; + expect "9. shlex_args[3]", shlex_args[3], to_be: "b"; + + # 10. flag-style token with = and quoted value + shlex_split "--msg='fix bug'"; + expect "10. shlex_args[1]", shlex_args[1], to_be: "--msg=fix bug"; + expect "10. length", length shlex_args, to_be: 1; + + # 11. only whitespace produces no tokens + shlex_split " "; + expect "11. length", length shlex_args, to_be: 0; + + # 12. single token, no spaces + shlex_split "hello"; + expect "12. shlex_args[1]", shlex_args[1], to_be: "hello"; + expect "12. length", length shlex_args, to_be: 1; +} diff --git a/test/stage.gs b/test/stage.gs deleted file mode 100644 index f5f4981..0000000 --- a/test/stage.gs +++ /dev/null @@ -1 +0,0 @@ -costumes "blank.svg"; diff --git a/test/string.test.gs b/test/string.test.gs new file mode 100644 index 0000000..ac5d9a8 --- /dev/null +++ b/test/string.test.gs @@ -0,0 +1,449 @@ +%include ../string.gs + +proc test { + + # ========================================================================= + # str_slice + # ========================================================================= + + # Basic usage + expect "str_slice('hello', 2, 4)", str_slice("hello", 2, 4), to_be: "ell"; + expect "str_slice('hello', 1, 5)", str_slice("hello", 1, 5), to_be: "hello"; + expect "str_slice('hello', 1, 1)", str_slice("hello", 1, 1), to_be: "h"; + expect "str_slice('hello', 5, 5)", str_slice("hello", 5, 5), to_be: "o"; + + # Negative indices + expect "str_slice('hello', -3)", str_slice("hello", -3), to_be: "llo"; + expect "str_slice('hello', -1)", str_slice("hello", -1), to_be: "o"; + expect "str_slice('hello', 2, -1)",str_slice("hello", 2, -1),to_be: "ello"; + expect "str_slice('hello', -3, -1)",str_slice("hello", -3, -1),to_be: "llo"; + expect "str_slice('hello', -5, -1)",str_slice("hello", -5, -1),to_be: "hello"; + + # Default args (full string) + expect "str_slice('hello')", str_slice("hello"), to_be: "hello"; + expect "str_slice('hello', 2)", str_slice("hello", 2), to_be: "ello"; + + # Out-of-bounds clamping + expect "str_slice('hello', 0, 3)", str_slice("hello", 0, 3), to_be: "hel"; + expect "str_slice('hello', 1, 99)",str_slice("hello", 1, 99),to_be: "hello"; + expect "str_slice('hello', 3, 99)",str_slice("hello", 3, 99),to_be: "llo"; + + # Invalid range → empty + expect "str_slice('hello', 4, 2)", str_slice("hello", 4, 2), to_be: ""; + expect "str_slice('hello', 6, 8)", str_slice("hello", 6, 8), to_be: ""; + expect "str_slice('', 1, 3)", str_slice("", 1, 3), to_be: ""; + + # Single character string + expect "str_slice('x', 1, 1)", str_slice("x", 1, 1), to_be: "x"; + expect "str_slice('x', 2, 3)", str_slice("x", 2, 3), to_be: ""; + + # ========================================================================= + # str_ends_with + # ========================================================================= + + expect_true "str_ends_with('hello', 'lo')", str_ends_with("hello", "lo"); + expect_true "str_ends_with('hello', 'hello')", str_ends_with("hello", "hello"); + expect_true "str_ends_with('hello', 'o')", str_ends_with("hello", "o"); + expect_false "str_ends_with('hello', 'he')", str_ends_with("hello", "he"); + expect_false "str_ends_with('hello', 'x')", str_ends_with("hello", "x"); + expect_true "str_ends_with('hello', '')", str_ends_with("hello", ""); + expect_true "str_ends_with('', '')", str_ends_with("", ""); + + # ========================================================================= + # str_starts_with + # ========================================================================= + + expect_true "str_starts_with('hello', 'he')", str_starts_with("hello", "he"); + expect_true "str_starts_with('hello', 'hello')", str_starts_with("hello", "hello"); + expect_true "str_starts_with('hello', 'h')", str_starts_with("hello", "h"); + expect_false "str_starts_with('hello', 'lo')", str_starts_with("hello", "lo"); + expect_false "str_starts_with('hello', 'x')", str_starts_with("hello", "x"); + expect_true "str_starts_with('hello', '')", str_starts_with("hello", ""); + expect_true "str_starts_with('', '')", str_starts_with("", ""); + + # ========================================================================= + # str_reverse + # ========================================================================= + + expect "str_reverse('hello')", str_reverse("hello"), to_be: "olleh"; + expect "str_reverse('abcd')", str_reverse("abcd"), to_be: "dcba"; + expect "str_reverse('a')", str_reverse("a"), to_be: "a"; + expect "str_reverse('')", str_reverse(""), to_be: ""; + expect "str_reverse('ab')", str_reverse("ab"), to_be: "ba"; + expect "str_reverse('racecar')",str_reverse("racecar"),to_be: "racecar"; + expect "str_reverse(' hi')", str_reverse(" hi"), to_be: "ih "; + + # ========================================================================= + # str_upper + # ========================================================================= + + expect "str_upper('hello')", str_upper("hello"), to_be: "HELLO"; + expect "str_upper('Hello!')", str_upper("Hello!"), to_be: "HELLO!"; + expect "str_upper('123')", str_upper("123"), to_be: "123"; + expect "str_upper('HELLO')", str_upper("HELLO"), to_be: "HELLO"; + expect "str_upper('')", str_upper(""), to_be: ""; + expect "str_upper('a1b2c3')", str_upper("a1b2c3"), to_be: "A1B2C3"; + expect "str_upper('hello world')", str_upper("hello world"), to_be: "HELLO WORLD"; + + # ========================================================================= + # str_lower + # ========================================================================= + + expect "str_lower('HELLO')", str_lower("HELLO"), to_be: "hello"; + expect "str_lower('Hello!')", str_lower("Hello!"), to_be: "hello!"; + expect "str_lower('123')", str_lower("123"), to_be: "123"; + expect "str_lower('hello')", str_lower("hello"), to_be: "hello"; + expect "str_lower('')", str_lower(""), to_be: ""; + expect "str_lower('A1B2C3')", str_lower("A1B2C3"), to_be: "a1b2c3"; + expect "str_lower('HELLO WORLD')", str_lower("HELLO WORLD"), to_be: "hello world"; + + # ========================================================================= + # str_capitalize + # ========================================================================= + + expect "str_capitalize('hello')", str_capitalize("hello"), to_be: "Hello"; + expect "str_capitalize('HELLO')", str_capitalize("HELLO"), to_be: "Hello"; + expect "str_capitalize('hELLO wORLD')", str_capitalize("hELLO wORLD"), to_be: "Hello world"; + expect "str_capitalize('a')", str_capitalize("a"), to_be: "A"; + expect "str_capitalize('ABC')", str_capitalize("ABC"), to_be: "Abc"; + expect "str_capitalize('123abc')", str_capitalize("123abc"), to_be: "123abc"; + + # ========================================================================= + # str_title + # ========================================================================= + + expect "str_title('hello world')", str_title("hello world"), to_be: "Hello World"; + expect "str_title('HELLO WORLD')", str_title("HELLO WORLD"), to_be: "Hello World"; + expect "str_title('it is a test')", str_title("it is a test"), to_be: "It Is A Test"; + expect "str_title('one')", str_title("one"), to_be: "One"; + expect "str_title('')", str_title(""), to_be: ""; + expect "str_title('hello')", str_title("hello"), to_be: "Hello"; + # Non-alpha acts as word boundary + expect "str_title('it\\'s a test')", str_title("it's a test"), to_be: "It'S A Test"; + expect "str_title('foo-bar')", str_title("foo-bar"), to_be: "Foo-Bar"; + + # ========================================================================= + # str_repeat + # ========================================================================= + + expect "str_repeat('ab', 3)", str_repeat("ab", 3), to_be: "ababab"; + expect "str_repeat('hi', 1)", str_repeat("hi", 1), to_be: "hi"; + expect "str_repeat('x', 0)", str_repeat("x", 0), to_be: ""; + expect "str_repeat('', 5)", str_repeat("", 5), to_be: ""; + expect "str_repeat('abc',2)", str_repeat("abc",2), to_be: "abcabc"; + expect "str_repeat('-', 4)", str_repeat("-", 4), to_be: "----"; + + # ========================================================================= + # str_split (results stored in list str_split) + # ========================================================================= + + str_split "a,b,c", ","; + expect "str_split 'a,b,c' [1]", str_split[1], to_be: "a"; + expect "str_split 'a,b,c' [2]", str_split[2], to_be: "b"; + expect "str_split 'a,b,c' [3]", str_split[3], to_be: "c"; + expect "str_split 'a,b,c' len", length(str_split), to_be: "3"; + + str_split "hello"; + expect "str_split 'hello' [1]", str_split[1], to_be: "hello"; + expect "str_split 'hello' len", length(str_split), to_be: "1"; + + str_split "a,,b", ","; + expect "str_split 'a,,b' [1]", str_split[1], to_be: "a"; + expect "str_split 'a,,b' [2]", str_split[2], to_be: ""; + expect "str_split 'a,,b' [3]", str_split[3], to_be: "b"; + expect "str_split 'a,,b' len", length(str_split), to_be: "3"; + + str_split ",a,", ","; + expect "str_split ',a,' [1]", str_split[1], to_be: ""; + expect "str_split ',a,' [2]", str_split[2], to_be: "a"; + expect "str_split ',a,' [3]", str_split[3], to_be: ""; + expect "str_split ',a,' len", length(str_split), to_be: "3"; + + str_split "one two three"; + expect "str_split 'one two three' [1]", str_split[1], to_be: "one"; + expect "str_split 'one two three' [2]", str_split[2], to_be: "two"; + expect "str_split 'one two three' [3]", str_split[3], to_be: "three"; + + # ========================================================================= + # str_split_lines + # ========================================================================= + + str_split_lines "a\nb\nc"; + expect "str_split_lines [1]", str_split_lines[1], to_be: "a"; + expect "str_split_lines [2]", str_split_lines[2], to_be: "b"; + expect "str_split_lines [3]", str_split_lines[3], to_be: "c"; + expect "str_split_lines len", length(str_split_lines), to_be: "3"; + + # Trailing newline is ignored + str_split_lines "end\n"; + expect "str_split_lines 'end\\n' [1]", str_split_lines[1], to_be: "end"; + expect "str_split_lines 'end\\n' len", length(str_split_lines), to_be: "1"; + + str_split_lines "hello"; + expect "str_split_lines 'hello' [1]", str_split_lines[1], to_be: "hello"; + expect "str_split_lines 'hello' len", length(str_split_lines), to_be: "1"; + + str_split_lines "a\n\nb"; + expect "str_split_lines 'a\\n\\nb' [1]", str_split_lines[1], to_be: "a"; + expect "str_split_lines 'a\\n\\nb' [2]", str_split_lines[2], to_be: ""; + expect "str_split_lines 'a\\n\\nb' [3]", str_split_lines[3], to_be: "b"; + + # ========================================================================= + # str_truncate + # ========================================================================= + + expect "str_truncate('hello world', 8)", str_truncate("hello world", 8), to_be: "hello..."; + expect "str_truncate('hi', 10)", str_truncate("hi", 10), to_be: "hi"; + expect "str_truncate('abcdefg', 7)", str_truncate("abcdefg", 7), to_be: "abcdefg"; + expect "str_truncate('abcdefg', 6)", str_truncate("abcdefg", 6), to_be: "abc..."; + expect "str_truncate('abcdefg', 3)", str_truncate("abcdefg", 3), to_be: "..."; + expect "str_truncate('hi', 2)", str_truncate("hi", 2), to_be: "hi"; + expect "str_truncate('', 5)", str_truncate("", 5), to_be: ""; + + # ========================================================================= + # str_count_char + # ========================================================================= + + expect "str_count_char('hello', 'lo')", str_count_char("hello", "lo"), to_be: "3"; + expect "str_count_char('aabbcc', 'ac')", str_count_char("aabbcc", "ac"), to_be: "4"; + expect "str_count_char('abc', 'xyz')", str_count_char("abc", "xyz"), to_be: "0"; + expect "str_count_char('', 'a')", str_count_char("", "a"), to_be: "0"; + expect "str_count_char('aaaa', 'a')", str_count_char("aaaa", "a"), to_be: "4"; + expect "str_count_char('hello', 'l')", str_count_char("hello", "l"), to_be: "2"; + expect "str_count_char('hello', 'aeiou')", str_count_char("hello", "aeiou"), to_be: "2"; + + # ========================================================================= + # str_count + # ========================================================================= + + expect "str_count('this is it', 'is')", str_count("this is it", "is"), to_be: "2"; + expect "str_count('aaaa', 'aa')", str_count("aaaa", "aa"), to_be: "2"; + expect "str_count('banana', 'an')", str_count("banana", "an"), to_be: "2"; + expect "str_count('hello', 'xyz')", str_count("hello", "xyz"), to_be: "0"; + expect "str_count('abc', '')", str_count("abc", ""), to_be: "4"; + expect "str_count('hello', 'l')", str_count("hello", "l"), to_be: "2"; + expect "str_count('hello', 'o')", str_count("hello", "o"), to_be: "1"; + expect "str_count('aaaaa', 'aaa')", str_count("aaaaa", "aaa"), to_be: "1"; + expect "str_count('', 'a')", str_count("", "a"), to_be: "0"; + expect "str_count('', '')", str_count("", ""), to_be: "1"; + expect "str_count('aaa', 'aa')", str_count("aaa", "aa"), to_be: "1"; + + # ========================================================================= + # str_lstrip + # ========================================================================= + + expect "str_lstrip(' hello')", str_lstrip(" hello"), to_be: "hello"; + expect "str_lstrip('hello ')", str_lstrip("hello "), to_be: "hello "; + expect "str_lstrip(' hello ')", str_lstrip(" hello "), to_be: "hello "; + expect "str_lstrip('xxhello', 'x')", str_lstrip("xxhello", "x"), to_be: "hello"; + expect "str_lstrip('hello', 'x')", str_lstrip("hello", "x"), to_be: "hello"; + expect "str_lstrip('', 'x')", str_lstrip("", "x"), to_be: ""; + expect "str_lstrip('\t\nhello')", str_lstrip("\t\nhello"), to_be: "hello"; + + # ========================================================================= + # str_rstrip + # ========================================================================= + + expect "str_rstrip('hello ')", str_rstrip("hello "), to_be: "hello"; + expect "str_rstrip(' hello')", str_rstrip(" hello"), to_be: " hello"; + expect "str_rstrip(' hello ')", str_rstrip(" hello "), to_be: " hello"; + expect "str_rstrip('helloxx', 'x')", str_rstrip("helloxx", "x"), to_be: "hello"; + expect "str_rstrip('hello', 'x')", str_rstrip("hello", "x"), to_be: "hello"; + expect "str_rstrip('', 'x')", str_rstrip("", "x"), to_be: ""; + expect "str_rstrip('hello\t\n')", str_rstrip("hello\t\n"), to_be: "hello"; + + # ========================================================================= + # str_strip + # ========================================================================= + + expect "str_strip(' hello ')", str_strip(" hello "), to_be: "hello"; + expect "str_strip('hello')", str_strip("hello"), to_be: "hello"; + expect "str_strip('xxhelloxx', 'x')", str_strip("xxhelloxx", "x"), to_be: "hello"; + expect "str_strip(' hello')", str_strip(" hello"), to_be: "hello"; + expect "str_strip('hello ')", str_strip("hello "), to_be: "hello"; + expect "str_strip('')", str_strip(""), to_be: ""; + expect "str_strip('\t hello \n')", str_strip("\t hello \n"), to_be: "hello"; + + # ========================================================================= + # str_is_alnum + # ========================================================================= + + expect_true "str_is_alnum('abc123')", str_is_alnum("abc123"); + expect_true "str_is_alnum('ABC123')", str_is_alnum("ABC123"); + expect_true "str_is_alnum('abc')", str_is_alnum("abc"); + expect_true "str_is_alnum('123')", str_is_alnum("123"); + expect_false "str_is_alnum('abc!')", str_is_alnum("abc!"); + expect_false "str_is_alnum('abc 123')", str_is_alnum("abc 123"); + expect_false "str_is_alnum('')", str_is_alnum(""); + + # ========================================================================= + # str_is_alpha + # ========================================================================= + + expect_true "str_is_alpha('hello')", str_is_alpha("hello"); + expect_true "str_is_alpha('HELLO')", str_is_alpha("HELLO"); + expect_true "str_is_alpha('Hello')", str_is_alpha("Hello"); + expect_false "str_is_alpha('hello1')", str_is_alpha("hello1"); + expect_false "str_is_alpha('hello!')", str_is_alpha("hello!"); + expect_false "str_is_alpha('123')", str_is_alpha("123"); + expect_false "str_is_alpha('')", str_is_alpha(""); + + # ========================================================================= + # str_is_digit + # ========================================================================= + + expect_true "str_is_digit('42')", str_is_digit("42"); + expect_true "str_is_digit('0')", str_is_digit("0"); + expect_true "str_is_digit('-5')", str_is_digit("-5"); + expect_false "str_is_digit('3.14')", str_is_digit("3.14"); + expect_false "str_is_digit('hello')", str_is_digit("hello"); + expect_false "str_is_digit('12abc')", str_is_digit("12abc"); + expect_false "str_is_digit('')", str_is_digit(""); + + # ========================================================================= + # str_find_char + # ========================================================================= + + expect "str_find_char('hello', 'l')", str_find_char("hello", "l"), to_be: "3"; + expect "str_find_char('hello', 'h')", str_find_char("hello", "h"), to_be: "1"; + expect "str_find_char('hello', 'o')", str_find_char("hello", "o"), to_be: "5"; + expect "str_find_char('hello', 'z')", str_find_char("hello", "z"), to_be: "0"; + expect "str_find_char('abca', 'a')", str_find_char("abca", "a"), to_be: "1"; + expect "str_find_char('', 'a')", str_find_char("", "a"), to_be: "0"; + + # ========================================================================= + # str_rfind_char + # ========================================================================= + + expect "str_rfind_char('hello', 'l')", str_rfind_char("hello", "l"), to_be: "4"; + expect "str_rfind_char('hello', 'h')", str_rfind_char("hello", "h"), to_be: "1"; + expect "str_rfind_char('hello', 'o')", str_rfind_char("hello", "o"), to_be: "5"; + expect "str_rfind_char('hello', 'z')", str_rfind_char("hello", "z"), to_be: "0"; + expect "str_rfind_char('abca', 'a')", str_rfind_char("abca", "a"), to_be: "4"; + expect "str_rfind_char('', 'a')", str_rfind_char("", "a"), to_be: "0"; + + # ========================================================================= + # str_splice + # ========================================================================= + + expect "str_splice('hello world', 6)", str_splice("hello world", 6), to_be: "hello"; + expect "str_splice('hello world', 6, 5)", str_splice("hello world", 6, 5), to_be: "hello "; + expect "str_splice('hello world', 6, 5, '!')", str_splice("hello world", 6, 5, "!"), to_be: "hello !"; + expect "str_splice('hello', 1)", str_splice("hello", 1), to_be: ""; + expect "str_splice('hello', 3, 1)", str_splice("hello", 3, 1), to_be: "helo"; + expect "str_splice('hello', 3, 1, 'XY')", str_splice("hello", 3, 1, "XY"), to_be: "heXYlo"; + expect "str_splice('hello', 6, 0, '!')", str_splice("hello", 6, 0, "!"), to_be: "hello!"; + expect "str_splice('abcde', 2, 3, 'Z')", str_splice("abcde", 2, 3, "Z"), to_be: "aZe"; + + # ========================================================================= + # str_replace + # ========================================================================= + + expect "str_replace('aabbaa', 'aa', 'X')", str_replace("aabbaa", "aa", "X"), to_be: "XbbX"; + expect "str_replace('hello', 'l', 'r')", str_replace("hello", "l", "r"), to_be: "herro"; + expect "str_replace('hello', 'z', 'r')", str_replace("hello", "z", "r"), to_be: "hello"; + expect "str_replace('hello', 'hello', '')", str_replace("hello", "hello", ""), to_be: ""; + expect "str_replace('aaaa', 'aa', 'X')", str_replace("aaaa", "aa", "X"), to_be: "XX"; + expect "str_replace('', 'a', 'b')", str_replace("", "a", "b"), to_be: ""; + expect "str_replace('abc', 'b', 'BB')", str_replace("abc", "b", "BB"), to_be: "aBBc"; + + # ========================================================================= + # str_replacen + # ========================================================================= + + expect "str_replacen('aabbaa', 'aa', 'X', 1)", str_replacen("aabbaa", "aa", "X", 1), to_be: "Xbbaa"; + expect "str_replacen('aabbaa', 'aa', 'X', 2)", str_replacen("aabbaa", "aa", "X", 2), to_be: "XbbX"; + expect "str_replacen('hello', 'l', 'r', 0)", str_replacen("hello", "l", "r", 0), to_be: "hello"; + expect "str_replacen('hello', 'l', 'r', 1)", str_replacen("hello", "l", "r", 1), to_be: "herlo"; + expect "str_replacen('aaaa', 'a', 'X', 3)", str_replacen("aaaa", "a", "X", 3), to_be: "XXXa"; + expect "str_replacen('abc', 'z', 'X', 5)", str_replacen("abc", "z", "X", 5), to_be: "abc"; + + # ========================================================================= + # str_replacenth + # ========================================================================= + + expect "str_replacenth('aabbaa', 'aa', 'X', 1)", str_replacenth("aabbaa", "aa", "X", 1), to_be: "Xbbaa"; + expect "str_replacenth('aabbaa', 'aa', 'X', 2)", str_replacenth("aabbaa", "aa", "X", 2), to_be: "aabbX"; + expect "str_replacenth('hello', 'l', 'r', 2)", str_replacenth("hello", "l", "r", 2), to_be: "helro"; + expect "str_replacenth('hello', 'l', 'r', 1)", str_replacenth("hello", "l", "r", 1), to_be: "herlo"; + expect "str_replacenth('aaaa', 'a', 'X', 3)", str_replacenth("aaaa", "a", "X", 3), to_be: "aaXa"; + # Fewer occurrences than n → unchanged + expect "str_replacenth('hello', 'z', 'X', 1)", str_replacenth("hello", "z", "X", 1), to_be: "hello"; + + # ========================================================================= + # str_remove_prefix + # ========================================================================= + + expect "str_remove_prefix('hello world', 'hello ')", str_remove_prefix("hello world", "hello "), to_be: "world"; + expect "str_remove_prefix('hello world', 'world')", str_remove_prefix("hello world", "world"), to_be: "hello world"; + expect "str_remove_prefix('hello', '')", str_remove_prefix("hello", ""), to_be: "hello"; + expect "str_remove_prefix('hello', 'hello')", str_remove_prefix("hello", "hello"), to_be: ""; + expect "str_remove_prefix('hello', 'xyz')", str_remove_prefix("hello", "xyz"), to_be: "hello"; + expect "str_remove_prefix('aabaa', 'aa')", str_remove_prefix("aabaa", "aa"), to_be: "baa"; + + # ========================================================================= + # str_remove_suffix + # ========================================================================= + + expect "str_remove_suffix('hello world', ' world')", str_remove_suffix("hello world", " world"), to_be: "hello"; + expect "str_remove_suffix('hello world', 'hello')", str_remove_suffix("hello world", "hello"), to_be: "hello world"; + expect "str_remove_suffix('hello', '')", str_remove_suffix("hello", ""), to_be: "hello"; + expect "str_remove_suffix('hello', 'hello')", str_remove_suffix("hello", "hello"), to_be: ""; + expect "str_remove_suffix('hello', 'xyz')", str_remove_suffix("hello", "xyz"), to_be: "hello"; + expect "str_remove_suffix('aabaa', 'aa')", str_remove_suffix("aabaa", "aa"), to_be: "aab"; + + # ========================================================================= + # str_find + # ========================================================================= + + expect "str_find('hello world', 'world')", str_find("hello world", "world"), to_be: "7"; + expect "str_find('hello world', 'hello')", str_find("hello world", "hello"), to_be: "1"; + expect "str_find('hello world', ' ')", str_find("hello world", " "), to_be: "6"; + expect "str_find('hello world', 'xyz')", str_find("hello world", "xyz"), to_be: "0"; + expect "str_find('aabaa', 'aa')", str_find("aabaa", "aa"), to_be: "1"; + expect "str_find('hello', 'hello')", str_find("hello", "hello"), to_be: "1"; + expect "str_find('hello', 'helloo')", str_find("hello", "helloo"), to_be: "0"; + expect "str_find('', 'a')", str_find("", "a"), to_be: "0"; + expect "str_find('abcabc', 'bc')", str_find("abcabc", "bc"), to_be: "2"; + expect "str_find('hello', 'o')", str_find("hello", "o"), to_be: "5"; + + # ========================================================================= + # str_center + # ========================================================================= + + expect "str_center('hello', 10)", str_center("hello", 10), to_be: " hello "; + expect "str_center('hello', 10, '-')", str_center("hello", 10, "-"), to_be: "--hello--"; + expect "str_center('hello', 5)", str_center("hello", 5), to_be: "hello"; + expect "str_center('hello', 6)", str_center("hello", 6), to_be: " hello"; + expect "str_center('hello', 7)", str_center("hello", 7), to_be: " hello "; + expect "str_center('', 5)", str_center("", 5), to_be: " "; + expect "str_center('a', 5)", str_center("a", 5), to_be: " a "; + expect "str_center('ab', 5)", str_center("ab", 5), to_be: " ab "; + expect "str_center('abc', 5)", str_center("abc", 5), to_be: " abc"; + expect "str_center('x', 1)", str_center("x", 1), to_be: "x"; + expect "str_center('x', 0)", str_center("x", 0), to_be: "x"; + + # ========================================================================= + # str_ljust + # ========================================================================= + + expect "str_ljust('hello', 10)", str_ljust("hello", 10), to_be: "hello "; + expect "str_ljust('hello', 10, '-')", str_ljust("hello", 10, "-"), to_be: "hello-----"; + expect "str_ljust('hello', 5)", str_ljust("hello", 5), to_be: "hello"; + expect "str_ljust('hello', 7)", str_ljust("hello", 7), to_be: "hello "; + expect "str_ljust('hello', 3)", str_ljust("hello", 3), to_be: "hello"; + expect "str_ljust('', 5)", str_ljust("", 5), to_be: " "; + expect "str_ljust('a', 5)", str_ljust("a", 5), to_be: "a "; + + # ========================================================================= + # str_rjust + # ========================================================================= + + expect "str_rjust('hello', 10)", str_rjust("hello", 10), to_be: " hello"; + expect "str_rjust('hello', 10, '-')", str_rjust("hello", 10, "-"), to_be: "-----hello"; + expect "str_rjust('hello', 5)", str_rjust("hello", 5), to_be: "hello"; + expect "str_rjust('hello', 7)", str_rjust("hello", 7), to_be: " hello"; + expect "str_rjust('hello', 3)", str_rjust("hello", 3), to_be: "hello"; + expect "str_rjust('', 5)", str_rjust("", 5), to_be: " "; + expect "str_rjust('a', 5)", str_rjust("a", 5), to_be: " a"; +} diff --git a/test/test.gs b/test/test.gs deleted file mode 100644 index fa0656f..0000000 --- a/test/test.gs +++ /dev/null @@ -1,190 +0,0 @@ -%include ../math -%include ../string -%include ../list -%include ../emoji -%include ../cskv -%include ../cmd - -list console; - -%define ASSERT_EQ(LEFT,RIGHT,MESSAGE) \ - if not casecmp(""&(LEFT), ""&(RIGHT)) { \ - add (MESSAGE)&" should be equal to "&(RIGHT)&", but it is "&(LEFT) to console; \ - } - -costumes "blank.svg" as "@ascii/"; - -list things; - -struct point {x, y} - -list point points; - -proc test { - # math - ASSERT_EQ(MIN(1, 2), 1, "MIN(1, 2)"); - ASSERT_EQ(MAX(1, 2), 2, "MAX(1, 2)"); - ASSERT_EQ(RGB(255, 0, 0), 16711680, "RGB(255, 0, 0)"); - ASSERT_EQ(RGBA(255, 0, 0, 0.5), 25100288, "RGBA(255, 0, 0, 0.5)"); - ASSERT_EQ(HEX("FF"), 255, "HEX(\"FF\") should be "); - ASSERT_EQ(BIN("11111111"), 255, "BIN(\"11111111\")"); - ASSERT_EQ(OCT("377"), 255, "OCT(\"377\")"); - ASSERT_EQ(ACOSH(2), 1.3169578969248166, "ACOSH(2)"); - ASSERT_EQ(ASINH(2), 1.4436354751788103, "ASINH(2)"); - ASSERT_EQ(ATANH(0.5), 0.5493061443340548, "ATANH(0.5)"); - ASSERT_EQ(COSH(2), 3.7621956910836314, "COSH(2)"); - ASSERT_EQ(SINH(2), 3.626860407847019, "SINH(2)"); - ASSERT_EQ(TANH(1), 0.7615941559557649, "TANH(1)"); - ASSERT_EQ(DIST(0, 0, 1, 1), 1.4142135623730951, "DIST(0, 0, 1, 1)"); - ASSERT_EQ(MAG(1, 1), 1.4142135623730951, "MAG(1, 1)"); - ASSERT_EQ(GAMMA(5), 2.0783258451246165, "GAMMA(5)"); - ASSERT_EQ(POSITIVE_CLAMP(-1), 0, "POSITIVE_CLAMP(-1)"); - ASSERT_EQ(NEGATIVE_CLAMP(1), 0, "NEGATIVE_CLAMP(1)"); - ASSERT_EQ(CLAMP(1, 0, 2), 1, "CLAMP(1, 0, 2)"); - ASSERT_EQ(CLAMP(-1, 0, 2), 0, "CLAMP(-1, 0, 2)"); - ASSERT_EQ(BIT(0, 255), 255, "BIT(0, 255)"); - ASSERT_EQ(LERP(0, 1, 0.5), 0.5, "LERP(0, 1, 0.5)"); - ASSERT_EQ(MAP(0, 1, 50, 100, 0.5), 75, "MAP(0, 1, 50, 100, 0.5)"); - ASSERT_EQ(RAD("90"), PI/2, "RAD(90)"); - ASSERT_EQ(DEG(PI/"2"), 90, "DEG(PI/2)"); - # string - ASSERT_EQ(countchar("AAA", "A"), 3, "countchar(...)"); - ASSERT_EQ(countchar("AAA", "B"), 0, "countchar(...)"); - ASSERT_EQ(countchars("AAA", "A"), 3, "countchars(...)"); - ASSERT_EQ(countchars("AAA", "B"), 0, "countchars(...)"); - ASSERT_EQ(slice("hello world", 1, 6), "hello", "slice(...)"); - ASSERT_EQ(slice("hello world", 7, 12), "world", "slice(...)"); - ASSERT_EQ(replace("lollollyllylollylly", "lolly", "LO"), "lolLOllyLOlly", "replace(...)"); - ASSERT_EQ(replacen("one one one", "one", "two", 2), "two two one", "lreplacen(...)"); - ASSERT_EQ(replacenth("one one one", "one", "two", 2), "one two one", "replacenth(...)"); - ASSERT_EQ(splice("hello world", 7, 5, "universe"), "hello universe", "1 splice(...)"); - ASSERT_EQ(splice("hello world", 7, 5, ""), "hello ", "2 splice(...)"); - ASSERT_EQ(uppercase("hello world"), "HELLO WORLD", "uppercase(...)"); - ASSERT_EQ(lowercase("HELLO WORLD"), "hello world", "lowercase(...)"); - ASSERT_EQ(capitalize("HELLO World"), "Hello world", "capitalize(...)"); - ASSERT_EQ(findchar("hello world", "l"), 3, "1 findchar(...)"); - ASSERT_EQ(findchar("hello world", "x"), 0, "2 findchar(...)"); - ASSERT_EQ(rfindchar("hello world", "l"), 10, "1 rfindchar(...)"); - ASSERT_EQ(rfindchar("hello world", "x"), 0, "2 rfindchar(...)"); - ASSERT_EQ(isalnum("Abc123"), true, "1 isalnum(...)"); - ASSERT_EQ(isalnum("Abc123!@#"), false, "2 isalnum(...)"); - ASSERT_EQ(isalnum(""), false, "3 isalnum(...)"); - ASSERT_EQ(isalpha("Abc"), true, "1 isalpha(...)"); - ASSERT_EQ(isalpha("Abc123"), false, "2 isalpha(...)"); - ASSERT_EQ(isalpha(""), false, "2 isalpha(...)"); - ASSERT_EQ(lstrip("www.example.com", "w."), "example.com", "1 lstrip(...)"); - ASSERT_EQ(lstrip(" hello ", " "), "hello ", "2 lstrip(...)"); - ASSERT_EQ(rstrip("www.example.com", ".com"), "www.example", "1 rstrip(...)"); - ASSERT_EQ(rstrip(" hello ", " "), " hello", "2 rstrip(...)"); - ASSERT_EQ(strip(" ", "< >"), "HELLO", "strip(...)"); - split "one,two,three,four,five", ","; - ASSERT_EQ(split[1], "one", "split(...)[1]"); - ASSERT_EQ(split[2], "two", "split(...)[2]"); - ASSERT_EQ(split[3], "three", "split(...)[3]"); - ASSERT_EQ(split[4], "four", "split(...)[4]"); - ASSERT_EQ(split[5], "five", "split(...)[5]"); - JOIN(split, ",", joined); - ASSERT_EQ(joined, "one,two,three,four,five", "JOIN(...)"); - ASSERT_EQ(reverse("hello"), "olleh", "reverse(...)"); - ASSERT_EQ(repeatstr("hello", 3), "hellohellohello", "repeatstr(...)"); - ASSERT_EQ(titlecase("hello world"), "Hello World", "titlecase(...)"); - splitlines ""; - ASSERT_EQ(length(split), 0, "1 splitlines(...)"); - splitlines "Two lines\n"; - ASSERT_EQ(length(split), 1, "1 splitlines(...)"); - ASSERT_EQ(split[1], "Two lines", "1 splitlines(...)"); - ASSERT_EQ(truncate("Hello world!", 12), "Hello world!", "1 shorten(...)"); - ASSERT_EQ(truncate("Hello world!", 11), "Hello ...", "2 shorten(...)"); - ASSERT_EQ(truncate("Hello world!", 10), "Hello...", "3 shorten(...)"); - # list - split "5,3,1,2,4", ","; - INSERTION_SORT(split); - JOIN(split, ",", joined); - ASSERT_EQ(joined, "1,2,3,4,5", "INSERTION_SORT(...)"); - delete points; - add point { x: 2, y: 200 } to points; - add point { x: 1, y: 100 } to points; - add point { x: 4, y: 400 } to points; - add point { x: 3, y: 300 } to points; - INSERTION_SORT_BY_FIELD(point, points, .x); - ASSERT_EQ(points[1].x, 1, "INSERTION_SORT_BY_FIELD(...)[1]"); - ASSERT_EQ(points[2].x, 2, "INSERTION_SORT_BY_FIELD(...)[2]"); - ASSERT_EQ(points[3].x, 3, "INSERTION_SORT_BY_FIELD(...)[3]"); - ASSERT_EQ(points[4].x, 4, "INSERTION_SORT_BY_FIELD(...)[4]"); - split "1,2,3,4,5", ","; - COUNT(split, split[i] % 2 == 0, count); - ASSERT_EQ(count, 2, "COUNT(...)"); - SUM(split, split[i] % 2 == 0, sum); - ASSERT_EQ(sum, 6, "SUM(...)"); - JOIN_BY_FIELD(points, .x, ",", joined); - ASSERT_EQ(joined, "1,2,3,4", "JOIN_BY_FIELD(...)"); - FINDMAX(split, split[i] % 2 == 0, max); - ASSERT_EQ(max, 4, "FINDMAX(...)"); - FINDMIN(split, split[i] % 2 == 0, min); - ASSERT_EQ(min, 2, "FINDMIN(...)"); - REVERSE(split); - JOIN(split, ",", joined); - ASSERT_EQ(joined, "5,4,3,2,1", "REVERSE(...)"); - COPY(split, things); - JOIN(things, ",", joined); - ASSERT_EQ(joined, "5,4,3,2,1", "COPY(...)"); - EXTEND(split, things); - JOIN(things, ",", joined); - ASSERT_EQ(joined, "5,4,3,2,1,5,4,3,2,1", "EXTEND(...)"); - UNIQUE(split); - JOIN(split, ",", joined); - ASSERT_EQ(joined, "5,4,3,2,1", "UNIQUE(...)"); - SUM_BY_FIELD(points, .x, points[i].x % 2 == 0, sum); - ASSERT_EQ(sum, 6, "SUM_BY_FIELD(...)"); - # TODO [BLOCKED BY]: https://github.com/aspizu/goboscript/issues/71 - #FINDMAX_BY_FIELD(point, points, .x, points[i] % 2 == 0, pmax); - #ASSERT_EQ(pmax.x, 4, "FINDMAX_BY_FIELD(...)"); - #FINDMIN_BY_FIELD(point, points, .x, points[i] % 2 == 0, pmin); - #ASSERT_EQ(pmin.x, 2, "FINDMIN_BY_FIELD(...)"); - add point { x: 2, y: 200 } to points; - add point { x: 1, y: 100 } to points; - add point { x: 4, y: 400 } to points; - UNIQUE_BY_FIELD(points, .x); - JOIN_BY_FIELD(points, .x, ",", joined); - ASSERT_EQ(joined, "1,2,3,4", "UNIQUE_BY_FIELD(...)"); - ASSERT_EQ(ENDSWITH("hello world", "world"), "true", "1 ENDSWITH(...)"); - ASSERT_EQ(ENDSWITH("hello world", "hello"), "false", "2 ENDSWITH(...)"); - ASSERT_EQ(STARTSWITH("hello world", "hello"), "true", "1 STARTSWITH(...)"); - ASSERT_EQ(STARTSWITH("hello world", "world"), "false", "2 STARTSWITH(...)"); - ASSERT_EQ(REMOVEPREFIX("hello world", "hello"), " world", "REMOVEPREFIX(...)"); - ASSERT_EQ(REMOVESUFFIX("hello world", "world"), "hello ", "REMOVESUFFIX(...)"); - # emoji - if EMOJI("football") != "🏈" { - add "football" to console; - } - if EMOJI("ping_pong") != "🏓" { - add "ping_pong" to console; - } - if EMOJI("soccer") != "⚽" { - add "soccer" to console; - } - if EMOJI("basketball") != "🏀" { - add "basketball" to console; - } - # cskv - cskv_unpack "a:1,b:2,array:3,A,B,C,c:3"; - ASSERT_EQ(cskv_pack(), "a:1,b:2,array:3,A,B,C,c:3", "cskv_pack(...)"); - # cmd - local cmd = "echo -n 'Multiple \\' words'; echo -n 'Single \\\\' word' \\' \\;"; - i = cmd_next(1, cmd); - ASSERT_EQ(cmd_args[1], "echo", "cmd_args[1]"); - ASSERT_EQ(cmd_args[2], "-n", "cmd_args[2]"); - ASSERT_EQ(cmd_args[3], "Multiple \\' words", "cmd_args[3]"); - i = cmd_next(i, cmd); - ASSERT_EQ(cmd_args[1], "echo", "cmd_args[1]"); - ASSERT_EQ(cmd_args[2], "-n", "cmd_args[2]"); - ASSERT_EQ(cmd_args[3], "Single \\\\' word", "cmd_args[3]"); - ASSERT_EQ(cmd_args[4], "'", "cmd_args[4]"); - ASSERT_EQ(cmd_args[5], ";", "cmd_args[5]"); -} - -onflag { - delete console; - show console; - test; -} diff --git a/test/test.py b/test/test.py new file mode 100644 index 0000000..2c17a2e --- /dev/null +++ b/test/test.py @@ -0,0 +1,146 @@ +import argparse +import hashlib +import pathlib +import shlex +import shutil +import subprocess +import sys +import tempfile + +BLANK_SVG = '\n' +STAGE_GS = 'costumes "blank.svg";\n' +MAIN_GS = """\ +costumes "blank.svg" as "@ascii/"; + +%include lib/test.gs + +func __testing_eq(a, b) { + if length($a) != length($b) { + return false; + } + local i = 1; + repeat length($a) { + switch_costume $a; + local c = costume_number(); + switch_costume $b; + if c != costume_number() { + return false; + } + i++; + } + return true; +} + +proc expect expr, value, to_be { + if not __testing_eq($value+"", $to_be+"") { + error "expected `" & $expr & "` to be `" & $to_be & "` but got `" & $value & "`"; + } +} + +proc expect_true expr, value { + if not $value { + error "expected `" & $expr & "` to be true but got `" & $value & "`"; + } +} + +proc expect_false expr, value { + if $value { + error "expected `" & $expr & "` to be false but got `" & $value & "`"; + } +} + +func _(value) { + return $value; +} + +onflag { + test; +} +""" + + +def resolve_includes( + input: pathlib.Path, + libdir: pathlib.Path, + prefix_map: dict[str, str] | None = None, +) -> None: + prefix_map = prefix_map or {} + parent_dir = input.parent + lines = input.read_text().splitlines() + result = [] + for line in lines: + if line.startswith("%include "): + include_path_str = line[len("%include ") :].strip() + + # Apply prefix remapping before any other resolution. + for from_prefix, to_prefix in prefix_map.items(): + if include_path_str.startswith(from_prefix): + include_path_str = to_prefix + include_path_str[len(from_prefix) :] + break + + if include_path_str.startswith("std/"): + result.append(f"%include {include_path_str}") + continue + + resolved = parent_dir.joinpath(include_path_str).resolve() + if not resolved.exists(): + result.append(f"%include {include_path_str}") + continue + + file_hash = hashlib.md5(str(resolved).encode()).hexdigest() + dest = libdir.joinpath(f"{file_hash}.gs") + if not dest.exists(): + shutil.copy2(resolved, dest) + result.append(f"%include lib/{file_hash}.gs") + else: + result.append(line) + result.append("") + libdir.joinpath("test.gs").write_text("\n".join(result)) + + +def parse_prefix_map(pairs: list[str]) -> dict[str, str]: + """Parse a list of 'from=to' strings into a prefix mapping dict.""" + mapping: dict[str, str] = {} + for pair in pairs: + if "=" not in pair: + sys.stderr.write(f"invalid --map entry (expected 'from=to'): {pair!r}\n") + sys.exit(1) + from_prefix, _, to_prefix = pair.partition("=") + mapping[from_prefix] = to_prefix + return mapping + + +argparser = argparse.ArgumentParser() +argparser.add_argument("input", type=pathlib.Path) +argparser.add_argument( + "--map", + metavar="FROM=TO", + action="append", + default=[], + dest="prefix_map", + help=( + "Remap an import prefix before resolution. " + "May be specified multiple times. " + "Example: --map vendor/=../../third_party/" + ), +) +args = argparser.parse_args() +input: pathlib.Path = args.input +if input.suffixes != [".test", ".gs"]: + sys.stderr.write("input must be a `.test.gs` file\n") + sys.exit(1) + +prefix_map = parse_prefix_map(args.prefix_map) +prefix_map["std/"] = "../" + +with tempfile.TemporaryDirectory() as tmpdir: + tmpdir = pathlib.Path(tmpdir) + tmpdir.joinpath("blank.svg").write_text(BLANK_SVG) + tmpdir.joinpath("stage.gs").write_text(STAGE_GS) + libdir = tmpdir.joinpath("lib") + libdir.mkdir() + resolve_includes(input, libdir, prefix_map) + tmpdir.joinpath("main.gs").write_text(MAIN_GS) + subprocess.run(shlex.split("goboscript build"), cwd=tmpdir).check_returncode() + subprocess.run(shlex.split("tw load"), cwd=tmpdir).check_returncode() + subprocess.run(shlex.split("tw start --listen")).check_returncode() diff --git a/uuid.gs b/uuid.gs index 5b8cf77..f7ef719 100644 --- a/uuid.gs +++ b/uuid.gs @@ -4,10 +4,13 @@ %define UUID_RANDHEX4 UUID_RANDHEX2 & UUID_RANDHEX2 %define UUID_RANDHEX8 UUID_RANDHEX4 & UUID_RANDHEX4 %define UUID_RANDHEX12 UUID_RANDHEX8 & UUID_RANDHEX4 -%define UUID_V4 UUID_RANDHEX8 \ - & "-" & UUID_RANDHEX4 \ - & "-4" & UUID_RANDHEX3 \ - & "-" & "89AB"[random(1, 4)] & UUID_RANDHEX3 \ - & "-" & UUID_RANDHEX12 %define UUID_NIL "00000000-0000-0000-0000-000000000000" %define UUID_MAX "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF" + +func uuid_v4() { + return UUID_RANDHEX8 + & "-" & UUID_RANDHEX4 + & "-4" & UUID_RANDHEX3 + & "-" & "89AB"[random(1, 4)] & UUID_RANDHEX3 + & "-" & UUID_RANDHEX12; +}