diff --git a/app/build.gradle b/app/build.gradle index 2bbb2ae2c6..fceadbdf03 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -270,6 +270,8 @@ dependencies { implementation("com.google.dagger:hilt-android:$daggerHiltVersion") implementation "androidx.appcompat:appcompat:$appcompatVersion" + implementation "androidx.emoji2:emoji2:$emoji2Version" + implementation "androidx.emoji2:emoji2-emojipicker:$emoji2Version" implementation 'androidx.recyclerview:recyclerview:1.4.0' implementation "com.google.android.material:material:$materialVersion" implementation 'com.google.android.flexbox:flexbox:3.0.0' diff --git a/app/src/main/assets/emoji/Activity.png b/app/src/main/assets/emoji/Activity.png deleted file mode 100644 index 5a8eb12ca5..0000000000 Binary files a/app/src/main/assets/emoji/Activity.png and /dev/null differ diff --git a/app/src/main/assets/emoji/Activity.webp b/app/src/main/assets/emoji/Activity.webp deleted file mode 100644 index 4db973ff49..0000000000 Binary files a/app/src/main/assets/emoji/Activity.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/Flags.png b/app/src/main/assets/emoji/Flags.png deleted file mode 100644 index 25c685d9cd..0000000000 Binary files a/app/src/main/assets/emoji/Flags.png and /dev/null differ diff --git a/app/src/main/assets/emoji/Flags_0.webp b/app/src/main/assets/emoji/Flags_0.webp deleted file mode 100644 index b170104812..0000000000 Binary files a/app/src/main/assets/emoji/Flags_0.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/Flags_1.webp b/app/src/main/assets/emoji/Flags_1.webp deleted file mode 100644 index f8e73daecd..0000000000 Binary files a/app/src/main/assets/emoji/Flags_1.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/Foods.png b/app/src/main/assets/emoji/Foods.png deleted file mode 100644 index 56345a6683..0000000000 Binary files a/app/src/main/assets/emoji/Foods.png and /dev/null differ diff --git a/app/src/main/assets/emoji/Foods.webp b/app/src/main/assets/emoji/Foods.webp deleted file mode 100644 index 72199546dd..0000000000 Binary files a/app/src/main/assets/emoji/Foods.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/Nature.png b/app/src/main/assets/emoji/Nature.png deleted file mode 100644 index 91fca3620c..0000000000 Binary files a/app/src/main/assets/emoji/Nature.png and /dev/null differ diff --git a/app/src/main/assets/emoji/Nature.webp b/app/src/main/assets/emoji/Nature.webp deleted file mode 100644 index e2a07a6162..0000000000 Binary files a/app/src/main/assets/emoji/Nature.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/Objects.png b/app/src/main/assets/emoji/Objects.png deleted file mode 100644 index 8b34016852..0000000000 Binary files a/app/src/main/assets/emoji/Objects.png and /dev/null differ diff --git a/app/src/main/assets/emoji/Objects.webp b/app/src/main/assets/emoji/Objects.webp deleted file mode 100644 index 0b264e16e5..0000000000 Binary files a/app/src/main/assets/emoji/Objects.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/People_0.png b/app/src/main/assets/emoji/People_0.png deleted file mode 100644 index 726d72ca2e..0000000000 Binary files a/app/src/main/assets/emoji/People_0.png and /dev/null differ diff --git a/app/src/main/assets/emoji/People_0.webp b/app/src/main/assets/emoji/People_0.webp deleted file mode 100644 index d684f3fcac..0000000000 Binary files a/app/src/main/assets/emoji/People_0.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/People_1.png b/app/src/main/assets/emoji/People_1.png deleted file mode 100644 index 3ffa9482e7..0000000000 Binary files a/app/src/main/assets/emoji/People_1.png and /dev/null differ diff --git a/app/src/main/assets/emoji/People_1.webp b/app/src/main/assets/emoji/People_1.webp deleted file mode 100644 index 655bfcc512..0000000000 Binary files a/app/src/main/assets/emoji/People_1.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/People_2.png b/app/src/main/assets/emoji/People_2.png deleted file mode 100644 index 0743a57028..0000000000 Binary files a/app/src/main/assets/emoji/People_2.png and /dev/null differ diff --git a/app/src/main/assets/emoji/People_2.webp b/app/src/main/assets/emoji/People_2.webp deleted file mode 100644 index 546179fbbf..0000000000 Binary files a/app/src/main/assets/emoji/People_2.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/People_3.png b/app/src/main/assets/emoji/People_3.png deleted file mode 100644 index 9436308307..0000000000 Binary files a/app/src/main/assets/emoji/People_3.png and /dev/null differ diff --git a/app/src/main/assets/emoji/People_3.webp b/app/src/main/assets/emoji/People_3.webp deleted file mode 100644 index 0fc68ab1a8..0000000000 Binary files a/app/src/main/assets/emoji/People_3.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/People_4.webp b/app/src/main/assets/emoji/People_4.webp deleted file mode 100644 index 2ee56dd2e9..0000000000 Binary files a/app/src/main/assets/emoji/People_4.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/People_5.webp b/app/src/main/assets/emoji/People_5.webp deleted file mode 100644 index 4810e2fcbb..0000000000 Binary files a/app/src/main/assets/emoji/People_5.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/People_6.webp b/app/src/main/assets/emoji/People_6.webp deleted file mode 100644 index 2343cfb87b..0000000000 Binary files a/app/src/main/assets/emoji/People_6.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/People_7.webp b/app/src/main/assets/emoji/People_7.webp deleted file mode 100644 index 28a70ae90a..0000000000 Binary files a/app/src/main/assets/emoji/People_7.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/People_8.webp b/app/src/main/assets/emoji/People_8.webp deleted file mode 100644 index ea2cdada5c..0000000000 Binary files a/app/src/main/assets/emoji/People_8.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/People_9.webp b/app/src/main/assets/emoji/People_9.webp deleted file mode 100644 index fb3333f2b4..0000000000 Binary files a/app/src/main/assets/emoji/People_9.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/Places.png b/app/src/main/assets/emoji/Places.png deleted file mode 100644 index 3375ae8884..0000000000 Binary files a/app/src/main/assets/emoji/Places.png and /dev/null differ diff --git a/app/src/main/assets/emoji/Places.webp b/app/src/main/assets/emoji/Places.webp deleted file mode 100644 index 5dc763b2b6..0000000000 Binary files a/app/src/main/assets/emoji/Places.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/Symbols.png b/app/src/main/assets/emoji/Symbols.png deleted file mode 100644 index 9dfb91c8c0..0000000000 Binary files a/app/src/main/assets/emoji/Symbols.png and /dev/null differ diff --git a/app/src/main/assets/emoji/Symbols.webp b/app/src/main/assets/emoji/Symbols.webp deleted file mode 100644 index 091017a19b..0000000000 Binary files a/app/src/main/assets/emoji/Symbols.webp and /dev/null differ diff --git a/app/src/main/assets/emoji/emoji_data.json b/app/src/main/assets/emoji/emoji_data.json deleted file mode 100644 index 62059254eb..0000000000 --- a/app/src/main/assets/emoji/emoji_data.json +++ /dev/null @@ -1 +0,0 @@ -{"emoji":{"People_0":[["d83dde00"],["d83dde03"],["d83dde04"],["d83dde01"],["d83dde06"],["d83dde05"],["d83edd23"],["d83dde02"],["d83dde42"],["d83dde43"],["d83edee0"],["d83dde09"],["d83dde0a"],["d83dde07"],["d83edd70"],["d83dde0d"],["d83edd29"],["d83dde18"],["d83dde17"],["263afe0f"],["d83dde1a"],["d83dde19"],["d83edd72"],["d83dde0b"],["d83dde1b"],["d83dde1c"],["d83edd2a"],["d83dde1d"],["d83edd11"],["d83edd17"],["d83edd2d"],["d83edee2"],["d83edee3"],["d83edd2b"],["d83edd14"],["d83edee1"],["d83edd10"],["d83edd28"],["d83dde10"],["d83dde11"],["d83dde36"],["d83edee5"],["d83dde36200dd83cdf2bfe0f"],["d83dde0f"],["d83dde12"],["d83dde44"],["d83dde2c"],["d83dde2e200dd83ddca8"],["d83edd25"],["d83dde0c"],["d83dde14"],["d83dde2a"],["d83edd24"],["d83dde34"],["d83dde37"],["d83edd12"],["d83edd15"],["d83edd22"],["d83edd2e"],["d83edd27"],["d83edd75"],["d83edd76"],["d83edd74"],["d83dde35"],["d83dde35200dd83ddcab"],["d83edd2f"],["d83edd20"],["d83edd73"],["d83edd78"],["d83dde0e"],["d83edd13"],["d83eddd0"],["d83dde15"],["d83edee4"],["d83dde1f"],["d83dde41"],["2639fe0f"],["d83dde2e"],["d83dde2f"],["d83dde32"],["d83dde33"],["d83edd7a"],["d83edd79"],["d83dde26"],["d83dde27"],["d83dde28"],["d83dde30"],["d83dde25"],["d83dde22"],["d83dde2d"],["d83dde31"],["d83dde16"],["d83dde23"],["d83dde1e"],["d83dde13"],["d83dde29"],["d83dde2b"],["d83edd71"],["d83dde24"],["d83dde21"],["d83dde20"],["d83edd2c"],["d83dde08"],["d83ddc7f"],["d83ddc80"],["2620fe0f"],["d83ddca9"],["d83edd21"],["d83ddc79"],["d83ddc7a"],["d83ddc7b"],["d83ddc7d"],["d83ddc7e"],["d83edd16"],["d83dde3a"],["d83dde38"],["d83dde39"],["d83dde3b"],["d83dde3c"],["d83dde3d"],["d83dde40"],["d83dde3f"],["d83dde3e"],["d83dde48"],["d83dde49"],["d83dde4a"],["d83ddc8b"],["d83ddc8c"],["d83ddc98"],["d83ddc9d"],["d83ddc96"],["d83ddc97"],["d83ddc93"],["d83ddc9e"],["d83ddc95"],["d83ddc9f"],["2763fe0f"],["d83ddc94"],["2764fe0f200dd83ddd25"],["2764fe0f200dd83ede79"],["2764fe0f"],["d83edde1"],["d83ddc9b"],["d83ddc9a"],["d83ddc99"],["d83ddc9c"],["d83edd0e"],["d83ddda4"],["d83edd0d"],["d83ddcaf"],["d83ddca2"],["d83ddca5"],["d83ddcab"],["d83ddca6"],["d83ddca8"],["d83ddd73fe0f"],["d83ddca3"],["d83ddcac"],["d83ddc41fe0f200dd83ddde8fe0f"],["d83ddde8fe0f"],["d83dddeffe0f"],["d83ddcad"],["d83ddca4"],["d83ddc4b","d83ddc4bd83cdffb","d83ddc4bd83cdffc","d83ddc4bd83cdffd","d83ddc4bd83cdffe","d83ddc4bd83cdfff"],["d83edd1a","d83edd1ad83cdffb","d83edd1ad83cdffc","d83edd1ad83cdffd","d83edd1ad83cdffe","d83edd1ad83cdfff"],["d83ddd90fe0f","d83ddd90d83cdffb","d83ddd90d83cdffc","d83ddd90d83cdffd","d83ddd90d83cdffe","d83ddd90d83cdfff"],["270b","270bd83cdffb","270bd83cdffc","270bd83cdffd","270bd83cdffe","270bd83cdfff"],["d83ddd96","d83ddd96d83cdffb","d83ddd96d83cdffc","d83ddd96d83cdffd","d83ddd96d83cdffe","d83ddd96d83cdfff"],["d83edef1","d83edef1d83cdffb","d83edef1d83cdffc","d83edef1d83cdffd","d83edef1d83cdffe","d83edef1d83cdfff"],["d83edef2","d83edef2d83cdffb","d83edef2d83cdffc","d83edef2d83cdffd","d83edef2d83cdffe","d83edef2d83cdfff"],["d83edef3","d83edef3d83cdffb","d83edef3d83cdffc","d83edef3d83cdffd","d83edef3d83cdffe","d83edef3d83cdfff"],["d83edef4","d83edef4d83cdffb","d83edef4d83cdffc","d83edef4d83cdffd","d83edef4d83cdffe","d83edef4d83cdfff"],["d83ddc4c","d83ddc4cd83cdffb","d83ddc4cd83cdffc","d83ddc4cd83cdffd","d83ddc4cd83cdffe","d83ddc4cd83cdfff"],["d83edd0c","d83edd0cd83cdffb","d83edd0cd83cdffc","d83edd0cd83cdffd","d83edd0cd83cdffe","d83edd0cd83cdfff"],["d83edd0f","d83edd0fd83cdffb","d83edd0fd83cdffc","d83edd0fd83cdffd","d83edd0fd83cdffe","d83edd0fd83cdfff"],["270cfe0f","270cd83cdffb","270cd83cdffc","270cd83cdffd","270cd83cdffe","270cd83cdfff"],["d83edd1e","d83edd1ed83cdffb","d83edd1ed83cdffc","d83edd1ed83cdffd","d83edd1ed83cdffe","d83edd1ed83cdfff"],["d83edef0","d83edef0d83cdffb","d83edef0d83cdffc","d83edef0d83cdffd","d83edef0d83cdffe","d83edef0d83cdfff"]],"People_1":[["d83edd1f","d83edd1fd83cdffb","d83edd1fd83cdffc","d83edd1fd83cdffd","d83edd1fd83cdffe","d83edd1fd83cdfff"],["d83edd18","d83edd18d83cdffb","d83edd18d83cdffc","d83edd18d83cdffd","d83edd18d83cdffe","d83edd18d83cdfff"],["d83edd19","d83edd19d83cdffb","d83edd19d83cdffc","d83edd19d83cdffd","d83edd19d83cdffe","d83edd19d83cdfff"],["d83ddc48","d83ddc48d83cdffb","d83ddc48d83cdffc","d83ddc48d83cdffd","d83ddc48d83cdffe","d83ddc48d83cdfff"],["d83ddc49","d83ddc49d83cdffb","d83ddc49d83cdffc","d83ddc49d83cdffd","d83ddc49d83cdffe","d83ddc49d83cdfff"],["d83ddc46","d83ddc46d83cdffb","d83ddc46d83cdffc","d83ddc46d83cdffd","d83ddc46d83cdffe","d83ddc46d83cdfff"],["d83ddd95","d83ddd95d83cdffb","d83ddd95d83cdffc","d83ddd95d83cdffd","d83ddd95d83cdffe","d83ddd95d83cdfff"],["d83ddc47","d83ddc47d83cdffb","d83ddc47d83cdffc","d83ddc47d83cdffd","d83ddc47d83cdffe","d83ddc47d83cdfff"],["261dfe0f","261dd83cdffb","261dd83cdffc","261dd83cdffd","261dd83cdffe","261dd83cdfff"],["d83edef5","d83edef5d83cdffb","d83edef5d83cdffc","d83edef5d83cdffd","d83edef5d83cdffe","d83edef5d83cdfff"],["d83ddc4d","d83ddc4dd83cdffb","d83ddc4dd83cdffc","d83ddc4dd83cdffd","d83ddc4dd83cdffe","d83ddc4dd83cdfff"],["d83ddc4e","d83ddc4ed83cdffb","d83ddc4ed83cdffc","d83ddc4ed83cdffd","d83ddc4ed83cdffe","d83ddc4ed83cdfff"],["270a","270ad83cdffb","270ad83cdffc","270ad83cdffd","270ad83cdffe","270ad83cdfff"],["d83ddc4a","d83ddc4ad83cdffb","d83ddc4ad83cdffc","d83ddc4ad83cdffd","d83ddc4ad83cdffe","d83ddc4ad83cdfff"],["d83edd1b","d83edd1bd83cdffb","d83edd1bd83cdffc","d83edd1bd83cdffd","d83edd1bd83cdffe","d83edd1bd83cdfff"],["d83edd1c","d83edd1cd83cdffb","d83edd1cd83cdffc","d83edd1cd83cdffd","d83edd1cd83cdffe","d83edd1cd83cdfff"],["d83ddc4f","d83ddc4fd83cdffb","d83ddc4fd83cdffc","d83ddc4fd83cdffd","d83ddc4fd83cdffe","d83ddc4fd83cdfff"],["d83dde4c","d83dde4cd83cdffb","d83dde4cd83cdffc","d83dde4cd83cdffd","d83dde4cd83cdffe","d83dde4cd83cdfff"],["d83edef6","d83edef6d83cdffb","d83edef6d83cdffc","d83edef6d83cdffd","d83edef6d83cdffe","d83edef6d83cdfff"],["d83ddc50","d83ddc50d83cdffb","d83ddc50d83cdffc","d83ddc50d83cdffd","d83ddc50d83cdffe","d83ddc50d83cdfff"],["d83edd32","d83edd32d83cdffb","d83edd32d83cdffc","d83edd32d83cdffd","d83edd32d83cdffe","d83edd32d83cdfff"],["d83edd1d","d83edd1dd83cdffb","d83edd1dd83cdffc","d83edd1dd83cdffd","d83edd1dd83cdffe","d83edd1dd83cdfff","d83edef1d83cdffb200dd83edef2d83cdffc","d83edef1d83cdffb200dd83edef2d83cdffd","d83edef1d83cdffb200dd83edef2d83cdffe","d83edef1d83cdffb200dd83edef2d83cdfff","d83edef1d83cdffc200dd83edef2d83cdffb","d83edef1d83cdffc200dd83edef2d83cdffd","d83edef1d83cdffc200dd83edef2d83cdffe","d83edef1d83cdffc200dd83edef2d83cdfff","d83edef1d83cdffd200dd83edef2d83cdffb","d83edef1d83cdffd200dd83edef2d83cdffc","d83edef1d83cdffd200dd83edef2d83cdffe","d83edef1d83cdffd200dd83edef2d83cdfff","d83edef1d83cdffe200dd83edef2d83cdffb","d83edef1d83cdffe200dd83edef2d83cdffc","d83edef1d83cdffe200dd83edef2d83cdffd","d83edef1d83cdffe200dd83edef2d83cdfff","d83edef1d83cdfff200dd83edef2d83cdffb","d83edef1d83cdfff200dd83edef2d83cdffc","d83edef1d83cdfff200dd83edef2d83cdffd","d83edef1d83cdfff200dd83edef2d83cdffe"],["d83dde4f","d83dde4fd83cdffb","d83dde4fd83cdffc","d83dde4fd83cdffd","d83dde4fd83cdffe","d83dde4fd83cdfff"],["270dfe0f","270dd83cdffb","270dd83cdffc","270dd83cdffd","270dd83cdffe","270dd83cdfff"],["d83ddc85","d83ddc85d83cdffb","d83ddc85d83cdffc","d83ddc85d83cdffd","d83ddc85d83cdffe","d83ddc85d83cdfff"],["d83edd33","d83edd33d83cdffb","d83edd33d83cdffc","d83edd33d83cdffd","d83edd33d83cdffe","d83edd33d83cdfff"],["d83ddcaa","d83ddcaad83cdffb","d83ddcaad83cdffc","d83ddcaad83cdffd","d83ddcaad83cdffe","d83ddcaad83cdfff"],["d83eddbe"],["d83eddbf"],["d83eddb5","d83eddb5d83cdffb","d83eddb5d83cdffc","d83eddb5d83cdffd","d83eddb5d83cdffe","d83eddb5d83cdfff"],["d83eddb6","d83eddb6d83cdffb","d83eddb6d83cdffc","d83eddb6d83cdffd","d83eddb6d83cdffe","d83eddb6d83cdfff"],["d83ddc42","d83ddc42d83cdffb","d83ddc42d83cdffc","d83ddc42d83cdffd","d83ddc42d83cdffe","d83ddc42d83cdfff"],["d83eddbb","d83eddbbd83cdffb","d83eddbbd83cdffc","d83eddbbd83cdffd","d83eddbbd83cdffe","d83eddbbd83cdfff"],["d83ddc43","d83ddc43d83cdffb","d83ddc43d83cdffc","d83ddc43d83cdffd","d83ddc43d83cdffe","d83ddc43d83cdfff"],["d83edde0"],["d83edec0"],["d83edec1"],["d83eddb7"],["d83eddb4"],["d83ddc40"],["d83ddc41fe0f"],["d83ddc45"],["d83ddc44"],["d83edee6"],["d83ddc76","d83ddc76d83cdffb","d83ddc76d83cdffc","d83ddc76d83cdffd","d83ddc76d83cdffe","d83ddc76d83cdfff"],["d83eddd2","d83eddd2d83cdffb","d83eddd2d83cdffc","d83eddd2d83cdffd","d83eddd2d83cdffe","d83eddd2d83cdfff"],["d83ddc66","d83ddc66d83cdffb","d83ddc66d83cdffc","d83ddc66d83cdffd","d83ddc66d83cdffe","d83ddc66d83cdfff"],["d83ddc67","d83ddc67d83cdffb","d83ddc67d83cdffc","d83ddc67d83cdffd","d83ddc67d83cdffe","d83ddc67d83cdfff"],["d83eddd1","d83eddd1d83cdffb","d83eddd1d83cdffc","d83eddd1d83cdffd","d83eddd1d83cdffe","d83eddd1d83cdfff"]],"People_2":[["d83ddc71","d83ddc71d83cdffb","d83ddc71d83cdffc","d83ddc71d83cdffd","d83ddc71d83cdffe","d83ddc71d83cdfff"],["d83ddc68","d83ddc68d83cdffb","d83ddc68d83cdffc","d83ddc68d83cdffd","d83ddc68d83cdffe","d83ddc68d83cdfff"],["d83eddd4","d83eddd4d83cdffb","d83eddd4d83cdffc","d83eddd4d83cdffd","d83eddd4d83cdffe","d83eddd4d83cdfff"],["d83eddd4200d2642fe0f","d83eddd4d83cdffb200d2642fe0f","d83eddd4d83cdffc200d2642fe0f","d83eddd4d83cdffd200d2642fe0f","d83eddd4d83cdffe200d2642fe0f","d83eddd4d83cdfff200d2642fe0f"],["d83eddd4200d2640fe0f","d83eddd4d83cdffb200d2640fe0f","d83eddd4d83cdffc200d2640fe0f","d83eddd4d83cdffd200d2640fe0f","d83eddd4d83cdffe200d2640fe0f","d83eddd4d83cdfff200d2640fe0f"],["d83ddc68200dd83eddb0","d83ddc68d83cdffb200dd83eddb0","d83ddc68d83cdffc200dd83eddb0","d83ddc68d83cdffd200dd83eddb0","d83ddc68d83cdffe200dd83eddb0","d83ddc68d83cdfff200dd83eddb0"],["d83ddc68200dd83eddb1","d83ddc68d83cdffb200dd83eddb1","d83ddc68d83cdffc200dd83eddb1","d83ddc68d83cdffd200dd83eddb1","d83ddc68d83cdffe200dd83eddb1","d83ddc68d83cdfff200dd83eddb1"],["d83ddc68200dd83eddb3","d83ddc68d83cdffb200dd83eddb3","d83ddc68d83cdffc200dd83eddb3","d83ddc68d83cdffd200dd83eddb3","d83ddc68d83cdffe200dd83eddb3","d83ddc68d83cdfff200dd83eddb3"],["d83ddc68200dd83eddb2","d83ddc68d83cdffb200dd83eddb2","d83ddc68d83cdffc200dd83eddb2","d83ddc68d83cdffd200dd83eddb2","d83ddc68d83cdffe200dd83eddb2","d83ddc68d83cdfff200dd83eddb2"],["d83ddc69","d83ddc69d83cdffb","d83ddc69d83cdffc","d83ddc69d83cdffd","d83ddc69d83cdffe","d83ddc69d83cdfff"],["d83ddc69200dd83eddb0","d83ddc69d83cdffb200dd83eddb0","d83ddc69d83cdffc200dd83eddb0","d83ddc69d83cdffd200dd83eddb0","d83ddc69d83cdffe200dd83eddb0","d83ddc69d83cdfff200dd83eddb0"],["d83eddd1200dd83eddb0","d83eddd1d83cdffb200dd83eddb0","d83eddd1d83cdffc200dd83eddb0","d83eddd1d83cdffd200dd83eddb0","d83eddd1d83cdffe200dd83eddb0","d83eddd1d83cdfff200dd83eddb0"],["d83ddc69200dd83eddb1","d83ddc69d83cdffb200dd83eddb1","d83ddc69d83cdffc200dd83eddb1","d83ddc69d83cdffd200dd83eddb1","d83ddc69d83cdffe200dd83eddb1","d83ddc69d83cdfff200dd83eddb1"],["d83eddd1200dd83eddb1","d83eddd1d83cdffb200dd83eddb1","d83eddd1d83cdffc200dd83eddb1","d83eddd1d83cdffd200dd83eddb1","d83eddd1d83cdffe200dd83eddb1","d83eddd1d83cdfff200dd83eddb1"],["d83ddc69200dd83eddb3","d83ddc69d83cdffb200dd83eddb3","d83ddc69d83cdffc200dd83eddb3","d83ddc69d83cdffd200dd83eddb3","d83ddc69d83cdffe200dd83eddb3","d83ddc69d83cdfff200dd83eddb3"],["d83eddd1200dd83eddb3","d83eddd1d83cdffb200dd83eddb3","d83eddd1d83cdffc200dd83eddb3","d83eddd1d83cdffd200dd83eddb3","d83eddd1d83cdffe200dd83eddb3","d83eddd1d83cdfff200dd83eddb3"],["d83ddc69200dd83eddb2","d83ddc69d83cdffb200dd83eddb2","d83ddc69d83cdffc200dd83eddb2","d83ddc69d83cdffd200dd83eddb2","d83ddc69d83cdffe200dd83eddb2","d83ddc69d83cdfff200dd83eddb2"],["d83eddd1200dd83eddb2","d83eddd1d83cdffb200dd83eddb2","d83eddd1d83cdffc200dd83eddb2","d83eddd1d83cdffd200dd83eddb2","d83eddd1d83cdffe200dd83eddb2","d83eddd1d83cdfff200dd83eddb2"],["d83ddc71200d2640fe0f","d83ddc71d83cdffb200d2640fe0f","d83ddc71d83cdffc200d2640fe0f","d83ddc71d83cdffd200d2640fe0f","d83ddc71d83cdffe200d2640fe0f","d83ddc71d83cdfff200d2640fe0f"],["d83ddc71200d2642fe0f","d83ddc71d83cdffb200d2642fe0f","d83ddc71d83cdffc200d2642fe0f","d83ddc71d83cdffd200d2642fe0f","d83ddc71d83cdffe200d2642fe0f","d83ddc71d83cdfff200d2642fe0f"],["d83eddd3","d83eddd3d83cdffb","d83eddd3d83cdffc","d83eddd3d83cdffd","d83eddd3d83cdffe","d83eddd3d83cdfff"],["d83ddc74","d83ddc74d83cdffb","d83ddc74d83cdffc","d83ddc74d83cdffd","d83ddc74d83cdffe","d83ddc74d83cdfff"],["d83ddc75","d83ddc75d83cdffb","d83ddc75d83cdffc","d83ddc75d83cdffd","d83ddc75d83cdffe","d83ddc75d83cdfff"],["d83dde4d","d83dde4dd83cdffb","d83dde4dd83cdffc","d83dde4dd83cdffd","d83dde4dd83cdffe","d83dde4dd83cdfff"],["d83dde4d200d2642fe0f","d83dde4dd83cdffb200d2642fe0f","d83dde4dd83cdffc200d2642fe0f","d83dde4dd83cdffd200d2642fe0f","d83dde4dd83cdffe200d2642fe0f","d83dde4dd83cdfff200d2642fe0f"],["d83dde4d200d2640fe0f","d83dde4dd83cdffb200d2640fe0f","d83dde4dd83cdffc200d2640fe0f","d83dde4dd83cdffd200d2640fe0f","d83dde4dd83cdffe200d2640fe0f","d83dde4dd83cdfff200d2640fe0f"],["d83dde4e","d83dde4ed83cdffb","d83dde4ed83cdffc","d83dde4ed83cdffd","d83dde4ed83cdffe","d83dde4ed83cdfff"],["d83dde4e200d2642fe0f","d83dde4ed83cdffb200d2642fe0f","d83dde4ed83cdffc200d2642fe0f","d83dde4ed83cdffd200d2642fe0f","d83dde4ed83cdffe200d2642fe0f","d83dde4ed83cdfff200d2642fe0f"],["d83dde4e200d2640fe0f","d83dde4ed83cdffb200d2640fe0f","d83dde4ed83cdffc200d2640fe0f","d83dde4ed83cdffd200d2640fe0f","d83dde4ed83cdffe200d2640fe0f","d83dde4ed83cdfff200d2640fe0f"],["d83dde45","d83dde45d83cdffb","d83dde45d83cdffc","d83dde45d83cdffd","d83dde45d83cdffe","d83dde45d83cdfff"],["d83dde45200d2642fe0f","d83dde45d83cdffb200d2642fe0f","d83dde45d83cdffc200d2642fe0f","d83dde45d83cdffd200d2642fe0f","d83dde45d83cdffe200d2642fe0f","d83dde45d83cdfff200d2642fe0f"],["d83dde45200d2640fe0f","d83dde45d83cdffb200d2640fe0f","d83dde45d83cdffc200d2640fe0f","d83dde45d83cdffd200d2640fe0f","d83dde45d83cdffe200d2640fe0f","d83dde45d83cdfff200d2640fe0f"],["d83dde46","d83dde46d83cdffb","d83dde46d83cdffc","d83dde46d83cdffd","d83dde46d83cdffe","d83dde46d83cdfff"],["d83dde46200d2642fe0f","d83dde46d83cdffb200d2642fe0f","d83dde46d83cdffc200d2642fe0f","d83dde46d83cdffd200d2642fe0f","d83dde46d83cdffe200d2642fe0f","d83dde46d83cdfff200d2642fe0f"],["d83dde46200d2640fe0f","d83dde46d83cdffb200d2640fe0f","d83dde46d83cdffc200d2640fe0f","d83dde46d83cdffd200d2640fe0f","d83dde46d83cdffe200d2640fe0f","d83dde46d83cdfff200d2640fe0f"],["d83ddc81","d83ddc81d83cdffb","d83ddc81d83cdffc","d83ddc81d83cdffd","d83ddc81d83cdffe","d83ddc81d83cdfff"],["d83ddc81200d2642fe0f","d83ddc81d83cdffb200d2642fe0f","d83ddc81d83cdffc200d2642fe0f","d83ddc81d83cdffd200d2642fe0f","d83ddc81d83cdffe200d2642fe0f","d83ddc81d83cdfff200d2642fe0f"],["d83ddc81200d2640fe0f","d83ddc81d83cdffb200d2640fe0f","d83ddc81d83cdffc200d2640fe0f","d83ddc81d83cdffd200d2640fe0f","d83ddc81d83cdffe200d2640fe0f","d83ddc81d83cdfff200d2640fe0f"],["d83dde4b","d83dde4bd83cdffb","d83dde4bd83cdffc","d83dde4bd83cdffd","d83dde4bd83cdffe","d83dde4bd83cdfff"],["d83dde4b200d2642fe0f","d83dde4bd83cdffb200d2642fe0f","d83dde4bd83cdffc200d2642fe0f","d83dde4bd83cdffd200d2642fe0f","d83dde4bd83cdffe200d2642fe0f","d83dde4bd83cdfff200d2642fe0f"],["d83dde4b200d2640fe0f","d83dde4bd83cdffb200d2640fe0f","d83dde4bd83cdffc200d2640fe0f","d83dde4bd83cdffd200d2640fe0f","d83dde4bd83cdffe200d2640fe0f","d83dde4bd83cdfff200d2640fe0f"],["d83eddcf","d83eddcfd83cdffb","d83eddcfd83cdffc","d83eddcfd83cdffd","d83eddcfd83cdffe","d83eddcfd83cdfff"]],"People_3":[["d83eddcf200d2642fe0f","d83eddcfd83cdffb200d2642fe0f","d83eddcfd83cdffc200d2642fe0f","d83eddcfd83cdffd200d2642fe0f","d83eddcfd83cdffe200d2642fe0f","d83eddcfd83cdfff200d2642fe0f"],["d83eddcf200d2640fe0f","d83eddcfd83cdffb200d2640fe0f","d83eddcfd83cdffc200d2640fe0f","d83eddcfd83cdffd200d2640fe0f","d83eddcfd83cdffe200d2640fe0f","d83eddcfd83cdfff200d2640fe0f"],["d83dde47","d83dde47d83cdffb","d83dde47d83cdffc","d83dde47d83cdffd","d83dde47d83cdffe","d83dde47d83cdfff"],["d83dde47200d2642fe0f","d83dde47d83cdffb200d2642fe0f","d83dde47d83cdffc200d2642fe0f","d83dde47d83cdffd200d2642fe0f","d83dde47d83cdffe200d2642fe0f","d83dde47d83cdfff200d2642fe0f"],["d83dde47200d2640fe0f","d83dde47d83cdffb200d2640fe0f","d83dde47d83cdffc200d2640fe0f","d83dde47d83cdffd200d2640fe0f","d83dde47d83cdffe200d2640fe0f","d83dde47d83cdfff200d2640fe0f"],["d83edd26","d83edd26d83cdffb","d83edd26d83cdffc","d83edd26d83cdffd","d83edd26d83cdffe","d83edd26d83cdfff"],["d83edd26200d2642fe0f","d83edd26d83cdffb200d2642fe0f","d83edd26d83cdffc200d2642fe0f","d83edd26d83cdffd200d2642fe0f","d83edd26d83cdffe200d2642fe0f","d83edd26d83cdfff200d2642fe0f"],["d83edd26200d2640fe0f","d83edd26d83cdffb200d2640fe0f","d83edd26d83cdffc200d2640fe0f","d83edd26d83cdffd200d2640fe0f","d83edd26d83cdffe200d2640fe0f","d83edd26d83cdfff200d2640fe0f"],["d83edd37","d83edd37d83cdffb","d83edd37d83cdffc","d83edd37d83cdffd","d83edd37d83cdffe","d83edd37d83cdfff"],["d83edd37200d2642fe0f","d83edd37d83cdffb200d2642fe0f","d83edd37d83cdffc200d2642fe0f","d83edd37d83cdffd200d2642fe0f","d83edd37d83cdffe200d2642fe0f","d83edd37d83cdfff200d2642fe0f"],["d83edd37200d2640fe0f","d83edd37d83cdffb200d2640fe0f","d83edd37d83cdffc200d2640fe0f","d83edd37d83cdffd200d2640fe0f","d83edd37d83cdffe200d2640fe0f","d83edd37d83cdfff200d2640fe0f"],["d83eddd1200d2695fe0f","d83eddd1d83cdffb200d2695fe0f","d83eddd1d83cdffc200d2695fe0f","d83eddd1d83cdffd200d2695fe0f","d83eddd1d83cdffe200d2695fe0f","d83eddd1d83cdfff200d2695fe0f"],["d83ddc68200d2695fe0f","d83ddc68d83cdffb200d2695fe0f","d83ddc68d83cdffc200d2695fe0f","d83ddc68d83cdffd200d2695fe0f","d83ddc68d83cdffe200d2695fe0f","d83ddc68d83cdfff200d2695fe0f"],["d83ddc69200d2695fe0f","d83ddc69d83cdffb200d2695fe0f","d83ddc69d83cdffc200d2695fe0f","d83ddc69d83cdffd200d2695fe0f","d83ddc69d83cdffe200d2695fe0f","d83ddc69d83cdfff200d2695fe0f"],["d83eddd1200dd83cdf93","d83eddd1d83cdffb200dd83cdf93","d83eddd1d83cdffc200dd83cdf93","d83eddd1d83cdffd200dd83cdf93","d83eddd1d83cdffe200dd83cdf93","d83eddd1d83cdfff200dd83cdf93"],["d83ddc68200dd83cdf93","d83ddc68d83cdffb200dd83cdf93","d83ddc68d83cdffc200dd83cdf93","d83ddc68d83cdffd200dd83cdf93","d83ddc68d83cdffe200dd83cdf93","d83ddc68d83cdfff200dd83cdf93"],["d83ddc69200dd83cdf93","d83ddc69d83cdffb200dd83cdf93","d83ddc69d83cdffc200dd83cdf93","d83ddc69d83cdffd200dd83cdf93","d83ddc69d83cdffe200dd83cdf93","d83ddc69d83cdfff200dd83cdf93"],["d83eddd1200dd83cdfeb","d83eddd1d83cdffb200dd83cdfeb","d83eddd1d83cdffc200dd83cdfeb","d83eddd1d83cdffd200dd83cdfeb","d83eddd1d83cdffe200dd83cdfeb","d83eddd1d83cdfff200dd83cdfeb"],["d83ddc68200dd83cdfeb","d83ddc68d83cdffb200dd83cdfeb","d83ddc68d83cdffc200dd83cdfeb","d83ddc68d83cdffd200dd83cdfeb","d83ddc68d83cdffe200dd83cdfeb","d83ddc68d83cdfff200dd83cdfeb"],["d83ddc69200dd83cdfeb","d83ddc69d83cdffb200dd83cdfeb","d83ddc69d83cdffc200dd83cdfeb","d83ddc69d83cdffd200dd83cdfeb","d83ddc69d83cdffe200dd83cdfeb","d83ddc69d83cdfff200dd83cdfeb"],["d83eddd1200d2696fe0f","d83eddd1d83cdffb200d2696fe0f","d83eddd1d83cdffc200d2696fe0f","d83eddd1d83cdffd200d2696fe0f","d83eddd1d83cdffe200d2696fe0f","d83eddd1d83cdfff200d2696fe0f"],["d83ddc68200d2696fe0f","d83ddc68d83cdffb200d2696fe0f","d83ddc68d83cdffc200d2696fe0f","d83ddc68d83cdffd200d2696fe0f","d83ddc68d83cdffe200d2696fe0f","d83ddc68d83cdfff200d2696fe0f"],["d83ddc69200d2696fe0f","d83ddc69d83cdffb200d2696fe0f","d83ddc69d83cdffc200d2696fe0f","d83ddc69d83cdffd200d2696fe0f","d83ddc69d83cdffe200d2696fe0f","d83ddc69d83cdfff200d2696fe0f"],["d83eddd1200dd83cdf3e","d83eddd1d83cdffb200dd83cdf3e","d83eddd1d83cdffc200dd83cdf3e","d83eddd1d83cdffd200dd83cdf3e","d83eddd1d83cdffe200dd83cdf3e","d83eddd1d83cdfff200dd83cdf3e"],["d83ddc68200dd83cdf3e","d83ddc68d83cdffb200dd83cdf3e","d83ddc68d83cdffc200dd83cdf3e","d83ddc68d83cdffd200dd83cdf3e","d83ddc68d83cdffe200dd83cdf3e","d83ddc68d83cdfff200dd83cdf3e"],["d83ddc69200dd83cdf3e","d83ddc69d83cdffb200dd83cdf3e","d83ddc69d83cdffc200dd83cdf3e","d83ddc69d83cdffd200dd83cdf3e","d83ddc69d83cdffe200dd83cdf3e","d83ddc69d83cdfff200dd83cdf3e"],["d83eddd1200dd83cdf73","d83eddd1d83cdffb200dd83cdf73","d83eddd1d83cdffc200dd83cdf73","d83eddd1d83cdffd200dd83cdf73","d83eddd1d83cdffe200dd83cdf73","d83eddd1d83cdfff200dd83cdf73"],["d83ddc68200dd83cdf73","d83ddc68d83cdffb200dd83cdf73","d83ddc68d83cdffc200dd83cdf73","d83ddc68d83cdffd200dd83cdf73","d83ddc68d83cdffe200dd83cdf73","d83ddc68d83cdfff200dd83cdf73"],["d83ddc69200dd83cdf73","d83ddc69d83cdffb200dd83cdf73","d83ddc69d83cdffc200dd83cdf73","d83ddc69d83cdffd200dd83cdf73","d83ddc69d83cdffe200dd83cdf73","d83ddc69d83cdfff200dd83cdf73"],["d83eddd1200dd83ddd27","d83eddd1d83cdffb200dd83ddd27","d83eddd1d83cdffc200dd83ddd27","d83eddd1d83cdffd200dd83ddd27","d83eddd1d83cdffe200dd83ddd27","d83eddd1d83cdfff200dd83ddd27"],["d83ddc68200dd83ddd27","d83ddc68d83cdffb200dd83ddd27","d83ddc68d83cdffc200dd83ddd27","d83ddc68d83cdffd200dd83ddd27","d83ddc68d83cdffe200dd83ddd27","d83ddc68d83cdfff200dd83ddd27"],["d83ddc69200dd83ddd27","d83ddc69d83cdffb200dd83ddd27","d83ddc69d83cdffc200dd83ddd27","d83ddc69d83cdffd200dd83ddd27","d83ddc69d83cdffe200dd83ddd27","d83ddc69d83cdfff200dd83ddd27"],["d83eddd1200dd83cdfed","d83eddd1d83cdffb200dd83cdfed","d83eddd1d83cdffc200dd83cdfed","d83eddd1d83cdffd200dd83cdfed","d83eddd1d83cdffe200dd83cdfed","d83eddd1d83cdfff200dd83cdfed"],["d83ddc68200dd83cdfed","d83ddc68d83cdffb200dd83cdfed","d83ddc68d83cdffc200dd83cdfed","d83ddc68d83cdffd200dd83cdfed","d83ddc68d83cdffe200dd83cdfed","d83ddc68d83cdfff200dd83cdfed"],["d83ddc69200dd83cdfed","d83ddc69d83cdffb200dd83cdfed","d83ddc69d83cdffc200dd83cdfed","d83ddc69d83cdffd200dd83cdfed","d83ddc69d83cdffe200dd83cdfed","d83ddc69d83cdfff200dd83cdfed"],["d83eddd1200dd83ddcbc","d83eddd1d83cdffb200dd83ddcbc","d83eddd1d83cdffc200dd83ddcbc","d83eddd1d83cdffd200dd83ddcbc","d83eddd1d83cdffe200dd83ddcbc","d83eddd1d83cdfff200dd83ddcbc"],["d83ddc68200dd83ddcbc","d83ddc68d83cdffb200dd83ddcbc","d83ddc68d83cdffc200dd83ddcbc","d83ddc68d83cdffd200dd83ddcbc","d83ddc68d83cdffe200dd83ddcbc","d83ddc68d83cdfff200dd83ddcbc"],["d83ddc69200dd83ddcbc","d83ddc69d83cdffb200dd83ddcbc","d83ddc69d83cdffc200dd83ddcbc","d83ddc69d83cdffd200dd83ddcbc","d83ddc69d83cdffe200dd83ddcbc","d83ddc69d83cdfff200dd83ddcbc"],["d83eddd1200dd83ddd2c","d83eddd1d83cdffb200dd83ddd2c","d83eddd1d83cdffc200dd83ddd2c","d83eddd1d83cdffd200dd83ddd2c","d83eddd1d83cdffe200dd83ddd2c","d83eddd1d83cdfff200dd83ddd2c"],["d83ddc68200dd83ddd2c","d83ddc68d83cdffb200dd83ddd2c","d83ddc68d83cdffc200dd83ddd2c","d83ddc68d83cdffd200dd83ddd2c","d83ddc68d83cdffe200dd83ddd2c","d83ddc68d83cdfff200dd83ddd2c"],["d83ddc69200dd83ddd2c","d83ddc69d83cdffb200dd83ddd2c","d83ddc69d83cdffc200dd83ddd2c","d83ddc69d83cdffd200dd83ddd2c","d83ddc69d83cdffe200dd83ddd2c","d83ddc69d83cdfff200dd83ddd2c"],["d83eddd1200dd83ddcbb","d83eddd1d83cdffb200dd83ddcbb","d83eddd1d83cdffc200dd83ddcbb","d83eddd1d83cdffd200dd83ddcbb","d83eddd1d83cdffe200dd83ddcbb","d83eddd1d83cdfff200dd83ddcbb"]],"People_4":[["d83ddc68200dd83ddcbb","d83ddc68d83cdffb200dd83ddcbb","d83ddc68d83cdffc200dd83ddcbb","d83ddc68d83cdffd200dd83ddcbb","d83ddc68d83cdffe200dd83ddcbb","d83ddc68d83cdfff200dd83ddcbb"],["d83ddc69200dd83ddcbb","d83ddc69d83cdffb200dd83ddcbb","d83ddc69d83cdffc200dd83ddcbb","d83ddc69d83cdffd200dd83ddcbb","d83ddc69d83cdffe200dd83ddcbb","d83ddc69d83cdfff200dd83ddcbb"],["d83eddd1200dd83cdfa4","d83eddd1d83cdffb200dd83cdfa4","d83eddd1d83cdffc200dd83cdfa4","d83eddd1d83cdffd200dd83cdfa4","d83eddd1d83cdffe200dd83cdfa4","d83eddd1d83cdfff200dd83cdfa4"],["d83ddc68200dd83cdfa4","d83ddc68d83cdffb200dd83cdfa4","d83ddc68d83cdffc200dd83cdfa4","d83ddc68d83cdffd200dd83cdfa4","d83ddc68d83cdffe200dd83cdfa4","d83ddc68d83cdfff200dd83cdfa4"],["d83ddc69200dd83cdfa4","d83ddc69d83cdffb200dd83cdfa4","d83ddc69d83cdffc200dd83cdfa4","d83ddc69d83cdffd200dd83cdfa4","d83ddc69d83cdffe200dd83cdfa4","d83ddc69d83cdfff200dd83cdfa4"],["d83eddd1200dd83cdfa8","d83eddd1d83cdffb200dd83cdfa8","d83eddd1d83cdffc200dd83cdfa8","d83eddd1d83cdffd200dd83cdfa8","d83eddd1d83cdffe200dd83cdfa8","d83eddd1d83cdfff200dd83cdfa8"],["d83ddc68200dd83cdfa8","d83ddc68d83cdffb200dd83cdfa8","d83ddc68d83cdffc200dd83cdfa8","d83ddc68d83cdffd200dd83cdfa8","d83ddc68d83cdffe200dd83cdfa8","d83ddc68d83cdfff200dd83cdfa8"],["d83ddc69200dd83cdfa8","d83ddc69d83cdffb200dd83cdfa8","d83ddc69d83cdffc200dd83cdfa8","d83ddc69d83cdffd200dd83cdfa8","d83ddc69d83cdffe200dd83cdfa8","d83ddc69d83cdfff200dd83cdfa8"],["d83eddd1200d2708fe0f","d83eddd1d83cdffb200d2708fe0f","d83eddd1d83cdffc200d2708fe0f","d83eddd1d83cdffd200d2708fe0f","d83eddd1d83cdffe200d2708fe0f","d83eddd1d83cdfff200d2708fe0f"],["d83ddc68200d2708fe0f","d83ddc68d83cdffb200d2708fe0f","d83ddc68d83cdffc200d2708fe0f","d83ddc68d83cdffd200d2708fe0f","d83ddc68d83cdffe200d2708fe0f","d83ddc68d83cdfff200d2708fe0f"],["d83ddc69200d2708fe0f","d83ddc69d83cdffb200d2708fe0f","d83ddc69d83cdffc200d2708fe0f","d83ddc69d83cdffd200d2708fe0f","d83ddc69d83cdffe200d2708fe0f","d83ddc69d83cdfff200d2708fe0f"],["d83eddd1200dd83dde80","d83eddd1d83cdffb200dd83dde80","d83eddd1d83cdffc200dd83dde80","d83eddd1d83cdffd200dd83dde80","d83eddd1d83cdffe200dd83dde80","d83eddd1d83cdfff200dd83dde80"],["d83ddc68200dd83dde80","d83ddc68d83cdffb200dd83dde80","d83ddc68d83cdffc200dd83dde80","d83ddc68d83cdffd200dd83dde80","d83ddc68d83cdffe200dd83dde80","d83ddc68d83cdfff200dd83dde80"],["d83ddc69200dd83dde80","d83ddc69d83cdffb200dd83dde80","d83ddc69d83cdffc200dd83dde80","d83ddc69d83cdffd200dd83dde80","d83ddc69d83cdffe200dd83dde80","d83ddc69d83cdfff200dd83dde80"],["d83eddd1200dd83dde92","d83eddd1d83cdffb200dd83dde92","d83eddd1d83cdffc200dd83dde92","d83eddd1d83cdffd200dd83dde92","d83eddd1d83cdffe200dd83dde92","d83eddd1d83cdfff200dd83dde92"],["d83ddc68200dd83dde92","d83ddc68d83cdffb200dd83dde92","d83ddc68d83cdffc200dd83dde92","d83ddc68d83cdffd200dd83dde92","d83ddc68d83cdffe200dd83dde92","d83ddc68d83cdfff200dd83dde92"],["d83ddc69200dd83dde92","d83ddc69d83cdffb200dd83dde92","d83ddc69d83cdffc200dd83dde92","d83ddc69d83cdffd200dd83dde92","d83ddc69d83cdffe200dd83dde92","d83ddc69d83cdfff200dd83dde92"],["d83ddc6e","d83ddc6ed83cdffb","d83ddc6ed83cdffc","d83ddc6ed83cdffd","d83ddc6ed83cdffe","d83ddc6ed83cdfff"],["d83ddc6e200d2642fe0f","d83ddc6ed83cdffb200d2642fe0f","d83ddc6ed83cdffc200d2642fe0f","d83ddc6ed83cdffd200d2642fe0f","d83ddc6ed83cdffe200d2642fe0f","d83ddc6ed83cdfff200d2642fe0f"],["d83ddc6e200d2640fe0f","d83ddc6ed83cdffb200d2640fe0f","d83ddc6ed83cdffc200d2640fe0f","d83ddc6ed83cdffd200d2640fe0f","d83ddc6ed83cdffe200d2640fe0f","d83ddc6ed83cdfff200d2640fe0f"],["d83ddd75fe0f","d83ddd75d83cdffb","d83ddd75d83cdffc","d83ddd75d83cdffd","d83ddd75d83cdffe","d83ddd75d83cdfff"],["d83ddd75fe0f200d2642fe0f","d83ddd75d83cdffb200d2642fe0f","d83ddd75d83cdffc200d2642fe0f","d83ddd75d83cdffd200d2642fe0f","d83ddd75d83cdffe200d2642fe0f","d83ddd75d83cdfff200d2642fe0f"],["d83ddd75fe0f200d2640fe0f","d83ddd75d83cdffb200d2640fe0f","d83ddd75d83cdffc200d2640fe0f","d83ddd75d83cdffd200d2640fe0f","d83ddd75d83cdffe200d2640fe0f","d83ddd75d83cdfff200d2640fe0f"],["d83ddc82","d83ddc82d83cdffb","d83ddc82d83cdffc","d83ddc82d83cdffd","d83ddc82d83cdffe","d83ddc82d83cdfff"],["d83ddc82200d2642fe0f","d83ddc82d83cdffb200d2642fe0f","d83ddc82d83cdffc200d2642fe0f","d83ddc82d83cdffd200d2642fe0f","d83ddc82d83cdffe200d2642fe0f","d83ddc82d83cdfff200d2642fe0f"],["d83ddc82200d2640fe0f","d83ddc82d83cdffb200d2640fe0f","d83ddc82d83cdffc200d2640fe0f","d83ddc82d83cdffd200d2640fe0f","d83ddc82d83cdffe200d2640fe0f","d83ddc82d83cdfff200d2640fe0f"],["d83edd77","d83edd77d83cdffb","d83edd77d83cdffc","d83edd77d83cdffd","d83edd77d83cdffe","d83edd77d83cdfff"],["d83ddc77","d83ddc77d83cdffb","d83ddc77d83cdffc","d83ddc77d83cdffd","d83ddc77d83cdffe","d83ddc77d83cdfff"],["d83ddc77200d2642fe0f","d83ddc77d83cdffb200d2642fe0f","d83ddc77d83cdffc200d2642fe0f","d83ddc77d83cdffd200d2642fe0f","d83ddc77d83cdffe200d2642fe0f","d83ddc77d83cdfff200d2642fe0f"],["d83ddc77200d2640fe0f","d83ddc77d83cdffb200d2640fe0f","d83ddc77d83cdffc200d2640fe0f","d83ddc77d83cdffd200d2640fe0f","d83ddc77d83cdffe200d2640fe0f","d83ddc77d83cdfff200d2640fe0f"],["d83edec5","d83edec5d83cdffb","d83edec5d83cdffc","d83edec5d83cdffd","d83edec5d83cdffe","d83edec5d83cdfff"],["d83edd34","d83edd34d83cdffb","d83edd34d83cdffc","d83edd34d83cdffd","d83edd34d83cdffe","d83edd34d83cdfff"],["d83ddc78","d83ddc78d83cdffb","d83ddc78d83cdffc","d83ddc78d83cdffd","d83ddc78d83cdffe","d83ddc78d83cdfff"],["d83ddc73","d83ddc73d83cdffb","d83ddc73d83cdffc","d83ddc73d83cdffd","d83ddc73d83cdffe","d83ddc73d83cdfff"],["d83ddc73200d2642fe0f","d83ddc73d83cdffb200d2642fe0f","d83ddc73d83cdffc200d2642fe0f","d83ddc73d83cdffd200d2642fe0f","d83ddc73d83cdffe200d2642fe0f","d83ddc73d83cdfff200d2642fe0f"],["d83ddc73200d2640fe0f","d83ddc73d83cdffb200d2640fe0f","d83ddc73d83cdffc200d2640fe0f","d83ddc73d83cdffd200d2640fe0f","d83ddc73d83cdffe200d2640fe0f","d83ddc73d83cdfff200d2640fe0f"],["d83ddc72","d83ddc72d83cdffb","d83ddc72d83cdffc","d83ddc72d83cdffd","d83ddc72d83cdffe","d83ddc72d83cdfff"],["d83eddd5","d83eddd5d83cdffb","d83eddd5d83cdffc","d83eddd5d83cdffd","d83eddd5d83cdffe","d83eddd5d83cdfff"],["d83edd35","d83edd35d83cdffb","d83edd35d83cdffc","d83edd35d83cdffd","d83edd35d83cdffe","d83edd35d83cdfff"],["d83edd35200d2642fe0f","d83edd35d83cdffb200d2642fe0f","d83edd35d83cdffc200d2642fe0f","d83edd35d83cdffd200d2642fe0f","d83edd35d83cdffe200d2642fe0f","d83edd35d83cdfff200d2642fe0f"],["d83edd35200d2640fe0f","d83edd35d83cdffb200d2640fe0f","d83edd35d83cdffc200d2640fe0f","d83edd35d83cdffd200d2640fe0f","d83edd35d83cdffe200d2640fe0f","d83edd35d83cdfff200d2640fe0f"],["d83ddc70","d83ddc70d83cdffb","d83ddc70d83cdffc","d83ddc70d83cdffd","d83ddc70d83cdffe","d83ddc70d83cdfff"]],"People_5":[["d83ddc70200d2642fe0f","d83ddc70d83cdffb200d2642fe0f","d83ddc70d83cdffc200d2642fe0f","d83ddc70d83cdffd200d2642fe0f","d83ddc70d83cdffe200d2642fe0f","d83ddc70d83cdfff200d2642fe0f"],["d83ddc70200d2640fe0f","d83ddc70d83cdffb200d2640fe0f","d83ddc70d83cdffc200d2640fe0f","d83ddc70d83cdffd200d2640fe0f","d83ddc70d83cdffe200d2640fe0f","d83ddc70d83cdfff200d2640fe0f"],["d83edd30","d83edd30d83cdffb","d83edd30d83cdffc","d83edd30d83cdffd","d83edd30d83cdffe","d83edd30d83cdfff"],["d83edec3","d83edec3d83cdffb","d83edec3d83cdffc","d83edec3d83cdffd","d83edec3d83cdffe","d83edec3d83cdfff"],["d83edec4","d83edec4d83cdffb","d83edec4d83cdffc","d83edec4d83cdffd","d83edec4d83cdffe","d83edec4d83cdfff"],["d83edd31","d83edd31d83cdffb","d83edd31d83cdffc","d83edd31d83cdffd","d83edd31d83cdffe","d83edd31d83cdfff"],["d83ddc69200dd83cdf7c","d83ddc69d83cdffb200dd83cdf7c","d83ddc69d83cdffc200dd83cdf7c","d83ddc69d83cdffd200dd83cdf7c","d83ddc69d83cdffe200dd83cdf7c","d83ddc69d83cdfff200dd83cdf7c"],["d83ddc68200dd83cdf7c","d83ddc68d83cdffb200dd83cdf7c","d83ddc68d83cdffc200dd83cdf7c","d83ddc68d83cdffd200dd83cdf7c","d83ddc68d83cdffe200dd83cdf7c","d83ddc68d83cdfff200dd83cdf7c"],["d83eddd1200dd83cdf7c","d83eddd1d83cdffb200dd83cdf7c","d83eddd1d83cdffc200dd83cdf7c","d83eddd1d83cdffd200dd83cdf7c","d83eddd1d83cdffe200dd83cdf7c","d83eddd1d83cdfff200dd83cdf7c"],["d83ddc7c","d83ddc7cd83cdffb","d83ddc7cd83cdffc","d83ddc7cd83cdffd","d83ddc7cd83cdffe","d83ddc7cd83cdfff"],["d83cdf85","d83cdf85d83cdffb","d83cdf85d83cdffc","d83cdf85d83cdffd","d83cdf85d83cdffe","d83cdf85d83cdfff"],["d83edd36","d83edd36d83cdffb","d83edd36d83cdffc","d83edd36d83cdffd","d83edd36d83cdffe","d83edd36d83cdfff"],["d83eddd1200dd83cdf84","d83eddd1d83cdffb200dd83cdf84","d83eddd1d83cdffc200dd83cdf84","d83eddd1d83cdffd200dd83cdf84","d83eddd1d83cdffe200dd83cdf84","d83eddd1d83cdfff200dd83cdf84"],["d83eddb8","d83eddb8d83cdffb","d83eddb8d83cdffc","d83eddb8d83cdffd","d83eddb8d83cdffe","d83eddb8d83cdfff"],["d83eddb8200d2642fe0f","d83eddb8d83cdffb200d2642fe0f","d83eddb8d83cdffc200d2642fe0f","d83eddb8d83cdffd200d2642fe0f","d83eddb8d83cdffe200d2642fe0f","d83eddb8d83cdfff200d2642fe0f"],["d83eddb8200d2640fe0f","d83eddb8d83cdffb200d2640fe0f","d83eddb8d83cdffc200d2640fe0f","d83eddb8d83cdffd200d2640fe0f","d83eddb8d83cdffe200d2640fe0f","d83eddb8d83cdfff200d2640fe0f"],["d83eddb9","d83eddb9d83cdffb","d83eddb9d83cdffc","d83eddb9d83cdffd","d83eddb9d83cdffe","d83eddb9d83cdfff"],["d83eddb9200d2642fe0f","d83eddb9d83cdffb200d2642fe0f","d83eddb9d83cdffc200d2642fe0f","d83eddb9d83cdffd200d2642fe0f","d83eddb9d83cdffe200d2642fe0f","d83eddb9d83cdfff200d2642fe0f"],["d83eddb9200d2640fe0f","d83eddb9d83cdffb200d2640fe0f","d83eddb9d83cdffc200d2640fe0f","d83eddb9d83cdffd200d2640fe0f","d83eddb9d83cdffe200d2640fe0f","d83eddb9d83cdfff200d2640fe0f"],["d83eddd9","d83eddd9d83cdffb","d83eddd9d83cdffc","d83eddd9d83cdffd","d83eddd9d83cdffe","d83eddd9d83cdfff"],["d83eddd9200d2642fe0f","d83eddd9d83cdffb200d2642fe0f","d83eddd9d83cdffc200d2642fe0f","d83eddd9d83cdffd200d2642fe0f","d83eddd9d83cdffe200d2642fe0f","d83eddd9d83cdfff200d2642fe0f"],["d83eddd9200d2640fe0f","d83eddd9d83cdffb200d2640fe0f","d83eddd9d83cdffc200d2640fe0f","d83eddd9d83cdffd200d2640fe0f","d83eddd9d83cdffe200d2640fe0f","d83eddd9d83cdfff200d2640fe0f"],["d83eddda","d83edddad83cdffb","d83edddad83cdffc","d83edddad83cdffd","d83edddad83cdffe","d83edddad83cdfff"],["d83eddda200d2642fe0f","d83edddad83cdffb200d2642fe0f","d83edddad83cdffc200d2642fe0f","d83edddad83cdffd200d2642fe0f","d83edddad83cdffe200d2642fe0f","d83edddad83cdfff200d2642fe0f"],["d83eddda200d2640fe0f","d83edddad83cdffb200d2640fe0f","d83edddad83cdffc200d2640fe0f","d83edddad83cdffd200d2640fe0f","d83edddad83cdffe200d2640fe0f","d83edddad83cdfff200d2640fe0f"],["d83edddb","d83edddbd83cdffb","d83edddbd83cdffc","d83edddbd83cdffd","d83edddbd83cdffe","d83edddbd83cdfff"],["d83edddb200d2642fe0f","d83edddbd83cdffb200d2642fe0f","d83edddbd83cdffc200d2642fe0f","d83edddbd83cdffd200d2642fe0f","d83edddbd83cdffe200d2642fe0f","d83edddbd83cdfff200d2642fe0f"],["d83edddb200d2640fe0f","d83edddbd83cdffb200d2640fe0f","d83edddbd83cdffc200d2640fe0f","d83edddbd83cdffd200d2640fe0f","d83edddbd83cdffe200d2640fe0f","d83edddbd83cdfff200d2640fe0f"],["d83edddc","d83edddcd83cdffb","d83edddcd83cdffc","d83edddcd83cdffd","d83edddcd83cdffe","d83edddcd83cdfff"],["d83edddc200d2642fe0f","d83edddcd83cdffb200d2642fe0f","d83edddcd83cdffc200d2642fe0f","d83edddcd83cdffd200d2642fe0f","d83edddcd83cdffe200d2642fe0f","d83edddcd83cdfff200d2642fe0f"],["d83edddc200d2640fe0f","d83edddcd83cdffb200d2640fe0f","d83edddcd83cdffc200d2640fe0f","d83edddcd83cdffd200d2640fe0f","d83edddcd83cdffe200d2640fe0f","d83edddcd83cdfff200d2640fe0f"],["d83edddd","d83eddddd83cdffb","d83eddddd83cdffc","d83eddddd83cdffd","d83eddddd83cdffe","d83eddddd83cdfff"],["d83edddd200d2642fe0f","d83eddddd83cdffb200d2642fe0f","d83eddddd83cdffc200d2642fe0f","d83eddddd83cdffd200d2642fe0f","d83eddddd83cdffe200d2642fe0f","d83eddddd83cdfff200d2642fe0f"],["d83edddd200d2640fe0f","d83eddddd83cdffb200d2640fe0f","d83eddddd83cdffc200d2640fe0f","d83eddddd83cdffd200d2640fe0f","d83eddddd83cdffe200d2640fe0f","d83eddddd83cdfff200d2640fe0f"],["d83eddde"],["d83eddde200d2642fe0f"],["d83eddde200d2640fe0f"],["d83edddf"],["d83edddf200d2642fe0f"],["d83edddf200d2640fe0f"],["d83eddcc"],["d83ddc86","d83ddc86d83cdffb","d83ddc86d83cdffc","d83ddc86d83cdffd","d83ddc86d83cdffe","d83ddc86d83cdfff"],["d83ddc86200d2642fe0f","d83ddc86d83cdffb200d2642fe0f","d83ddc86d83cdffc200d2642fe0f","d83ddc86d83cdffd200d2642fe0f","d83ddc86d83cdffe200d2642fe0f","d83ddc86d83cdfff200d2642fe0f"],["d83ddc86200d2640fe0f","d83ddc86d83cdffb200d2640fe0f","d83ddc86d83cdffc200d2640fe0f","d83ddc86d83cdffd200d2640fe0f","d83ddc86d83cdffe200d2640fe0f","d83ddc86d83cdfff200d2640fe0f"],["d83ddc87","d83ddc87d83cdffb","d83ddc87d83cdffc","d83ddc87d83cdffd","d83ddc87d83cdffe","d83ddc87d83cdfff"],["d83ddc87200d2642fe0f","d83ddc87d83cdffb200d2642fe0f","d83ddc87d83cdffc200d2642fe0f","d83ddc87d83cdffd200d2642fe0f","d83ddc87d83cdffe200d2642fe0f","d83ddc87d83cdfff200d2642fe0f"],["d83ddc87200d2640fe0f","d83ddc87d83cdffb200d2640fe0f","d83ddc87d83cdffc200d2640fe0f","d83ddc87d83cdffd200d2640fe0f","d83ddc87d83cdffe200d2640fe0f","d83ddc87d83cdfff200d2640fe0f"],["d83ddeb6","d83ddeb6d83cdffb","d83ddeb6d83cdffc","d83ddeb6d83cdffd","d83ddeb6d83cdffe","d83ddeb6d83cdfff"]],"People_6":[["d83ddeb6200d2642fe0f","d83ddeb6d83cdffb200d2642fe0f","d83ddeb6d83cdffc200d2642fe0f","d83ddeb6d83cdffd200d2642fe0f","d83ddeb6d83cdffe200d2642fe0f","d83ddeb6d83cdfff200d2642fe0f"],["d83ddeb6200d2640fe0f","d83ddeb6d83cdffb200d2640fe0f","d83ddeb6d83cdffc200d2640fe0f","d83ddeb6d83cdffd200d2640fe0f","d83ddeb6d83cdffe200d2640fe0f","d83ddeb6d83cdfff200d2640fe0f"],["d83eddcd","d83eddcdd83cdffb","d83eddcdd83cdffc","d83eddcdd83cdffd","d83eddcdd83cdffe","d83eddcdd83cdfff"],["d83eddcd200d2642fe0f","d83eddcdd83cdffb200d2642fe0f","d83eddcdd83cdffc200d2642fe0f","d83eddcdd83cdffd200d2642fe0f","d83eddcdd83cdffe200d2642fe0f","d83eddcdd83cdfff200d2642fe0f"],["d83eddcd200d2640fe0f","d83eddcdd83cdffb200d2640fe0f","d83eddcdd83cdffc200d2640fe0f","d83eddcdd83cdffd200d2640fe0f","d83eddcdd83cdffe200d2640fe0f","d83eddcdd83cdfff200d2640fe0f"],["d83eddce","d83eddced83cdffb","d83eddced83cdffc","d83eddced83cdffd","d83eddced83cdffe","d83eddced83cdfff"],["d83eddce200d2642fe0f","d83eddced83cdffb200d2642fe0f","d83eddced83cdffc200d2642fe0f","d83eddced83cdffd200d2642fe0f","d83eddced83cdffe200d2642fe0f","d83eddced83cdfff200d2642fe0f"],["d83eddce200d2640fe0f","d83eddced83cdffb200d2640fe0f","d83eddced83cdffc200d2640fe0f","d83eddced83cdffd200d2640fe0f","d83eddced83cdffe200d2640fe0f","d83eddced83cdfff200d2640fe0f"],["d83eddd1200dd83eddaf","d83eddd1d83cdffb200dd83eddaf","d83eddd1d83cdffc200dd83eddaf","d83eddd1d83cdffd200dd83eddaf","d83eddd1d83cdffe200dd83eddaf","d83eddd1d83cdfff200dd83eddaf"],["d83ddc68200dd83eddaf","d83ddc68d83cdffb200dd83eddaf","d83ddc68d83cdffc200dd83eddaf","d83ddc68d83cdffd200dd83eddaf","d83ddc68d83cdffe200dd83eddaf","d83ddc68d83cdfff200dd83eddaf"],["d83ddc69200dd83eddaf","d83ddc69d83cdffb200dd83eddaf","d83ddc69d83cdffc200dd83eddaf","d83ddc69d83cdffd200dd83eddaf","d83ddc69d83cdffe200dd83eddaf","d83ddc69d83cdfff200dd83eddaf"],["d83eddd1200dd83eddbc","d83eddd1d83cdffb200dd83eddbc","d83eddd1d83cdffc200dd83eddbc","d83eddd1d83cdffd200dd83eddbc","d83eddd1d83cdffe200dd83eddbc","d83eddd1d83cdfff200dd83eddbc"],["d83ddc68200dd83eddbc","d83ddc68d83cdffb200dd83eddbc","d83ddc68d83cdffc200dd83eddbc","d83ddc68d83cdffd200dd83eddbc","d83ddc68d83cdffe200dd83eddbc","d83ddc68d83cdfff200dd83eddbc"],["d83ddc69200dd83eddbc","d83ddc69d83cdffb200dd83eddbc","d83ddc69d83cdffc200dd83eddbc","d83ddc69d83cdffd200dd83eddbc","d83ddc69d83cdffe200dd83eddbc","d83ddc69d83cdfff200dd83eddbc"],["d83eddd1200dd83eddbd","d83eddd1d83cdffb200dd83eddbd","d83eddd1d83cdffc200dd83eddbd","d83eddd1d83cdffd200dd83eddbd","d83eddd1d83cdffe200dd83eddbd","d83eddd1d83cdfff200dd83eddbd"],["d83ddc68200dd83eddbd","d83ddc68d83cdffb200dd83eddbd","d83ddc68d83cdffc200dd83eddbd","d83ddc68d83cdffd200dd83eddbd","d83ddc68d83cdffe200dd83eddbd","d83ddc68d83cdfff200dd83eddbd"],["d83ddc69200dd83eddbd","d83ddc69d83cdffb200dd83eddbd","d83ddc69d83cdffc200dd83eddbd","d83ddc69d83cdffd200dd83eddbd","d83ddc69d83cdffe200dd83eddbd","d83ddc69d83cdfff200dd83eddbd"],["d83cdfc3","d83cdfc3d83cdffb","d83cdfc3d83cdffc","d83cdfc3d83cdffd","d83cdfc3d83cdffe","d83cdfc3d83cdfff"],["d83cdfc3200d2642fe0f","d83cdfc3d83cdffb200d2642fe0f","d83cdfc3d83cdffc200d2642fe0f","d83cdfc3d83cdffd200d2642fe0f","d83cdfc3d83cdffe200d2642fe0f","d83cdfc3d83cdfff200d2642fe0f"],["d83cdfc3200d2640fe0f","d83cdfc3d83cdffb200d2640fe0f","d83cdfc3d83cdffc200d2640fe0f","d83cdfc3d83cdffd200d2640fe0f","d83cdfc3d83cdffe200d2640fe0f","d83cdfc3d83cdfff200d2640fe0f"],["d83ddc83","d83ddc83d83cdffb","d83ddc83d83cdffc","d83ddc83d83cdffd","d83ddc83d83cdffe","d83ddc83d83cdfff"],["d83ddd7a","d83ddd7ad83cdffb","d83ddd7ad83cdffc","d83ddd7ad83cdffd","d83ddd7ad83cdffe","d83ddd7ad83cdfff"],["d83ddd74fe0f","d83ddd74d83cdffb","d83ddd74d83cdffc","d83ddd74d83cdffd","d83ddd74d83cdffe","d83ddd74d83cdfff"],["d83ddc6f"],["d83ddc6f200d2642fe0f"],["d83ddc6f200d2640fe0f"],["d83eddd6","d83eddd6d83cdffb","d83eddd6d83cdffc","d83eddd6d83cdffd","d83eddd6d83cdffe","d83eddd6d83cdfff"],["d83eddd6200d2642fe0f","d83eddd6d83cdffb200d2642fe0f","d83eddd6d83cdffc200d2642fe0f","d83eddd6d83cdffd200d2642fe0f","d83eddd6d83cdffe200d2642fe0f","d83eddd6d83cdfff200d2642fe0f"],["d83eddd6200d2640fe0f","d83eddd6d83cdffb200d2640fe0f","d83eddd6d83cdffc200d2640fe0f","d83eddd6d83cdffd200d2640fe0f","d83eddd6d83cdffe200d2640fe0f","d83eddd6d83cdfff200d2640fe0f"],["d83eddd7","d83eddd7d83cdffb","d83eddd7d83cdffc","d83eddd7d83cdffd","d83eddd7d83cdffe","d83eddd7d83cdfff"],["d83eddd7200d2642fe0f","d83eddd7d83cdffb200d2642fe0f","d83eddd7d83cdffc200d2642fe0f","d83eddd7d83cdffd200d2642fe0f","d83eddd7d83cdffe200d2642fe0f","d83eddd7d83cdfff200d2642fe0f"],["d83eddd7200d2640fe0f","d83eddd7d83cdffb200d2640fe0f","d83eddd7d83cdffc200d2640fe0f","d83eddd7d83cdffd200d2640fe0f","d83eddd7d83cdffe200d2640fe0f","d83eddd7d83cdfff200d2640fe0f"],["d83edd3a"],["d83cdfc7","d83cdfc7d83cdffb","d83cdfc7d83cdffc","d83cdfc7d83cdffd","d83cdfc7d83cdffe","d83cdfc7d83cdfff"],["26f7fe0f"],["d83cdfc2","d83cdfc2d83cdffb","d83cdfc2d83cdffc","d83cdfc2d83cdffd","d83cdfc2d83cdffe","d83cdfc2d83cdfff"],["d83cdfccfe0f","d83cdfccd83cdffb","d83cdfccd83cdffc","d83cdfccd83cdffd","d83cdfccd83cdffe","d83cdfccd83cdfff"],["d83cdfccfe0f200d2642fe0f","d83cdfccd83cdffb200d2642fe0f","d83cdfccd83cdffc200d2642fe0f","d83cdfccd83cdffd200d2642fe0f","d83cdfccd83cdffe200d2642fe0f","d83cdfccd83cdfff200d2642fe0f"],["d83cdfccfe0f200d2640fe0f","d83cdfccd83cdffb200d2640fe0f","d83cdfccd83cdffc200d2640fe0f","d83cdfccd83cdffd200d2640fe0f","d83cdfccd83cdffe200d2640fe0f","d83cdfccd83cdfff200d2640fe0f"],["d83cdfc4","d83cdfc4d83cdffb","d83cdfc4d83cdffc","d83cdfc4d83cdffd","d83cdfc4d83cdffe","d83cdfc4d83cdfff"],["d83cdfc4200d2642fe0f","d83cdfc4d83cdffb200d2642fe0f","d83cdfc4d83cdffc200d2642fe0f","d83cdfc4d83cdffd200d2642fe0f","d83cdfc4d83cdffe200d2642fe0f","d83cdfc4d83cdfff200d2642fe0f"],["d83cdfc4200d2640fe0f","d83cdfc4d83cdffb200d2640fe0f","d83cdfc4d83cdffc200d2640fe0f","d83cdfc4d83cdffd200d2640fe0f","d83cdfc4d83cdffe200d2640fe0f","d83cdfc4d83cdfff200d2640fe0f"],["d83ddea3","d83ddea3d83cdffb","d83ddea3d83cdffc","d83ddea3d83cdffd","d83ddea3d83cdffe","d83ddea3d83cdfff"],["d83ddea3200d2642fe0f","d83ddea3d83cdffb200d2642fe0f","d83ddea3d83cdffc200d2642fe0f","d83ddea3d83cdffd200d2642fe0f","d83ddea3d83cdffe200d2642fe0f","d83ddea3d83cdfff200d2642fe0f"],["d83ddea3200d2640fe0f","d83ddea3d83cdffb200d2640fe0f","d83ddea3d83cdffc200d2640fe0f","d83ddea3d83cdffd200d2640fe0f","d83ddea3d83cdffe200d2640fe0f","d83ddea3d83cdfff200d2640fe0f"],["d83cdfca","d83cdfcad83cdffb","d83cdfcad83cdffc","d83cdfcad83cdffd","d83cdfcad83cdffe","d83cdfcad83cdfff"]],"People_7":[["d83cdfca200d2642fe0f","d83cdfcad83cdffb200d2642fe0f","d83cdfcad83cdffc200d2642fe0f","d83cdfcad83cdffd200d2642fe0f","d83cdfcad83cdffe200d2642fe0f","d83cdfcad83cdfff200d2642fe0f"],["d83cdfca200d2640fe0f","d83cdfcad83cdffb200d2640fe0f","d83cdfcad83cdffc200d2640fe0f","d83cdfcad83cdffd200d2640fe0f","d83cdfcad83cdffe200d2640fe0f","d83cdfcad83cdfff200d2640fe0f"],["26f9fe0f","26f9d83cdffb","26f9d83cdffc","26f9d83cdffd","26f9d83cdffe","26f9d83cdfff"],["26f9fe0f200d2642fe0f","26f9d83cdffb200d2642fe0f","26f9d83cdffc200d2642fe0f","26f9d83cdffd200d2642fe0f","26f9d83cdffe200d2642fe0f","26f9d83cdfff200d2642fe0f"],["26f9fe0f200d2640fe0f","26f9d83cdffb200d2640fe0f","26f9d83cdffc200d2640fe0f","26f9d83cdffd200d2640fe0f","26f9d83cdffe200d2640fe0f","26f9d83cdfff200d2640fe0f"],["d83cdfcbfe0f","d83cdfcbd83cdffb","d83cdfcbd83cdffc","d83cdfcbd83cdffd","d83cdfcbd83cdffe","d83cdfcbd83cdfff"],["d83cdfcbfe0f200d2642fe0f","d83cdfcbd83cdffb200d2642fe0f","d83cdfcbd83cdffc200d2642fe0f","d83cdfcbd83cdffd200d2642fe0f","d83cdfcbd83cdffe200d2642fe0f","d83cdfcbd83cdfff200d2642fe0f"],["d83cdfcbfe0f200d2640fe0f","d83cdfcbd83cdffb200d2640fe0f","d83cdfcbd83cdffc200d2640fe0f","d83cdfcbd83cdffd200d2640fe0f","d83cdfcbd83cdffe200d2640fe0f","d83cdfcbd83cdfff200d2640fe0f"],["d83ddeb4","d83ddeb4d83cdffb","d83ddeb4d83cdffc","d83ddeb4d83cdffd","d83ddeb4d83cdffe","d83ddeb4d83cdfff"],["d83ddeb4200d2642fe0f","d83ddeb4d83cdffb200d2642fe0f","d83ddeb4d83cdffc200d2642fe0f","d83ddeb4d83cdffd200d2642fe0f","d83ddeb4d83cdffe200d2642fe0f","d83ddeb4d83cdfff200d2642fe0f"],["d83ddeb4200d2640fe0f","d83ddeb4d83cdffb200d2640fe0f","d83ddeb4d83cdffc200d2640fe0f","d83ddeb4d83cdffd200d2640fe0f","d83ddeb4d83cdffe200d2640fe0f","d83ddeb4d83cdfff200d2640fe0f"],["d83ddeb5","d83ddeb5d83cdffb","d83ddeb5d83cdffc","d83ddeb5d83cdffd","d83ddeb5d83cdffe","d83ddeb5d83cdfff"],["d83ddeb5200d2642fe0f","d83ddeb5d83cdffb200d2642fe0f","d83ddeb5d83cdffc200d2642fe0f","d83ddeb5d83cdffd200d2642fe0f","d83ddeb5d83cdffe200d2642fe0f","d83ddeb5d83cdfff200d2642fe0f"],["d83ddeb5200d2640fe0f","d83ddeb5d83cdffb200d2640fe0f","d83ddeb5d83cdffc200d2640fe0f","d83ddeb5d83cdffd200d2640fe0f","d83ddeb5d83cdffe200d2640fe0f","d83ddeb5d83cdfff200d2640fe0f"],["d83edd38","d83edd38d83cdffb","d83edd38d83cdffc","d83edd38d83cdffd","d83edd38d83cdffe","d83edd38d83cdfff"],["d83edd38200d2642fe0f","d83edd38d83cdffb200d2642fe0f","d83edd38d83cdffc200d2642fe0f","d83edd38d83cdffd200d2642fe0f","d83edd38d83cdffe200d2642fe0f","d83edd38d83cdfff200d2642fe0f"],["d83edd38200d2640fe0f","d83edd38d83cdffb200d2640fe0f","d83edd38d83cdffc200d2640fe0f","d83edd38d83cdffd200d2640fe0f","d83edd38d83cdffe200d2640fe0f","d83edd38d83cdfff200d2640fe0f"],["d83edd3c"],["d83edd3c200d2642fe0f"],["d83edd3c200d2640fe0f"],["d83edd3d","d83edd3dd83cdffb","d83edd3dd83cdffc","d83edd3dd83cdffd","d83edd3dd83cdffe","d83edd3dd83cdfff"],["d83edd3d200d2642fe0f","d83edd3dd83cdffb200d2642fe0f","d83edd3dd83cdffc200d2642fe0f","d83edd3dd83cdffd200d2642fe0f","d83edd3dd83cdffe200d2642fe0f","d83edd3dd83cdfff200d2642fe0f"],["d83edd3d200d2640fe0f","d83edd3dd83cdffb200d2640fe0f","d83edd3dd83cdffc200d2640fe0f","d83edd3dd83cdffd200d2640fe0f","d83edd3dd83cdffe200d2640fe0f","d83edd3dd83cdfff200d2640fe0f"],["d83edd3e","d83edd3ed83cdffb","d83edd3ed83cdffc","d83edd3ed83cdffd","d83edd3ed83cdffe","d83edd3ed83cdfff"],["d83edd3e200d2642fe0f","d83edd3ed83cdffb200d2642fe0f","d83edd3ed83cdffc200d2642fe0f","d83edd3ed83cdffd200d2642fe0f","d83edd3ed83cdffe200d2642fe0f","d83edd3ed83cdfff200d2642fe0f"],["d83edd3e200d2640fe0f","d83edd3ed83cdffb200d2640fe0f","d83edd3ed83cdffc200d2640fe0f","d83edd3ed83cdffd200d2640fe0f","d83edd3ed83cdffe200d2640fe0f","d83edd3ed83cdfff200d2640fe0f"],["d83edd39","d83edd39d83cdffb","d83edd39d83cdffc","d83edd39d83cdffd","d83edd39d83cdffe","d83edd39d83cdfff"],["d83edd39200d2642fe0f","d83edd39d83cdffb200d2642fe0f","d83edd39d83cdffc200d2642fe0f","d83edd39d83cdffd200d2642fe0f","d83edd39d83cdffe200d2642fe0f","d83edd39d83cdfff200d2642fe0f"],["d83edd39200d2640fe0f","d83edd39d83cdffb200d2640fe0f","d83edd39d83cdffc200d2640fe0f","d83edd39d83cdffd200d2640fe0f","d83edd39d83cdffe200d2640fe0f","d83edd39d83cdfff200d2640fe0f"],["d83eddd8","d83eddd8d83cdffb","d83eddd8d83cdffc","d83eddd8d83cdffd","d83eddd8d83cdffe","d83eddd8d83cdfff"],["d83eddd8200d2642fe0f","d83eddd8d83cdffb200d2642fe0f","d83eddd8d83cdffc200d2642fe0f","d83eddd8d83cdffd200d2642fe0f","d83eddd8d83cdffe200d2642fe0f","d83eddd8d83cdfff200d2642fe0f"],["d83eddd8200d2640fe0f","d83eddd8d83cdffb200d2640fe0f","d83eddd8d83cdffc200d2640fe0f","d83eddd8d83cdffd200d2640fe0f","d83eddd8d83cdffe200d2640fe0f","d83eddd8d83cdfff200d2640fe0f"],["d83ddec0","d83ddec0d83cdffb","d83ddec0d83cdffc","d83ddec0d83cdffd","d83ddec0d83cdffe","d83ddec0d83cdfff"],["d83ddecc","d83ddeccd83cdffb","d83ddeccd83cdffc","d83ddeccd83cdffd","d83ddeccd83cdffe","d83ddeccd83cdfff"],["d83eddd1200dd83edd1d200dd83eddd1","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdfff","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdfff","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdfff","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdfff","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdfff"],["d83ddc6d","d83ddc6dd83cdffb","d83ddc6dd83cdffc","d83ddc6dd83cdffd","d83ddc6dd83cdffe","d83ddc6dd83cdfff","d83ddc69d83cdffb200dd83edd1d200dd83ddc69d83cdffc","d83ddc69d83cdffb200dd83edd1d200dd83ddc69d83cdffd","d83ddc69d83cdffb200dd83edd1d200dd83ddc69d83cdffe","d83ddc69d83cdffb200dd83edd1d200dd83ddc69d83cdfff","d83ddc69d83cdffc200dd83edd1d200dd83ddc69d83cdffb","d83ddc69d83cdffc200dd83edd1d200dd83ddc69d83cdffd","d83ddc69d83cdffc200dd83edd1d200dd83ddc69d83cdffe","d83ddc69d83cdffc200dd83edd1d200dd83ddc69d83cdfff","d83ddc69d83cdffd200dd83edd1d200dd83ddc69d83cdffb","d83ddc69d83cdffd200dd83edd1d200dd83ddc69d83cdffc","d83ddc69d83cdffd200dd83edd1d200dd83ddc69d83cdffe","d83ddc69d83cdffd200dd83edd1d200dd83ddc69d83cdfff","d83ddc69d83cdffe200dd83edd1d200dd83ddc69d83cdffb","d83ddc69d83cdffe200dd83edd1d200dd83ddc69d83cdffc","d83ddc69d83cdffe200dd83edd1d200dd83ddc69d83cdffd","d83ddc69d83cdffe200dd83edd1d200dd83ddc69d83cdfff","d83ddc69d83cdfff200dd83edd1d200dd83ddc69d83cdffb","d83ddc69d83cdfff200dd83edd1d200dd83ddc69d83cdffc","d83ddc69d83cdfff200dd83edd1d200dd83ddc69d83cdffd","d83ddc69d83cdfff200dd83edd1d200dd83ddc69d83cdffe"]],"People_8":[["d83ddc6b","d83ddc6bd83cdffb","d83ddc6bd83cdffc","d83ddc6bd83cdffd","d83ddc6bd83cdffe","d83ddc6bd83cdfff","d83ddc69d83cdffb200dd83edd1d200dd83ddc68d83cdffc","d83ddc69d83cdffb200dd83edd1d200dd83ddc68d83cdffd","d83ddc69d83cdffb200dd83edd1d200dd83ddc68d83cdffe","d83ddc69d83cdffb200dd83edd1d200dd83ddc68d83cdfff","d83ddc69d83cdffc200dd83edd1d200dd83ddc68d83cdffb","d83ddc69d83cdffc200dd83edd1d200dd83ddc68d83cdffd","d83ddc69d83cdffc200dd83edd1d200dd83ddc68d83cdffe","d83ddc69d83cdffc200dd83edd1d200dd83ddc68d83cdfff","d83ddc69d83cdffd200dd83edd1d200dd83ddc68d83cdffb","d83ddc69d83cdffd200dd83edd1d200dd83ddc68d83cdffc","d83ddc69d83cdffd200dd83edd1d200dd83ddc68d83cdffe","d83ddc69d83cdffd200dd83edd1d200dd83ddc68d83cdfff","d83ddc69d83cdffe200dd83edd1d200dd83ddc68d83cdffb","d83ddc69d83cdffe200dd83edd1d200dd83ddc68d83cdffc","d83ddc69d83cdffe200dd83edd1d200dd83ddc68d83cdffd","d83ddc69d83cdffe200dd83edd1d200dd83ddc68d83cdfff","d83ddc69d83cdfff200dd83edd1d200dd83ddc68d83cdffb","d83ddc69d83cdfff200dd83edd1d200dd83ddc68d83cdffc","d83ddc69d83cdfff200dd83edd1d200dd83ddc68d83cdffd","d83ddc69d83cdfff200dd83edd1d200dd83ddc68d83cdffe"],["d83ddc6c","d83ddc6cd83cdffb","d83ddc6cd83cdffc","d83ddc6cd83cdffd","d83ddc6cd83cdffe","d83ddc6cd83cdfff","d83ddc68d83cdffb200dd83edd1d200dd83ddc68d83cdffc","d83ddc68d83cdffb200dd83edd1d200dd83ddc68d83cdffd","d83ddc68d83cdffb200dd83edd1d200dd83ddc68d83cdffe","d83ddc68d83cdffb200dd83edd1d200dd83ddc68d83cdfff","d83ddc68d83cdffc200dd83edd1d200dd83ddc68d83cdffb","d83ddc68d83cdffc200dd83edd1d200dd83ddc68d83cdffd","d83ddc68d83cdffc200dd83edd1d200dd83ddc68d83cdffe","d83ddc68d83cdffc200dd83edd1d200dd83ddc68d83cdfff","d83ddc68d83cdffd200dd83edd1d200dd83ddc68d83cdffb","d83ddc68d83cdffd200dd83edd1d200dd83ddc68d83cdffc","d83ddc68d83cdffd200dd83edd1d200dd83ddc68d83cdffe","d83ddc68d83cdffd200dd83edd1d200dd83ddc68d83cdfff","d83ddc68d83cdffe200dd83edd1d200dd83ddc68d83cdffb","d83ddc68d83cdffe200dd83edd1d200dd83ddc68d83cdffc","d83ddc68d83cdffe200dd83edd1d200dd83ddc68d83cdffd","d83ddc68d83cdffe200dd83edd1d200dd83ddc68d83cdfff","d83ddc68d83cdfff200dd83edd1d200dd83ddc68d83cdffb","d83ddc68d83cdfff200dd83edd1d200dd83ddc68d83cdffc","d83ddc68d83cdfff200dd83edd1d200dd83ddc68d83cdffd","d83ddc68d83cdfff200dd83edd1d200dd83ddc68d83cdffe"],["d83ddc8f","d83ddc8fd83cdffb","d83ddc8fd83cdffc","d83ddc8fd83cdffd","d83ddc8fd83cdffe","d83ddc8fd83cdfff","d83eddd1d83cdffb200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffc","d83eddd1d83cdffb200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffd","d83eddd1d83cdffb200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffe","d83eddd1d83cdffb200d2764fe0f200dd83ddc8b200dd83eddd1d83cdfff","d83eddd1d83cdffc200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffb","d83eddd1d83cdffc200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffd","d83eddd1d83cdffc200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffe","d83eddd1d83cdffc200d2764fe0f200dd83ddc8b200dd83eddd1d83cdfff","d83eddd1d83cdffd200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffb","d83eddd1d83cdffd200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffc","d83eddd1d83cdffd200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffe","d83eddd1d83cdffd200d2764fe0f200dd83ddc8b200dd83eddd1d83cdfff","d83eddd1d83cdffe200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffb","d83eddd1d83cdffe200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffc","d83eddd1d83cdffe200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffd","d83eddd1d83cdffe200d2764fe0f200dd83ddc8b200dd83eddd1d83cdfff","d83eddd1d83cdfff200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffb","d83eddd1d83cdfff200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffc","d83eddd1d83cdfff200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffd","d83eddd1d83cdfff200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffe"],["d83ddc69200d2764fe0f200dd83ddc8b200dd83ddc68","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff"],["d83ddc68200d2764fe0f200dd83ddc8b200dd83ddc68","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff"],["d83ddc69200d2764fe0f200dd83ddc8b200dd83ddc69","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff"]],"People_9":[["d83ddc91","d83ddc91d83cdffb","d83ddc91d83cdffc","d83ddc91d83cdffd","d83ddc91d83cdffe","d83ddc91d83cdfff","d83eddd1d83cdffb200d2764fe0f200dd83eddd1d83cdffc","d83eddd1d83cdffb200d2764fe0f200dd83eddd1d83cdffd","d83eddd1d83cdffb200d2764fe0f200dd83eddd1d83cdffe","d83eddd1d83cdffb200d2764fe0f200dd83eddd1d83cdfff","d83eddd1d83cdffc200d2764fe0f200dd83eddd1d83cdffb","d83eddd1d83cdffc200d2764fe0f200dd83eddd1d83cdffd","d83eddd1d83cdffc200d2764fe0f200dd83eddd1d83cdffe","d83eddd1d83cdffc200d2764fe0f200dd83eddd1d83cdfff","d83eddd1d83cdffd200d2764fe0f200dd83eddd1d83cdffb","d83eddd1d83cdffd200d2764fe0f200dd83eddd1d83cdffc","d83eddd1d83cdffd200d2764fe0f200dd83eddd1d83cdffe","d83eddd1d83cdffd200d2764fe0f200dd83eddd1d83cdfff","d83eddd1d83cdffe200d2764fe0f200dd83eddd1d83cdffb","d83eddd1d83cdffe200d2764fe0f200dd83eddd1d83cdffc","d83eddd1d83cdffe200d2764fe0f200dd83eddd1d83cdffd","d83eddd1d83cdffe200d2764fe0f200dd83eddd1d83cdfff","d83eddd1d83cdfff200d2764fe0f200dd83eddd1d83cdffb","d83eddd1d83cdfff200d2764fe0f200dd83eddd1d83cdffc","d83eddd1d83cdfff200d2764fe0f200dd83eddd1d83cdffd","d83eddd1d83cdfff200d2764fe0f200dd83eddd1d83cdffe"],["d83ddc69200d2764fe0f200dd83ddc68","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdfff","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdfff","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdfff","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdfff","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdfff"],["d83ddc68200d2764fe0f200dd83ddc68","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdfff","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdfff","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdfff","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdfff","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdfff"],["d83ddc69200d2764fe0f200dd83ddc69","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdfff","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdfff","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdfff","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdfff","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdfff"],["d83ddc6a"],["d83ddc68200dd83ddc69200dd83ddc66"],["d83ddc68200dd83ddc69200dd83ddc67"],["d83ddc68200dd83ddc69200dd83ddc67200dd83ddc66"],["d83ddc68200dd83ddc69200dd83ddc66200dd83ddc66"],["d83ddc68200dd83ddc69200dd83ddc67200dd83ddc67"],["d83ddc68200dd83ddc68200dd83ddc66"],["d83ddc68200dd83ddc68200dd83ddc67"],["d83ddc68200dd83ddc68200dd83ddc67200dd83ddc66"],["d83ddc68200dd83ddc68200dd83ddc66200dd83ddc66"],["d83ddc68200dd83ddc68200dd83ddc67200dd83ddc67"],["d83ddc69200dd83ddc69200dd83ddc66"],["d83ddc69200dd83ddc69200dd83ddc67"],["d83ddc69200dd83ddc69200dd83ddc67200dd83ddc66"],["d83ddc69200dd83ddc69200dd83ddc66200dd83ddc66"],["d83ddc69200dd83ddc69200dd83ddc67200dd83ddc67"],["d83ddc68200dd83ddc66"],["d83ddc68200dd83ddc66200dd83ddc66"],["d83ddc68200dd83ddc67"],["d83ddc68200dd83ddc67200dd83ddc66"],["d83ddc68200dd83ddc67200dd83ddc67"],["d83ddc69200dd83ddc66"],["d83ddc69200dd83ddc66200dd83ddc66"],["d83ddc69200dd83ddc67"],["d83ddc69200dd83ddc67200dd83ddc66"],["d83ddc69200dd83ddc67200dd83ddc67"],["d83ddde3fe0f"],["d83ddc64"],["d83ddc65"],["d83edec2"],["d83ddc63"]],"Nature":[["d83ddc35"],["d83ddc12"],["d83edd8d"],["d83edda7"],["d83ddc36"],["d83ddc15"],["d83eddae"],["d83ddc15200dd83eddba"],["d83ddc29"],["d83ddc3a"],["d83edd8a"],["d83edd9d"],["d83ddc31"],["d83ddc08"],["d83ddc08200d2b1b"],["d83edd81"],["d83ddc2f"],["d83ddc05"],["d83ddc06"],["d83ddc34"],["d83ddc0e"],["d83edd84"],["d83edd93"],["d83edd8c"],["d83eddac"],["d83ddc2e"],["d83ddc02"],["d83ddc03"],["d83ddc04"],["d83ddc37"],["d83ddc16"],["d83ddc17"],["d83ddc3d"],["d83ddc0f"],["d83ddc11"],["d83ddc10"],["d83ddc2a"],["d83ddc2b"],["d83edd99"],["d83edd92"],["d83ddc18"],["d83edda3"],["d83edd8f"],["d83edd9b"],["d83ddc2d"],["d83ddc01"],["d83ddc00"],["d83ddc39"],["d83ddc30"],["d83ddc07"],["d83ddc3ffe0f"],["d83eddab"],["d83edd94"],["d83edd87"],["d83ddc3b"],["d83ddc3b200d2744fe0f"],["d83ddc28"],["d83ddc3c"],["d83edda5"],["d83edda6"],["d83edda8"],["d83edd98"],["d83edda1"],["d83ddc3e"],["d83edd83"],["d83ddc14"],["d83ddc13"],["d83ddc23"],["d83ddc24"],["d83ddc25"],["d83ddc26"],["d83ddc27"],["d83ddd4afe0f"],["d83edd85"],["d83edd86"],["d83edda2"],["d83edd89"],["d83edda4"],["d83edeb6"],["d83edda9"],["d83edd9a"],["d83edd9c"],["d83ddc38"],["d83ddc0a"],["d83ddc22"],["d83edd8e"],["d83ddc0d"],["d83ddc32"],["d83ddc09"],["d83edd95"],["d83edd96"],["d83ddc33"],["d83ddc0b"],["d83ddc2c"],["d83eddad"],["d83ddc1f"],["d83ddc20"],["d83ddc21"],["d83edd88"],["d83ddc19"],["d83ddc1a"],["d83edeb8"],["d83ddc0c"],["d83edd8b"],["d83ddc1b"],["d83ddc1c"],["d83ddc1d"],["d83edeb2"],["d83ddc1e"],["d83edd97"],["d83edeb3"],["d83ddd77fe0f"],["d83ddd78fe0f"],["d83edd82"],["d83edd9f"],["d83edeb0"],["d83edeb1"],["d83edda0"],["d83ddc90"],["d83cdf38"],["d83ddcae"],["d83edeb7"],["d83cdff5fe0f"],["d83cdf39"],["d83edd40"],["d83cdf3a"],["d83cdf3b"],["d83cdf3c"],["d83cdf37"],["d83cdf31"],["d83edeb4"],["d83cdf32"],["d83cdf33"],["d83cdf34"],["d83cdf35"],["d83cdf3e"],["d83cdf3f"],["2618fe0f"],["d83cdf40"],["d83cdf41"],["d83cdf42"],["d83cdf43"],["d83edeb9"],["d83edeba"]],"Foods":[["d83cdf47"],["d83cdf48"],["d83cdf49"],["d83cdf4a"],["d83cdf4b"],["d83cdf4c"],["d83cdf4d"],["d83edd6d"],["d83cdf4e"],["d83cdf4f"],["d83cdf50"],["d83cdf51"],["d83cdf52"],["d83cdf53"],["d83eded0"],["d83edd5d"],["d83cdf45"],["d83eded2"],["d83edd65"],["d83edd51"],["d83cdf46"],["d83edd54"],["d83edd55"],["d83cdf3d"],["d83cdf36fe0f"],["d83eded1"],["d83edd52"],["d83edd6c"],["d83edd66"],["d83eddc4"],["d83eddc5"],["d83cdf44"],["d83edd5c"],["d83eded8"],["d83cdf30"],["d83cdf5e"],["d83edd50"],["d83edd56"],["d83eded3"],["d83edd68"],["d83edd6f"],["d83edd5e"],["d83eddc7"],["d83eddc0"],["d83cdf56"],["d83cdf57"],["d83edd69"],["d83edd53"],["d83cdf54"],["d83cdf5f"],["d83cdf55"],["d83cdf2d"],["d83edd6a"],["d83cdf2e"],["d83cdf2f"],["d83eded4"],["d83edd59"],["d83eddc6"],["d83edd5a"],["d83cdf73"],["d83edd58"],["d83cdf72"],["d83eded5"],["d83edd63"],["d83edd57"],["d83cdf7f"],["d83eddc8"],["d83eddc2"],["d83edd6b"],["d83cdf71"],["d83cdf58"],["d83cdf59"],["d83cdf5a"],["d83cdf5b"],["d83cdf5c"],["d83cdf5d"],["d83cdf60"],["d83cdf62"],["d83cdf63"],["d83cdf64"],["d83cdf65"],["d83edd6e"],["d83cdf61"],["d83edd5f"],["d83edd60"],["d83edd61"],["d83edd80"],["d83edd9e"],["d83edd90"],["d83edd91"],["d83eddaa"],["d83cdf66"],["d83cdf67"],["d83cdf68"],["d83cdf69"],["d83cdf6a"],["d83cdf82"],["d83cdf70"],["d83eddc1"],["d83edd67"],["d83cdf6b"],["d83cdf6c"],["d83cdf6d"],["d83cdf6e"],["d83cdf6f"],["d83cdf7c"],["d83edd5b"],["2615"],["d83eded6"],["d83cdf75"],["d83cdf76"],["d83cdf7e"],["d83cdf77"],["d83cdf78"],["d83cdf79"],["d83cdf7a"],["d83cdf7b"],["d83edd42"],["d83edd43"],["d83eded7"],["d83edd64"],["d83eddcb"],["d83eddc3"],["d83eddc9"],["d83eddca"],["d83edd62"],["d83cdf7dfe0f"],["d83cdf74"],["d83edd44"],["d83ddd2a"],["d83eded9"],["d83cdffa"]],"Places":[["d83cdf0d"],["d83cdf0e"],["d83cdf0f"],["d83cdf10"],["d83dddfafe0f"],["d83dddfe"],["d83edded"],["d83cdfd4fe0f"],["26f0fe0f"],["d83cdf0b"],["d83dddfb"],["d83cdfd5fe0f"],["d83cdfd6fe0f"],["d83cdfdcfe0f"],["d83cdfddfe0f"],["d83cdfdefe0f"],["d83cdfdffe0f"],["d83cdfdbfe0f"],["d83cdfd7fe0f"],["d83eddf1"],["d83edea8"],["d83edeb5"],["d83dded6"],["d83cdfd8fe0f"],["d83cdfdafe0f"],["d83cdfe0"],["d83cdfe1"],["d83cdfe2"],["d83cdfe3"],["d83cdfe4"],["d83cdfe5"],["d83cdfe6"],["d83cdfe8"],["d83cdfe9"],["d83cdfea"],["d83cdfeb"],["d83cdfec"],["d83cdfed"],["d83cdfef"],["d83cdff0"],["d83ddc92"],["d83dddfc"],["d83dddfd"],["26ea"],["d83ddd4c"],["d83dded5"],["d83ddd4d"],["26e9fe0f"],["d83ddd4b"],["26f2"],["26fa"],["d83cdf01"],["d83cdf03"],["d83cdfd9fe0f"],["d83cdf04"],["d83cdf05"],["d83cdf06"],["d83cdf07"],["d83cdf09"],["2668fe0f"],["d83cdfa0"],["d83ddedd"],["d83cdfa1"],["d83cdfa2"],["d83ddc88"],["d83cdfaa"],["d83dde82"],["d83dde83"],["d83dde84"],["d83dde85"],["d83dde86"],["d83dde87"],["d83dde88"],["d83dde89"],["d83dde8a"],["d83dde9d"],["d83dde9e"],["d83dde8b"],["d83dde8c"],["d83dde8d"],["d83dde8e"],["d83dde90"],["d83dde91"],["d83dde92"],["d83dde93"],["d83dde94"],["d83dde95"],["d83dde96"],["d83dde97"],["d83dde98"],["d83dde99"],["d83ddefb"],["d83dde9a"],["d83dde9b"],["d83dde9c"],["d83cdfcefe0f"],["d83cdfcdfe0f"],["d83ddef5"],["d83eddbd"],["d83eddbc"],["d83ddefa"],["d83ddeb2"],["d83ddef4"],["d83ddef9"],["d83ddefc"],["d83dde8f"],["d83ddee3fe0f"],["d83ddee4fe0f"],["d83ddee2fe0f"],["26fd"],["d83ddede"],["d83ddea8"],["d83ddea5"],["d83ddea6"],["d83dded1"],["d83ddea7"],["2693"],["d83ddedf"],["26f5"],["d83ddef6"],["d83ddea4"],["d83ddef3fe0f"],["26f4fe0f"],["d83ddee5fe0f"],["d83ddea2"],["2708fe0f"],["d83ddee9fe0f"],["d83ddeeb"],["d83ddeec"],["d83ede82"],["d83ddcba"],["d83dde81"],["d83dde9f"],["d83ddea0"],["d83ddea1"],["d83ddef0fe0f"],["d83dde80"],["d83ddef8"],["d83ddecefe0f"],["d83eddf3"],["231b"],["23f3"],["231a"],["23f0"],["23f1fe0f"],["23f2fe0f"],["d83ddd70fe0f"],["d83ddd5b"],["d83ddd67"],["d83ddd50"],["d83ddd5c"],["d83ddd51"],["d83ddd5d"],["d83ddd52"],["d83ddd5e"],["d83ddd53"],["d83ddd5f"],["d83ddd54"],["d83ddd60"],["d83ddd55"],["d83ddd61"],["d83ddd56"],["d83ddd62"],["d83ddd57"],["d83ddd63"],["d83ddd58"],["d83ddd64"],["d83ddd59"],["d83ddd65"],["d83ddd5a"],["d83ddd66"],["d83cdf11"],["d83cdf12"],["d83cdf13"],["d83cdf14"],["d83cdf15"],["d83cdf16"],["d83cdf17"],["d83cdf18"],["d83cdf19"],["d83cdf1a"],["d83cdf1b"],["d83cdf1c"],["d83cdf21fe0f"],["2600fe0f"],["d83cdf1d"],["d83cdf1e"],["d83ede90"],["2b50"],["d83cdf1f"],["d83cdf20"],["d83cdf0c"],["2601fe0f"],["26c5"],["26c8fe0f"],["d83cdf24fe0f"],["d83cdf25fe0f"],["d83cdf26fe0f"],["d83cdf27fe0f"],["d83cdf28fe0f"],["d83cdf29fe0f"],["d83cdf2afe0f"],["d83cdf2bfe0f"],["d83cdf2cfe0f"],["d83cdf00"],["d83cdf08"],["d83cdf02"],["2602fe0f"],["2614"],["26f1fe0f"],["26a1"],["2744fe0f"],["2603fe0f"],["26c4"],["2604fe0f"],["d83ddd25"],["d83ddca7"],["d83cdf0a"]],"Activity":[["d83cdf83"],["d83cdf84"],["d83cdf86"],["d83cdf87"],["d83edde8"],["2728"],["d83cdf88"],["d83cdf89"],["d83cdf8a"],["d83cdf8b"],["d83cdf8d"],["d83cdf8e"],["d83cdf8f"],["d83cdf90"],["d83cdf91"],["d83edde7"],["d83cdf80"],["d83cdf81"],["d83cdf97fe0f"],["d83cdf9ffe0f"],["d83cdfab"],["d83cdf96fe0f"],["d83cdfc6"],["d83cdfc5"],["d83edd47"],["d83edd48"],["d83edd49"],["26bd"],["26be"],["d83edd4e"],["d83cdfc0"],["d83cdfd0"],["d83cdfc8"],["d83cdfc9"],["d83cdfbe"],["d83edd4f"],["d83cdfb3"],["d83cdfcf"],["d83cdfd1"],["d83cdfd2"],["d83edd4d"],["d83cdfd3"],["d83cdff8"],["d83edd4a"],["d83edd4b"],["d83edd45"],["26f3"],["26f8fe0f"],["d83cdfa3"],["d83edd3f"],["d83cdfbd"],["d83cdfbf"],["d83ddef7"],["d83edd4c"],["d83cdfaf"],["d83ede80"],["d83ede81"],["d83cdfb1"],["d83ddd2e"],["d83ede84"],["d83eddff"],["d83edeac"],["d83cdfae"],["d83ddd79fe0f"],["d83cdfb0"],["d83cdfb2"],["d83edde9"],["d83eddf8"],["d83ede85"],["d83edea9"],["d83ede86"],["2660fe0f"],["2665fe0f"],["2666fe0f"],["2663fe0f"],["265ffe0f"],["d83cdccf"],["d83cdc04"],["d83cdfb4"],["d83cdfad"],["d83dddbcfe0f"],["d83cdfa8"],["d83eddf5"],["d83edea1"],["d83eddf6"],["d83edea2"]],"Objects":[["d83ddc53"],["d83ddd76fe0f"],["d83edd7d"],["d83edd7c"],["d83eddba"],["d83ddc54"],["d83ddc55"],["d83ddc56"],["d83edde3"],["d83edde4"],["d83edde5"],["d83edde6"],["d83ddc57"],["d83ddc58"],["d83edd7b"],["d83ede71"],["d83ede72"],["d83ede73"],["d83ddc59"],["d83ddc5a"],["d83ddc5b"],["d83ddc5c"],["d83ddc5d"],["d83ddecdfe0f"],["d83cdf92"],["d83ede74"],["d83ddc5e"],["d83ddc5f"],["d83edd7e"],["d83edd7f"],["d83ddc60"],["d83ddc61"],["d83ede70"],["d83ddc62"],["d83ddc51"],["d83ddc52"],["d83cdfa9"],["d83cdf93"],["d83edde2"],["d83ede96"],["26d1fe0f"],["d83ddcff"],["d83ddc84"],["d83ddc8d"],["d83ddc8e"],["d83ddd07"],["d83ddd08"],["d83ddd09"],["d83ddd0a"],["d83ddce2"],["d83ddce3"],["d83ddcef"],["d83ddd14"],["d83ddd15"],["d83cdfbc"],["d83cdfb5"],["d83cdfb6"],["d83cdf99fe0f"],["d83cdf9afe0f"],["d83cdf9bfe0f"],["d83cdfa4"],["d83cdfa7"],["d83ddcfb"],["d83cdfb7"],["d83ede97"],["d83cdfb8"],["d83cdfb9"],["d83cdfba"],["d83cdfbb"],["d83ede95"],["d83edd41"],["d83ede98"],["d83ddcf1"],["d83ddcf2"],["260efe0f"],["d83ddcde"],["d83ddcdf"],["d83ddce0"],["d83ddd0b"],["d83edeab"],["d83ddd0c"],["d83ddcbb"],["d83ddda5fe0f"],["d83ddda8fe0f"],["2328fe0f"],["d83dddb1fe0f"],["d83dddb2fe0f"],["d83ddcbd"],["d83ddcbe"],["d83ddcbf"],["d83ddcc0"],["d83eddee"],["d83cdfa5"],["d83cdf9efe0f"],["d83ddcfdfe0f"],["d83cdfac"],["d83ddcfa"],["d83ddcf7"],["d83ddcf8"],["d83ddcf9"],["d83ddcfc"],["d83ddd0d"],["d83ddd0e"],["d83ddd6ffe0f"],["d83ddca1"],["d83ddd26"],["d83cdfee"],["d83ede94"],["d83ddcd4"],["d83ddcd5"],["d83ddcd6"],["d83ddcd7"],["d83ddcd8"],["d83ddcd9"],["d83ddcda"],["d83ddcd3"],["d83ddcd2"],["d83ddcc3"],["d83ddcdc"],["d83ddcc4"],["d83ddcf0"],["d83ddddefe0f"],["d83ddcd1"],["d83ddd16"],["d83cdff7fe0f"],["d83ddcb0"],["d83ede99"],["d83ddcb4"],["d83ddcb5"],["d83ddcb6"],["d83ddcb7"],["d83ddcb8"],["d83ddcb3"],["d83eddfe"],["d83ddcb9"],["2709fe0f"],["d83ddce7"],["d83ddce8"],["d83ddce9"],["d83ddce4"],["d83ddce5"],["d83ddce6"],["d83ddceb"],["d83ddcea"],["d83ddcec"],["d83ddced"],["d83ddcee"],["d83dddf3fe0f"],["270ffe0f"],["2712fe0f"],["d83ddd8bfe0f"],["d83ddd8afe0f"],["d83ddd8cfe0f"],["d83ddd8dfe0f"],["d83ddcdd"],["d83ddcbc"],["d83ddcc1"],["d83ddcc2"],["d83dddc2fe0f"],["d83ddcc5"],["d83ddcc6"],["d83dddd2fe0f"],["d83dddd3fe0f"],["d83ddcc7"],["d83ddcc8"],["d83ddcc9"],["d83ddcca"],["d83ddccb"],["d83ddccc"],["d83ddccd"],["d83ddcce"],["d83ddd87fe0f"],["d83ddccf"],["d83ddcd0"],["2702fe0f"],["d83dddc3fe0f"],["d83dddc4fe0f"],["d83dddd1fe0f"],["d83ddd12"],["d83ddd13"],["d83ddd0f"],["d83ddd10"],["d83ddd11"],["d83dddddfe0f"],["d83ddd28"],["d83ede93"],["26cffe0f"],["2692fe0f"],["d83ddee0fe0f"],["d83ddde1fe0f"],["2694fe0f"],["d83ddd2b"],["d83ede83"],["d83cdff9"],["d83ddee1fe0f"],["d83ede9a"],["d83ddd27"],["d83ede9b"],["d83ddd29"],["2699fe0f"],["d83ddddcfe0f"],["2696fe0f"],["d83eddaf"],["d83ddd17"],["26d3fe0f"],["d83ede9d"],["d83eddf0"],["d83eddf2"],["d83ede9c"],["2697fe0f"],["d83eddea"],["d83eddeb"],["d83eddec"],["d83ddd2c"],["d83ddd2d"],["d83ddce1"],["d83ddc89"],["d83ede78"],["d83ddc8a"],["d83ede79"],["d83ede7c"],["d83ede7a"],["d83ede7b"],["d83ddeaa"],["d83dded7"],["d83ede9e"],["d83ede9f"],["d83ddecffe0f"],["d83ddecbfe0f"],["d83ede91"],["d83ddebd"],["d83edea0"],["d83ddebf"],["d83ddec1"],["d83edea4"],["d83ede92"],["d83eddf4"],["d83eddf7"],["d83eddf9"],["d83eddfa"],["d83eddfb"],["d83edea3"],["d83eddfc"],["d83edee7"],["d83edea5"],["d83eddfd"],["d83eddef"],["d83dded2"],["d83ddeac"],["26b0fe0f"],["d83edea6"],["26b1fe0f"],["d83dddff"],["d83edea7"],["d83edeaa"]],"Symbols":[["d83cdfe7"],["d83ddeae"],["d83ddeb0"],["267f"],["d83ddeb9"],["d83ddeba"],["d83ddebb"],["d83ddebc"],["d83ddebe"],["d83ddec2"],["d83ddec3"],["d83ddec4"],["d83ddec5"],["26a0fe0f"],["d83ddeb8"],["26d4"],["d83ddeab"],["d83ddeb3"],["d83ddead"],["d83ddeaf"],["d83ddeb1"],["d83ddeb7"],["d83ddcf5"],["d83ddd1e"],["2622fe0f"],["2623fe0f"],["2b06fe0f"],["2197fe0f"],["27a1fe0f"],["2198fe0f"],["2b07fe0f"],["2199fe0f"],["2b05fe0f"],["2196fe0f"],["2195fe0f"],["2194fe0f"],["21a9fe0f"],["21aafe0f"],["2934fe0f"],["2935fe0f"],["d83ddd03"],["d83ddd04"],["d83ddd19"],["d83ddd1a"],["d83ddd1b"],["d83ddd1c"],["d83ddd1d"],["d83dded0"],["269bfe0f"],["d83ddd49fe0f"],["2721fe0f"],["2638fe0f"],["262ffe0f"],["271dfe0f"],["2626fe0f"],["262afe0f"],["262efe0f"],["d83ddd4e"],["d83ddd2f"],["2648"],["2649"],["264a"],["264b"],["264c"],["264d"],["264e"],["264f"],["2650"],["2651"],["2652"],["2653"],["26ce"],["d83ddd00"],["d83ddd01"],["d83ddd02"],["25b6fe0f"],["23e9"],["23edfe0f"],["23effe0f"],["25c0fe0f"],["23ea"],["23eefe0f"],["d83ddd3c"],["23eb"],["d83ddd3d"],["23ec"],["23f8fe0f"],["23f9fe0f"],["23fafe0f"],["23cffe0f"],["d83cdfa6"],["d83ddd05"],["d83ddd06"],["d83ddcf6"],["d83ddcf3"],["d83ddcf4"],["26a7fe0f"],["2716fe0f"],["2795"],["2796"],["2797"],["d83ddff0"],["267efe0f"],["203cfe0f"],["2049fe0f"],["2753"],["2754"],["2755"],["2757"],["3030fe0f"],["d83ddcb1"],["d83ddcb2"],["267bfe0f"],["269cfe0f"],["d83ddd31"],["d83ddcdb"],["d83ddd30"],["2b55"],["2705"],["2611fe0f"],["2714fe0f"],["274c"],["274e"],["27b0"],["27bf"],["303dfe0f"],["2733fe0f"],["2734fe0f"],["2747fe0f"],["00a9fe0f"],["00aefe0f"],["2122fe0f"],["0023fe0f20e3"],["002afe0f20e3"],["0030fe0f20e3"],["0031fe0f20e3"],["0032fe0f20e3"],["0033fe0f20e3"],["0034fe0f20e3"],["0035fe0f20e3"],["0036fe0f20e3"],["0037fe0f20e3"],["0038fe0f20e3"],["0039fe0f20e3"],["d83ddd1f"],["d83ddd20"],["d83ddd21"],["d83ddd22"],["d83ddd23"],["d83ddd24"],["d83cdd70fe0f"],["d83cdd8e"],["d83cdd71fe0f"],["d83cdd91"],["d83cdd92"],["d83cdd93"],["2139fe0f"],["d83cdd94"],["24c2fe0f"],["d83cdd95"],["d83cdd96"],["d83cdd7efe0f"],["d83cdd97"],["d83cdd7ffe0f"],["d83cdd98"],["d83cdd99"],["d83cdd9a"],["d83cde01"],["d83cde02fe0f"],["d83cde37fe0f"],["d83cde36"],["d83cde2f"],["d83cde50"],["d83cde39"],["d83cde1a"],["d83cde32"],["d83cde51"],["d83cde38"],["d83cde34"],["d83cde33"],["3297fe0f"],["3299fe0f"],["d83cde3a"],["d83cde35"],["d83ddd34"],["d83ddfe0"],["d83ddfe1"],["d83ddfe2"],["d83ddd35"],["d83ddfe3"],["d83ddfe4"],["26ab"],["26aa"],["d83ddfe5"],["d83ddfe7"],["d83ddfe8"],["d83ddfe9"],["d83ddfe6"],["d83ddfea"],["d83ddfeb"],["2b1b"],["2b1c"],["25fcfe0f"],["25fbfe0f"],["25fe"],["25fd"],["25aafe0f"],["25abfe0f"],["d83ddd36"],["d83ddd37"],["d83ddd38"],["d83ddd39"],["d83ddd3a"],["d83ddd3b"],["d83ddca0"],["d83ddd18"],["d83ddd33"],["d83ddd32"]],"Flags_0":[["d83cdfc1"],["d83ddea9"],["d83cdf8c"],["d83cdff4"],["d83cdff3fe0f"],["d83cdff3fe0f200dd83cdf08"],["d83cdff3fe0f200d26a7fe0f"],["d83cdff4200d2620fe0f"],["d83cdde6d83cdde8"],["d83cdde6d83cdde9"],["d83cdde6d83cddea"],["d83cdde6d83cddeb"],["d83cdde6d83cddec"],["d83cdde6d83cddee"],["d83cdde6d83cddf1"],["d83cdde6d83cddf2"],["d83cdde6d83cddf4"],["d83cdde6d83cddf6"],["d83cdde6d83cddf7"],["d83cdde6d83cddf8"],["d83cdde6d83cddf9"],["d83cdde6d83cddfa"],["d83cdde6d83cddfc"],["d83cdde6d83cddfd"],["d83cdde6d83cddff"],["d83cdde7d83cdde6"],["d83cdde7d83cdde7"],["d83cdde7d83cdde9"],["d83cdde7d83cddea"],["d83cdde7d83cddeb"],["d83cdde7d83cddec"],["d83cdde7d83cdded"],["d83cdde7d83cddee"],["d83cdde7d83cddef"],["d83cdde7d83cddf1"],["d83cdde7d83cddf2"],["d83cdde7d83cddf3"],["d83cdde7d83cddf4"],["d83cdde7d83cddf6"],["d83cdde7d83cddf7"],["d83cdde7d83cddf8"],["d83cdde7d83cddf9"],["d83cdde7d83cddfb"],["d83cdde7d83cddfc"],["d83cdde7d83cddfe"],["d83cdde7d83cddff"],["d83cdde8d83cdde6"],["d83cdde8d83cdde8"],["d83cdde8d83cdde9"],["d83cdde8d83cddeb"],["d83cdde8d83cddec"],["d83cdde8d83cdded"],["d83cdde8d83cddee"],["d83cdde8d83cddf0"],["d83cdde8d83cddf1"],["d83cdde8d83cddf2"],["d83cdde8d83cddf3"],["d83cdde8d83cddf4"],["d83cdde8d83cddf5"],["d83cdde8d83cddf7"],["d83cdde8d83cddfa"],["d83cdde8d83cddfb"],["d83cdde8d83cddfc"],["d83cdde8d83cddfd"],["d83cdde8d83cddfe"],["d83cdde8d83cddff"],["d83cdde9d83cddea"],["d83cdde9d83cddec"],["d83cdde9d83cddef"],["d83cdde9d83cddf0"],["d83cdde9d83cddf2"],["d83cdde9d83cddf4"],["d83cdde9d83cddff"],["d83cddead83cdde6"],["d83cddead83cdde8"],["d83cddead83cddea"],["d83cddead83cddec"],["d83cddead83cdded"],["d83cddead83cddf7"],["d83cddead83cddf8"],["d83cddead83cddf9"],["d83cddead83cddfa"],["d83cddebd83cddee"],["d83cddebd83cddef"],["d83cddebd83cddf0"],["d83cddebd83cddf2"],["d83cddebd83cddf4"],["d83cddebd83cddf7"],["d83cddecd83cdde6"],["d83cddecd83cdde7"],["d83cddecd83cdde9"],["d83cddecd83cddea"],["d83cddecd83cddeb"],["d83cddecd83cddec"],["d83cddecd83cdded"],["d83cddecd83cddee"],["d83cddecd83cddf1"],["d83cddecd83cddf2"],["d83cddecd83cddf3"],["d83cddecd83cddf5"],["d83cddecd83cddf6"],["d83cddecd83cddf7"],["d83cddecd83cddf8"],["d83cddecd83cddf9"],["d83cddecd83cddfa"],["d83cddecd83cddfc"],["d83cddecd83cddfe"],["d83cddedd83cddf0"],["d83cddedd83cddf2"],["d83cddedd83cddf3"],["d83cddedd83cddf7"],["d83cddedd83cddf9"],["d83cddedd83cddfa"],["d83cddeed83cdde8"],["d83cddeed83cdde9"],["d83cddeed83cddea"],["d83cddeed83cddf1"],["d83cddeed83cddf2"],["d83cddeed83cddf3"],["d83cddeed83cddf4"],["d83cddeed83cddf6"],["d83cddeed83cddf7"],["d83cddeed83cddf8"],["d83cddeed83cddf9"],["d83cddefd83cddea"],["d83cddefd83cddf2"],["d83cddefd83cddf4"],["d83cddefd83cddf5"],["d83cddf0d83cddea"],["d83cddf0d83cddec"],["d83cddf0d83cdded"],["d83cddf0d83cddee"],["d83cddf0d83cddf2"],["d83cddf0d83cddf3"],["d83cddf0d83cddf5"]],"Flags_1":[["d83cddf0d83cddf7"],["d83cddf0d83cddfc"],["d83cddf0d83cddfe"],["d83cddf0d83cddff"],["d83cddf1d83cdde6"],["d83cddf1d83cdde7"],["d83cddf1d83cdde8"],["d83cddf1d83cddee"],["d83cddf1d83cddf0"],["d83cddf1d83cddf7"],["d83cddf1d83cddf8"],["d83cddf1d83cddf9"],["d83cddf1d83cddfa"],["d83cddf1d83cddfb"],["d83cddf1d83cddfe"],["d83cddf2d83cdde6"],["d83cddf2d83cdde8"],["d83cddf2d83cdde9"],["d83cddf2d83cddea"],["d83cddf2d83cddeb"],["d83cddf2d83cddec"],["d83cddf2d83cdded"],["d83cddf2d83cddf0"],["d83cddf2d83cddf1"],["d83cddf2d83cddf2"],["d83cddf2d83cddf3"],["d83cddf2d83cddf4"],["d83cddf2d83cddf5"],["d83cddf2d83cddf6"],["d83cddf2d83cddf7"],["d83cddf2d83cddf8"],["d83cddf2d83cddf9"],["d83cddf2d83cddfa"],["d83cddf2d83cddfb"],["d83cddf2d83cddfc"],["d83cddf2d83cddfd"],["d83cddf2d83cddfe"],["d83cddf2d83cddff"],["d83cddf3d83cdde6"],["d83cddf3d83cdde8"],["d83cddf3d83cddea"],["d83cddf3d83cddeb"],["d83cddf3d83cddec"],["d83cddf3d83cddee"],["d83cddf3d83cddf1"],["d83cddf3d83cddf4"],["d83cddf3d83cddf5"],["d83cddf3d83cddf7"],["d83cddf3d83cddfa"],["d83cddf3d83cddff"],["d83cddf4d83cddf2"],["d83cddf5d83cdde6"],["d83cddf5d83cddea"],["d83cddf5d83cddeb"],["d83cddf5d83cddec"],["d83cddf5d83cdded"],["d83cddf5d83cddf0"],["d83cddf5d83cddf1"],["d83cddf5d83cddf2"],["d83cddf5d83cddf3"],["d83cddf5d83cddf7"],["d83cddf5d83cddf8"],["d83cddf5d83cddf9"],["d83cddf5d83cddfc"],["d83cddf5d83cddfe"],["d83cddf6d83cdde6"],["d83cddf7d83cddea"],["d83cddf7d83cddf4"],["d83cddf7d83cddf8"],["d83cddf7d83cddfa"],["d83cddf7d83cddfc"],["d83cddf8d83cdde6"],["d83cddf8d83cdde7"],["d83cddf8d83cdde8"],["d83cddf8d83cdde9"],["d83cddf8d83cddea"],["d83cddf8d83cddec"],["d83cddf8d83cdded"],["d83cddf8d83cddee"],["d83cddf8d83cddef"],["d83cddf8d83cddf0"],["d83cddf8d83cddf1"],["d83cddf8d83cddf2"],["d83cddf8d83cddf3"],["d83cddf8d83cddf4"],["d83cddf8d83cddf7"],["d83cddf8d83cddf8"],["d83cddf8d83cddf9"],["d83cddf8d83cddfb"],["d83cddf8d83cddfd"],["d83cddf8d83cddfe"],["d83cddf8d83cddff"],["d83cddf9d83cdde6"],["d83cddf9d83cdde8"],["d83cddf9d83cdde9"],["d83cddf9d83cddeb"],["d83cddf9d83cddec"],["d83cddf9d83cdded"],["d83cddf9d83cddef"],["d83cddf9d83cddf0"],["d83cddf9d83cddf1"],["d83cddf9d83cddf2"],["d83cddf9d83cddf3"],["d83cddf9d83cddf4"],["d83cddf9d83cddf7"],["d83cddf9d83cddf9"],["d83cddf9d83cddfb"],["d83cddf9d83cddfc"],["d83cddf9d83cddff"],["d83cddfad83cdde6"],["d83cddfad83cddec"],["d83cddfad83cddf2"],["d83cddfad83cddf3"],["d83cddfad83cddf8"],["d83cddfad83cddfe"],["d83cddfad83cddff"],["d83cddfbd83cdde6"],["d83cddfbd83cdde8"],["d83cddfbd83cddea"],["d83cddfbd83cddec"],["d83cddfbd83cddee"],["d83cddfbd83cddf3"],["d83cddfbd83cddfa"],["d83cddfcd83cddeb"],["d83cddfcd83cddf8"],["d83cddfdd83cddf0"],["d83cddfed83cddea"],["d83cddfed83cddf9"],["d83cddffd83cdde6"],["d83cddffd83cddf2"],["d83cddffd83cddfc"],["d83cdff4db40dc67db40dc62db40dc65db40dc6edb40dc67db40dc7f"],["d83cdff4db40dc67db40dc62db40dc73db40dc63db40dc74db40dc7f"],["d83cdff4db40dc67db40dc62db40dc77db40dc6cdb40dc73db40dc7f"]]},"obsolete":[],"metrics":{"raw_width":66,"raw_height":66,"per_row":16},"densities":["xhdpi"],"format":"webp"} \ No newline at end of file diff --git a/app/src/main/assets/emoji/emoji_search_index.json b/app/src/main/assets/emoji/emoji_search_index.json deleted file mode 100644 index 966f21be32..0000000000 --- a/app/src/main/assets/emoji/emoji_search_index.json +++ /dev/null @@ -1 +0,0 @@ -[{"emoji":"😀","tags":["face","grin","smile","grinning face","smiling","happy"]},{"emoji":"😃","tags":["face","grinning face with big eyes","open","mouth","smile","smiling","happy"]},{"emoji":"😄","tags":["eye","face","mouth","grinning face with smiling eyes","open","smile","smiling","happy"]},{"emoji":"😁","tags":["beaming face with smiling eyes","eye","grin","face","smile","smiling","happy"]},{"emoji":"😆","tags":["face","grinning squinting face","mouth","laugh","satisfied","smile","smiling","squint","happy"]},{"emoji":"😅","tags":["face","open","grinning face with sweat","smile","sweat","smiling","laugh","funny"]},{"emoji":"🤣","tags":["face","floor","rofl","laugh","rolling","rolling on the floor laughing","rotfl","funny","cry"]},{"emoji":"😂","tags":["face","face with tears of joy","laugh","joy","tear","funny","cry"]},{"emoji":"🙂","tags":["face","slightly smiling face","smiling","smile"]},{"emoji":"🙃","tags":["face","upside-down","sarcasm","silly","sarcastic","uh oh"]},{"emoji":"😉","tags":["face","wink","winking face"]},{"emoji":"😊","tags":["blush","eye","smile","face","smiling face with smiling eyes"]},{"emoji":"😇","tags":["angel","face","halo","fantasy","innocent","smiling face with halo"]},{"emoji":"🥰","tags":["adore","crush","in love","hearts","smiling face with hearts"]},{"emoji":"😍","tags":["eye","face","smile","love","smiling face with heart-eyes","hearts"]},{"emoji":"🤩","tags":["eyes","face","star","grinning","star-struck"]},{"emoji":"😘","tags":["face","face blowing a kiss","flirt","kiss","kiss with heart"]},{"emoji":"😗","tags":["face","kiss","pout","kissing face"]},{"emoji":"☺️","tags":["face","slightly smiling face","smiling","smile"]},{"emoji":"😚","tags":["closed","eye","kiss","face","kissing face with closed eyes","kiss squinty"]},{"emoji":"😙","tags":["eye","face","kissing face with smiling eyes","kiss","smile"]},{"emoji":"🥲","tags":["grateful","proud","smiling","relieved","smiling face with tear","tear","touched"]},{"emoji":"😋","tags":["delicious","face","savouring","face savoring food","smile","yum"]},{"emoji":"😛","tags":["face","face with tongue","tongue"]},{"emoji":"😜","tags":["eye","face","tongue","joke","wink","winking face with tongue"]},{"emoji":"🤪","tags":["eye","goofy","small","large","zany face","silly"]},{"emoji":"😝","tags":["eye","face","squinting face with tongue","horrible","taste","tongue"]},{"emoji":"🤑","tags":["face","money","mouth","money-mouth face"]},{"emoji":"🤗","tags":["face","hug","hugging"]},{"emoji":"🤭","tags":["face with hand over mouth","whoops","shush","shh"]},{"emoji":"🤫","tags":["quiet","shush","shh","shushing face"]},{"emoji":"🤔","tags":["face","thinking"]},{"emoji":"🤐","tags":["face","mouth","zipper-mouth face","zipper","shh"]},{"emoji":"🤨","tags":["distrust","face with raised eyebrow","unsure","skeptic"]},{"emoji":"😐","tags":["deadpan","face","neutral","meh"]},{"emoji":"😑","tags":["expressionless","face","meh","inexpressive","unexpressive"]},{"emoji":"😶","tags":["face","face without mouth","quiet","mouth","silent"]},{"emoji":"😶‍🌫️","tags":["absentminded","face in clouds","head in clouds","face in the fog"]},{"emoji":"😏","tags":["face","smirk","smirking face"]},{"emoji":"😒","tags":["face","unamused","unhappy"]},{"emoji":"🙄","tags":["eyeroll","eyes","face with rolling eyes","face","rolling"]},{"emoji":"😬","tags":["face","grimace","grimacing face"]},{"emoji":"😮‍💨","tags":["exhale","face exhaling","groan","gasp","relief","whisper","whistle"]},{"emoji":"🤥","tags":["face","lie","pinocchio","lying face"]},{"emoji":"😌","tags":["face","relieved"]},{"emoji":"😔","tags":["dejected","face","pensive"]},{"emoji":"😪","tags":["face","sleep","snore","sleepy face"]},{"emoji":"🤤","tags":["drooling","face"]},{"emoji":"😴","tags":["face","sleep","zzz","sleeping face","tired"]},{"emoji":"😷","tags":["cold","doctor","face with medical mask","face","mask","sick"]},{"emoji":"🤒","tags":["face","face with thermometer","sick","ill","thermometer"]},{"emoji":"🤕","tags":["bandage","face","hurt","face with head-bandage","injury"]},{"emoji":"🤢","tags":["face","nauseated","sick","vomit","throw up"]},{"emoji":"🤮","tags":["face vomiting","puke","vomit","sick","throw up"]},{"emoji":"🤧","tags":["face","gesundheit","sneezing face","sneeze","sick"]},{"emoji":"🥵","tags":["feverish","heat stroke","hot face","hot","red-faced","sweating"]},{"emoji":"🥶","tags":["blue-faced","cold","freezing","cold face","frostbite","icicles"]},{"emoji":"🥴","tags":["dizzy","intoxicated","uneven eyes","tipsy","wavy mouth","woozy face","drunk"]},{"emoji":"😵","tags":["dead","face","knocked-out face","knocked out"]},{"emoji":"😵‍💫","tags":["dizzy","face with spiral eyes","spiral","hypnotized","trouble","whoa"]},{"emoji":"🤯","tags":["exploding head","mind blown","shocked"]},{"emoji":"🤠","tags":["cowboy","cowgirl","hat","face"]},{"emoji":"🥳","tags":["celebration","hat","party","horn","partying face"]},{"emoji":"🥸","tags":["disguise","disguised face","glasses","face","incognito","nose"]},{"emoji":"😎","tags":["bright","cool","smiling face with sunglasses","face","sun","sunglasses"]},{"emoji":"🤓","tags":["face","geek","glasses","nerd","smart"]},{"emoji":"🧐","tags":["face with monocle","stuffy"]},{"emoji":"😕","tags":["confused","face","meh"]},{"emoji":"😟","tags":["face","worried","sad"]},{"emoji":"🙁","tags":["face","frown","sad","slightly frowning face"]},{"emoji":"☹️","tags":[]},{"emoji":"😮","tags":["face","face with open mouth","open","mouth","sympathy","wow"]},{"emoji":"😯","tags":["face","hushed","surprised","stunned"]},{"emoji":"😲","tags":["astonished","face","totally","shocked","wow"]},{"emoji":"😳","tags":["dazed","face","flushed"]},{"emoji":"🥺","tags":["begging","mercy","puppy eyes","pleading face","cute"]},{"emoji":"😦","tags":["face","frown","mouth","frowning face with open mouth","open"]},{"emoji":"😧","tags":["anguished","face"]},{"emoji":"😨","tags":["face","fear","scared","fearful"]},{"emoji":"😰","tags":["anxious face with sweat","blue","face","cold","rushed","sweat"]},{"emoji":"😥","tags":["disappointed","face","sad but relieved face","relieved","whew"]},{"emoji":"😢","tags":["cry","crying face","sad","face","tear"]},{"emoji":"😭","tags":["cry","face","sad","loudly crying face","sob","tear"]},{"emoji":"😱","tags":["face","face screaming in fear","munch","fear","scared","scream"]},{"emoji":"😖","tags":["confounded","face"]},{"emoji":"😣","tags":["face","persevere","persevering face"]},{"emoji":"😞","tags":["disappointed","face"]},{"emoji":"😓","tags":["cold","downcast face with sweat","sweat","face"]},{"emoji":"😩","tags":["face","tired","despair","weary"]},{"emoji":"😫","tags":["face","tired","despair"]},{"emoji":"🥱","tags":["bored","tired","yawning face","yawn"]},{"emoji":"😤","tags":["face","face with steam from nose","won","triumph","angry"]},{"emoji":"😡","tags":["angry","face","pouting","mad","rage","red"]},{"emoji":"😠","tags":["anger","angry","mad","face"]},{"emoji":"🤬","tags":["face with symbols on mouth","swearing"]},{"emoji":"😈","tags":["face","fairy tale","horns","fantasy","smile","smiling face with horns"]},{"emoji":"👿","tags":["angry face with horns","demon","face","devil","fantasy","imp"]},{"emoji":"💀","tags":["death","face","monster","fairy tale","skull","dead","funny"]},{"emoji":"☠️","tags":[]},{"emoji":"💩","tags":["dung","face","pile of poo","monster","poo","poop"]},{"emoji":"🤡","tags":["clown","face","silly"]},{"emoji":"👹","tags":["creature","face","fantasy","fairy tale","monster","ogre","devil","demon"]},{"emoji":"👺","tags":["creature","face","fantasy","fairy tale","goblin","monster","devil","demon"]},{"emoji":"👻","tags":["creature","face","fantasy","fairy tale","ghost","monster","boo","spooky"]},{"emoji":"👽","tags":["alien","creature","face","extraterrestrial","fantasy","ufo"]},{"emoji":"👾","tags":["alien","creature","face","extraterrestrial","monster","ufo"]},{"emoji":"🤖","tags":["face","monster","robot"]},{"emoji":"😺","tags":["cat","face","mouth","grinning","open","smile"]},{"emoji":"😸","tags":["cat","eye","grin","face","grinning cat with smiling eyes","smile"]},{"emoji":"😹","tags":["cat","cat with tears of joy","joy","face","tear"]},{"emoji":"😻","tags":["cat","eye","heart eyes","face","love","smile","smiling cat with heart-eyes"]},{"emoji":"😼","tags":["cat","cat with wry smile","ironic","face","smile","wry"]},{"emoji":"😽","tags":["cat","eye","kiss","face","kissing cat"]},{"emoji":"🙀","tags":["cat","face","surprised","oh","weary"]},{"emoji":"😿","tags":["cat","cry","face","crying cat","sad","tear"]},{"emoji":"😾","tags":["cat","face","pouting"]},{"emoji":"🙈","tags":["evil","face","monkey","forbidden","see","see-no-evil monkey"]},{"emoji":"🙉","tags":["evil","face","hear","forbidden","hear-no-evil monkey","monkey"]},{"emoji":"🙊","tags":["evil","face","monkey","forbidden","speak","speak-no-evil monkey"]},{"emoji":"💋","tags":["kiss","kiss mark","lips"]},{"emoji":"💌","tags":["heart letter","letter","mail","love"]},{"emoji":"💘","tags":["arrow","cupid","heart with arrow"]},{"emoji":"💝","tags":["heart with ribbon","ribbon","valentine"]},{"emoji":"💖","tags":["excited","sparkle","sparkling heart"]},{"emoji":"💗","tags":["excited","growing heart","nervous","growing","pulse"]},{"emoji":"💓","tags":["beating","beating heart","pulsating","heartbeat"]},{"emoji":"💞","tags":["revolving","revolving hearts"]},{"emoji":"💕","tags":["love","two hearts"]},{"emoji":"💟","tags":["heart decoration"]},{"emoji":"❣️","tags":["heart exclamation","heart drop","exclamation"]},{"emoji":"💔","tags":["break","broken heart","heart break"]},{"emoji":"❤️‍🔥","tags":["burn","burning heart","heart on fire","love","lust","sacred heart"]},{"emoji":"❤️‍🩹","tags":["healthier","mending heart","heart mending","mending","recovering","recuperating","well","improving"]},{"emoji":"❤️","tags":[]},{"emoji":"🧡","tags":["orange","orange heart","heart orange"]},{"emoji":"💛","tags":["yellow","yellow heart","heart yellow"]},{"emoji":"💚","tags":["green","green heart","heart green"]},{"emoji":"💙","tags":["blue","blue heart","heart blue"]},{"emoji":"💜","tags":["purple","purple heart","heart purple"]},{"emoji":"🤎","tags":["brown","brownheart","heart brown"]},{"emoji":"🖤","tags":["black","black heart","heart black","wicked","evil"]},{"emoji":"🤍","tags":["white","white heart","heart white"]},{"emoji":"💯","tags":["100","full","hundred points","hundred","score"]},{"emoji":"💢","tags":["anger symbol","angry","mad","comic"]},{"emoji":"💥","tags":["boom","collision","comic"]},{"emoji":"💫","tags":["comic","dizzy","star"]},{"emoji":"💦","tags":["comic","splashing","sweat droplets","sweat"]},{"emoji":"💨","tags":["comic","dash","running","dashing away"]},{"emoji":"🕳️","tags":["hole"]},{"emoji":"💣","tags":["bomb","comic"]},{"emoji":"💬","tags":["balloon","bubble","dialog","comic","speech","typing"]},{"emoji":"🗨️","tags":[]},{"emoji":"🗯️","tags":["angry","balloon","mad","bubble","right anger bubble","danger"]},{"emoji":"💭","tags":["balloon","bubble","thought","comic"]},{"emoji":"💤","tags":["comic","sleep","zzz"]},{"emoji":"👋","tags":["hand","wave","waving","hi","hey","hello","bye","goodbye"]},{"emoji":"🤚","tags":["backhand","raised","raised back of hand"]},{"emoji":"🖐️","tags":["finger","hand","splayed","hand with fingers splayed"]},{"emoji":"✋","tags":["hand","high 5","raised hand","high five","hifive"]},{"emoji":"🖖","tags":["finger","hand","vulcan","spock","vulcan salute"]},{"emoji":"👌","tags":["hand","OK"]},{"emoji":"🤌","tags":["fingers","hand gesture","pinched","interrogation","sarcastic"]},{"emoji":"🤏","tags":["pinching hand","small amount","little"]},{"emoji":"✌️","tags":["hand","v","victory"]},{"emoji":"🤞","tags":["cross","crossed fingers","hand","finger","luck"]},{"emoji":"🤟","tags":["hand","ILY","love-you gesture"]},{"emoji":"🤘","tags":["finger","hand","rock-on","horns","sign of the horns","metal"]},{"emoji":"🤙","tags":["call","call me hand","hand","shaka sign","right on","thanks"]},{"emoji":"👈","tags":["backhand","backhand index pointing left","hand","finger","index","point"]},{"emoji":"👉","tags":["backhand","backhand index pointing right","hand","finger","index","point"]},{"emoji":"👆","tags":["backhand","backhand index pointing up","hand","finger","point","up"]},{"emoji":"🖕","tags":["finger","hand","middle finger"]},{"emoji":"👇","tags":["backhand","backhand index pointing down","finger","down","hand","point"]},{"emoji":"☝️","tags":["finger","hand","index pointing up","index","point","up"]},{"emoji":"👍","tags":["+1","hand","thumbs up","thumb","up"]},{"emoji":"👎","tags":["-1","down","thumb","hand","thumbs down"]},{"emoji":"✊","tags":["clenched","fist","punch","hand","raised fist"]},{"emoji":"👊","tags":["clenched","fist","oncoming fist","hand","punch"]},{"emoji":"🤛","tags":["fist","left-facing fist","bump","leftwards"]},{"emoji":"🤜","tags":["fist","right-facing fist","bump","rightwards"]},{"emoji":"👏","tags":["clap","clapping hands","hand"]},{"emoji":"🙌","tags":["celebration","gesture","hooray","hand","raised","raising hands"]},{"emoji":"👐","tags":["hand","open","open hands"]},{"emoji":"🤲","tags":["palms up together","prayer"]},{"emoji":"🤝","tags":["agreement","hand","meeting","handshake","shake"]},{"emoji":"🙏","tags":["ask","folded hands","high 5","hand","high five","please","pray","thanks"]},{"emoji":"✍️","tags":["hand","write","writing hand"]},{"emoji":"💅","tags":["care","cosmetics","nail","manicure","polish"]},{"emoji":"🤳","tags":["camera","phone","selfie"]},{"emoji":"💪","tags":["biceps","comic","flexed biceps","flex","muscle","strong"]},{"emoji":"🦾","tags":["accessibility","mechanical arm","metal","prosthetic","strong"]},{"emoji":"🦿","tags":["accessibility","mechanical leg","metal","prosthetic"]},{"emoji":"🦵","tags":["kick","leg","limb"]},{"emoji":"🦶","tags":["foot","kick","stomp"]},{"emoji":"👂","tags":["body","ear"]},{"emoji":"🦻","tags":["accessibility","ear with hearing aid","hard of hearing"]},{"emoji":"👃","tags":["body","nose"]},{"emoji":"🧠","tags":["brain","intelligent"]},{"emoji":"🫀","tags":["anatomical","cardiology","organ","heart","pulse"]},{"emoji":"🫁","tags":["breath","exhalation","lungs","inhalation","organ","respiration"]},{"emoji":"🦷","tags":["dentist","tooth"]},{"emoji":"🦴","tags":["bone","skeleton"]},{"emoji":"👀","tags":["eye","eyes","look","stare"]},{"emoji":"👁️","tags":["body","eye","stare"]},{"emoji":"👅","tags":["body","tongue"]},{"emoji":"👄","tags":["lips","mouth"]},{"emoji":"👶","tags":["baby","young"]},{"emoji":"🧒","tags":["child","gender-neutral","young","unspecified gender"]},{"emoji":"👦","tags":["boy","young"]},{"emoji":"👧","tags":["girl","Virgo","zodiac","young"]},{"emoji":"🧑","tags":["adult","gender-neutral","unspecified gender","person"]},{"emoji":"👱","tags":["blond","blond-haired person","person: blond hair","hair"]},{"emoji":"👨","tags":["adult","man","male"]},{"emoji":"🧔","tags":["beard","person","person: beard"]},{"emoji":"🧔‍♂️","tags":["beard","man","male","man: beard"]},{"emoji":"👱‍♂️","tags":["blond","blond-haired man","man","hair","man: blond hair","male"]},{"emoji":"👩","tags":["adult","woman","female"]},{"emoji":"🧔‍♀️","tags":["beard","woman","female","woman: beard"]},{"emoji":"👱‍♀️","tags":["blond-haired woman","blonde","woman","hair","woman: blond hair","female"]},{"emoji":"🧓","tags":["adult","gender-neutral","older person","old","unspecified gender"]},{"emoji":"👴","tags":["adult","man","male","old"]},{"emoji":"👵","tags":["adult","old","female","woman"]},{"emoji":"🙍","tags":["frown","gesture","male","person frowning"]},{"emoji":"🙍‍♂️","tags":["frowning","gesture","male","man"]},{"emoji":"🙍‍♀️","tags":["frowning","gesture","female","woman"]},{"emoji":"🙎","tags":["gesture","person pouting","pouting"]},{"emoji":"🙎‍♂️","tags":["gesture","man","male","pouting"]},{"emoji":"🙎‍♀️","tags":["gesture","pouting","female","woman"]},{"emoji":"🙅","tags":["forbidden","gesture","person gesturing NO","hand","prohibited","X","no"]},{"emoji":"🙅‍♂️","tags":["forbidden","gesture","man","hand","man gesturing NO","prohibited","X","no"]},{"emoji":"🙅‍♀️","tags":["forbidden","gesture","prohibited","hand","woman","woman gesturing NO","X","no"]},{"emoji":"🙆","tags":["gesture","hand","person gesturing OK","OK"]},{"emoji":"🙆‍♂️","tags":["gesture","hand","man gesturing OK","man","OK","male"]},{"emoji":"🙆‍♀️","tags":["gesture","hand","woman","OK","woman gesturing OK","female"]},{"emoji":"💁","tags":["hand","help","person tipping hand","information","sassy","tipping"]},{"emoji":"💁‍♂️","tags":["man","man tipping hand","tipping hand","sassy","male"]},{"emoji":"💁‍♀️","tags":["sassy","tipping hand","woman tipping hand","woman","female"]},{"emoji":"🙋","tags":["gesture","hand","person raising hand","raised","hi","hey","hello"]},{"emoji":"🙋‍♂️","tags":["gesture","man","raising hand","man raising hand","male","hi","hey","hello"]},{"emoji":"🙋‍♀️","tags":["gesture","raising hand","woman raising hand","woman","female","hi","hey","hello"]},{"emoji":"🧏","tags":["accessibility","deaf","ear","deaf person","hear"]},{"emoji":"🧏‍♂️","tags":["deaf","man","male","ear","hear"]},{"emoji":"🧏‍♀️","tags":["deaf","woman","female","ear","hear"]},{"emoji":"🙇","tags":["apology","bow","person bowing","gesture","sorry"]},{"emoji":"🙇‍♂️","tags":["apology","bowing","gesture","favor","man","sorry","male"]},{"emoji":"🙇‍♀️","tags":["apology","bowing","gesture","favor","sorry","woman","female"]},{"emoji":"🤦","tags":["disbelief","exasperation","palm","face","person facepalming"]},{"emoji":"🤦‍♂️","tags":["disbelief","exasperation","man","facepalm","man facepalming","male"]},{"emoji":"🤦‍♀️","tags":["disbelief","exasperation","woman","facepalm","woman facepalming","female"]},{"emoji":"🤷","tags":["doubt","ignorance","person shrugging","indifference","shrug"]},{"emoji":"🤷‍♂️","tags":["doubt","ignorance","man","indifference","man shrugging","shrug","male","idk","don't know"]},{"emoji":"🤷‍♀️","tags":["doubt","ignorance","shrug","indifference","woman","woman shrugging","female","idk","don't know"]},{"emoji":"🧑‍⚕️","tags":["doctor","health worker","nurse","healthcare","therapist"]},{"emoji":"👨‍⚕️","tags":["doctor","healthcare","man health worker","man","nurse","therapist","male"]},{"emoji":"👩‍⚕️","tags":["doctor","healthcare","therapist","nurse","woman","woman health worker","female"]},{"emoji":"🧑‍🎓","tags":["graduate","student"]},{"emoji":"👨‍🎓","tags":["graduate","man","male","student"]},{"emoji":"👩‍🎓","tags":["graduate","student","female","woman"]},{"emoji":"🧑‍🏫","tags":["instructor","professor","teacher"]},{"emoji":"👨‍🏫","tags":["instructor","man","teacher","professor","male"]},{"emoji":"👩‍🏫","tags":["instructor","professor","woman","teacher","female"]},{"emoji":"🧑‍⚖️","tags":["judge","justice","scales","law","court"]},{"emoji":"👨‍⚖️","tags":["judge","justice","scales","man","male","law","court"]},{"emoji":"👩‍⚖️","tags":["judge","justice","woman","scales","female","law","court"]},{"emoji":"🧑‍🌾","tags":["farmer","gardener","rancher"]},{"emoji":"👨‍🌾","tags":["farmer","gardener","rancher","man","male"]},{"emoji":"👩‍🌾","tags":["farmer","gardener","woman","rancher","female"]},{"emoji":"🧑‍🍳","tags":["chef","cook"]},{"emoji":"👨‍🍳","tags":["chef","cook","man","male"]},{"emoji":"👩‍🍳","tags":["chef","cook","woman","female"]},{"emoji":"🧑‍🔧","tags":["electrician","mechanic","tradesperson","plumber"]},{"emoji":"👨‍🔧","tags":["electrician","man","plumber","mechanic","tradesperson","male"]},{"emoji":"👩‍🔧","tags":["electrician","mechanic","tradesperson","plumber","woman","female"]},{"emoji":"🧑‍🏭","tags":["assembly","factory","worker","industrial"]},{"emoji":"👨‍🏭","tags":["assembly","factory","man","industrial","worker","male"]},{"emoji":"👩‍🏭","tags":["assembly","factory","woman","industrial","worker","female"]},{"emoji":"🧑‍💼","tags":["architect","business","office worker","manager","white-collar"]},{"emoji":"👨‍💼","tags":["architect","business","man office worker","man","manager","white-collar","male"]},{"emoji":"👩‍💼","tags":["architect","business","white-collar","manager","woman","woman office worker","female"]},{"emoji":"🧑‍🔬","tags":["biologist","chemist","physicist","engineer","scientist"]},{"emoji":"👨‍🔬","tags":["biologist","chemist","man","engineer","physicist","scientist","male"]},{"emoji":"👩‍🔬","tags":["biologist","chemist","physicist","engineer","scientist","woman","female"]},{"emoji":"🧑‍💻","tags":["coder","developer","software","inventor","technologist"]},{"emoji":"👨‍💻","tags":["coder","developer","man","inventor","software","technologist","male"]},{"emoji":"👩‍💻","tags":["coder","developer","software","inventor","technologist","woman","female"]},{"emoji":"🧑‍🎤","tags":["actor","entertainer","singer","rock","star"]},{"emoji":"👨‍🎤","tags":["actor","entertainer","rock","man","singer","star","male"]},{"emoji":"👩‍🎤","tags":["actor","entertainer","singer","rock","star","woman","female"]},{"emoji":"🧑‍🎨","tags":["artist","palette"]},{"emoji":"👨‍🎨","tags":["artist","man","male","palette"]},{"emoji":"👩‍🎨","tags":["artist","palette","female","woman"]},{"emoji":"🧑‍✈️","tags":["pilot"]},{"emoji":"👨‍✈️","tags":["pilot","male","man"]},{"emoji":"👩‍✈️","tags":["pilot","female","woman"]},{"emoji":"🧑‍🚀","tags":["astronaut","rocket"]},{"emoji":"👨‍🚀","tags":["astronaut","man","male","rocket"]},{"emoji":"👩‍🚀","tags":["astronaut","rocket","female","woman"]},{"emoji":"🧑‍🚒","tags":["firefighter","firetruck"]},{"emoji":"👨‍🚒","tags":["firefighter","firetruck","male","man"]},{"emoji":"👩‍🚒","tags":["firefighter","firetruck","female","woman"]},{"emoji":"👮","tags":["cop","officer","police"]},{"emoji":"👮‍♂️","tags":["cop","man","police","officer","male"]},{"emoji":"👮‍♀️","tags":["cop","officer","woman","police","female"]},{"emoji":"🕵️","tags":["detective","sleuth","spy"]},{"emoji":"💂","tags":["guard"]},{"emoji":"💂‍♂️","tags":["guard","man","male"]},{"emoji":"💂‍♀️","tags":["guard","woman","female"]},{"emoji":"🥷","tags":["fighter","hidden","stealth","ninja"]},{"emoji":"👷","tags":["construction","hat","worker"]},{"emoji":"👷‍♂️","tags":["construction","man","male","worker"]},{"emoji":"👷‍♀️","tags":["construction","woman","female","worker"]},{"emoji":"🤴","tags":["prince","king","royal"]},{"emoji":"👸","tags":["fairy tale","fantasy","princess","queen","royal"]},{"emoji":"👳","tags":["person wearing turban","turban"]},{"emoji":"👳‍♂️","tags":["man","man wearing turban","male","turban"]},{"emoji":"👳‍♀️","tags":["turban","woman","female","woman wearing turban"]},{"emoji":"👲","tags":["cap","gua pi mao","person","hat","person with skullcap","skullcap"]},{"emoji":"🧕","tags":["headscarf","hijab","tichel","mantilla","woman with headscarf"]},{"emoji":"🤵","tags":["groom","person","tuxedo","person in tuxedo","wedding"]},{"emoji":"🤵‍♂️","tags":["man","man in tuxedo","male","tuxedo","groom","wedding"]},{"emoji":"🤵‍♀️","tags":["tuxedo","woman","female","woman in tuxedo","groom","wedding"]},{"emoji":"👰","tags":["bride","person","veil","person with veil","wedding"]},{"emoji":"👰‍♂️","tags":["man","man with veil","male","veil","bride"]},{"emoji":"👰‍♀️","tags":["veil","woman","female","woman with veil","bride"]},{"emoji":"🤰","tags":["pregnant","woman","female","baby"]},{"emoji":"🤱","tags":["baby","breast","nursing","breast-feeding"]},{"emoji":"👩‍🍼","tags":["baby","feeding","woman","nursing","female"]},{"emoji":"👨‍🍼","tags":["baby","feeding","nursing","man","male"]},{"emoji":"🧑‍🍼","tags":["baby","feeding","person","nursing"]},{"emoji":"👼","tags":["angel","baby","fairy tale","face","fantasy"]},{"emoji":"🎅","tags":["celebration","Christmas","father","claus","santa","Santa Claus","male"]},{"emoji":"🤶","tags":["celebration","Christmas","mother","claus","Mrs.","Mrs. Claus","female"]},{"emoji":"🧑‍🎄","tags":["Claus, christmas","mx claus"]},{"emoji":"🦸","tags":["good","hero","superhero","heroine","superpower"]},{"emoji":"🦸‍♂️","tags":["good","hero","man superhero","man","superpower","male"]},{"emoji":"🦸‍♀️","tags":["good","hero","superpower","heroine","woman","woman superhero","female"]},{"emoji":"🦹","tags":["criminal","evil","supervillain","superpower","villain"]},{"emoji":"🦹‍♂️","tags":["criminal","evil","man supervillain","man","superpower","villain","male"]},{"emoji":"🦹‍♀️","tags":["criminal","evil","villain","superpower","woman","woman supervillain","female"]},{"emoji":"🧙","tags":["mage","sorcerer","witch","sorceress","wizard"]},{"emoji":"🧙‍♂️","tags":["man mage","sorcerer","male","wizard"]},{"emoji":"🧙‍♀️","tags":["sorceress","witch","female","woman mage","wizard"]},{"emoji":"🧚","tags":["fairy","Oberon","Titania","Puck"]},{"emoji":"🧚‍♂️","tags":["man fairy","Oberon","male","Puck","fairy"]},{"emoji":"🧚‍♀️","tags":["Titania","woman fairy","female","fairy"]},{"emoji":"🧛","tags":["Dracula","undead","vampire"]},{"emoji":"🧛‍♂️","tags":["Dracula","man vampire","male","undead"]},{"emoji":"🧛‍♀️","tags":["undead","woman vampire","female","Dracula"]},{"emoji":"🧜","tags":["mermaid","merman","merwoman","merperson"]},{"emoji":"🧜‍♂️","tags":["merman","Triton","male"]},{"emoji":"🧜‍♀️","tags":["mermaid","merwoman","female"]},{"emoji":"🧝","tags":["elf","magical"]},{"emoji":"🧝‍♂️","tags":["magical","man elf","male"]},{"emoji":"🧝‍♀️","tags":["magical","woman elf","female"]},{"emoji":"🧞","tags":["djinn","genie"]},{"emoji":"🧞‍♂️","tags":["djinn","man genie","male"]},{"emoji":"🧞‍♀️","tags":["djinn","woman genie","female"]},{"emoji":"🧟","tags":["undead","walking dead","zombie"]},{"emoji":"🧟‍♂️","tags":["man zombie","undead","male","walking dead"]},{"emoji":"🧟‍♀️","tags":["undead","walking dead","female","woman zombie"]},{"emoji":"💆","tags":["face","massage","salon","person getting massage"]},{"emoji":"💆‍♂️","tags":["face","man","massage","man getting massage","male"]},{"emoji":"💆‍♀️","tags":["face","massage","woman getting massage","woman","female"]},{"emoji":"💇","tags":["barber","beauty","parlor","haircut","person getting haircut"]},{"emoji":"💇‍♂️","tags":["haircut","man","male","man getting haircut"]},{"emoji":"💇‍♀️","tags":["haircut","woman","female","woman getting haircut"]},{"emoji":"🚶","tags":["hike","person walking","walking","walk"]},{"emoji":"🚶‍♂️","tags":["hike","man","walk","man walking","male"]},{"emoji":"🚶‍♀️","tags":["hike","walk","woman walking","woman","female"]},{"emoji":"🧍","tags":["person standing","stand","standing"]},{"emoji":"🧍‍♂️","tags":["man","standing","male"]},{"emoji":"🧍‍♀️","tags":["standing","woman","female"]},{"emoji":"🧎","tags":["kneel","kneeling","person kneeling"]},{"emoji":"🧎‍♂️","tags":["kneeling","man","male"]},{"emoji":"🧎‍♀️","tags":["kneeling","woman","female"]},{"emoji":"🧑‍🦯","tags":["accessibility","blind","person with white cane"]},{"emoji":"👨‍🦯","tags":["accessibility","blind","man with white cane","man","male"]},{"emoji":"👩‍🦯","tags":["accessibility","blind","woman with white cane","woman","female"]},{"emoji":"🧑‍🦼","tags":["accessibility","person in motorized wheelchair","wheelchair"]},{"emoji":"👨‍🦼","tags":["accessibility","man","wheelchair","man in motorized wheelchair","male"]},{"emoji":"👩‍🦼","tags":["accessibility","wheelchair","woman in motorized wheelchair","woman","female"]},{"emoji":"🧑‍🦽","tags":["accessibility","person in manual wheelchair","wheelchair"]},{"emoji":"👨‍🦽","tags":["accessibility","man","wheelchair","man in manual wheelchair","male"]},{"emoji":"👩‍🦽","tags":["accessibility","wheelchair","woman in manual wheelchair","woman","female"]},{"emoji":"🏃","tags":["marathon","person running","running"]},{"emoji":"🏃‍♂️","tags":["man","marathon","running","racing","male"]},{"emoji":"🏃‍♀️","tags":["marathon","racing","woman","running","female"]},{"emoji":"💃","tags":["dance","dancing","female","woman"]},{"emoji":"🕺","tags":["dance","dancing","male","man"]},{"emoji":"🕴️","tags":["business","person","suit","person in suit levitating"]},{"emoji":"👯","tags":["bunny ear","dancer","people with bunny ears","partying"]},{"emoji":"👯‍♂️","tags":["bunny ear","dancer","men with bunny ears","men","partying"]},{"emoji":"👯‍♀️","tags":["bunny ear","dancer","women","partying","women with bunny ears"]},{"emoji":"🧖","tags":["person in steamy room","sauna","steam room","spa"]},{"emoji":"🧖‍♂️","tags":["man in steamy room","sauna","male","steam room","spa"]},{"emoji":"🧖‍♀️","tags":["sauna","steam room","female","woman in steamy room","spa"]},{"emoji":"🧗","tags":["climber","person climbing"]},{"emoji":"🧗‍♂️","tags":["climber","man climbing","male"]},{"emoji":"🧗‍♀️","tags":["climber","woman climbing","female"]},{"emoji":"🤺","tags":["fencer","fencing","sword","person fencing"]},{"emoji":"🏇","tags":["horse","jockey","racing","racehorse"]},{"emoji":"⛷️","tags":["ski","skier","snow"]},{"emoji":"🏂","tags":["ski","snow","snowboarder","snowboard"]},{"emoji":"🏌️","tags":["ball","golf","person golfing"]},{"emoji":"🏄","tags":["person surfing","surfing"]},{"emoji":"🏄‍♂️","tags":["man","surfing","male"]},{"emoji":"🏄‍♀️","tags":["surfing","woman","female"]},{"emoji":"🚣","tags":["boat","person rowing boat","rowboat"]},{"emoji":"🚣‍♂️","tags":["boat","man","rowboat","man rowing boat","male"]},{"emoji":"🚣‍♀️","tags":["boat","rowboat","woman rowing boat","woman","female"]},{"emoji":"🏊","tags":["person swimming","swim","swimmer"]},{"emoji":"🏊‍♂️","tags":["man","man swimming","male","swim","swimmer"]},{"emoji":"🏊‍♀️","tags":["swim","woman","female","woman swimming","swimmer"]},{"emoji":"⛹️","tags":["ball","person bouncing ball"]},{"emoji":"🏋️","tags":["lifter","person lifting weights","weight"]},{"emoji":"🚴","tags":["bicycle","biking","person biking","cyclist"]},{"emoji":"🚴‍♂️","tags":["bicycle","biking","man","cyclist","male"]},{"emoji":"🚴‍♀️","tags":["bicycle","biking","woman","cyclist","female"]},{"emoji":"🚵","tags":["bicycle","bicyclist","cyclist","bike","mountain","person mountain biking"]},{"emoji":"🚵‍♂️","tags":["bicycle","bike","man","cyclist","man mountain biking","mountain","male"]},{"emoji":"🚵‍♀️","tags":["bicycle","bike","cyclist","biking","mountain","woman","female"]},{"emoji":"🤸","tags":["cartwheel","gymnastics","person cartwheeling"]},{"emoji":"🤸‍♂️","tags":["cartwheel","gymnastics","man cartwheeling","man","male"]},{"emoji":"🤸‍♀️","tags":["cartwheel","gymnastics","woman cartwheeling","woman","female"]},{"emoji":"🤼","tags":["people wrestling","wrestle","wrestler"]},{"emoji":"🤼‍♂️","tags":["men","men wrestling","wrestle"]},{"emoji":"🤼‍♀️","tags":["women","women wrestling","wrestle"]},{"emoji":"🤽","tags":["person playing water polo","polo","water"]},{"emoji":"🤽‍♂️","tags":["man","man playing water polo","male","water polo"]},{"emoji":"🤽‍♀️","tags":["water polo","woman","female","woman playing water polo"]},{"emoji":"🤾","tags":["ball","handball","person playing handball"]},{"emoji":"🤾‍♂️","tags":["handball","man","male","man playing handball"]},{"emoji":"🤾‍♀️","tags":["handball","woman","female","woman playing handball"]},{"emoji":"🤹","tags":["balance","juggle","person juggling","multitask","skill"]},{"emoji":"🤹‍♂️","tags":["juggling","man","male","multitask"]},{"emoji":"🤹‍♀️","tags":["juggling","multitask","female","woman"]},{"emoji":"🧘","tags":["meditation","person in lotus position","yoga","meditate"]},{"emoji":"🧘‍♂️","tags":["man in lotus position","meditation","male","yoga","meditate"]},{"emoji":"🧘‍♀️","tags":["meditation","woman in lotus position","female","yoga","meditate"]},{"emoji":"🛀","tags":["bath","bathtub","person taking bath","bathing"]},{"emoji":"🛌","tags":["hotel","person in bed","sleep","bed","sleeping"]},{"emoji":"🧑‍🤝‍🧑","tags":["couple","hand","holding hands","hold","people holding hands","person"]},{"emoji":"👭","tags":["couple","hand","women","holding hands","women holding hands","female"]},{"emoji":"👫","tags":["couple","hand","holding hands","hold","man","woman","woman and man holding hands","female","male"]},{"emoji":"👬","tags":["couple","Gemini","man","holding hands","men","men holding hands","twins","zodiac","male"]},{"emoji":"💏","tags":["couple","kiss"]},{"emoji":"💑","tags":["couple","couple with heart","love"]},{"emoji":"👪","tags":["family"]},{"emoji":"🗣️","tags":["face","head","speak","silhouette","speaking","shadow","shout"]},{"emoji":"👤","tags":["bust","bust in silhouette","silhouette","shadow"]},{"emoji":"👥","tags":["bust","busts in silhouette","silhouette","shadow"]},{"emoji":"🫂","tags":["goodbye","hello","people hugging","hug","thanks","shadow"]},{"emoji":"👣","tags":["clothing","footprint","print","footprints"]},{"emoji":"🐵","tags":["face","monkey"]},{"emoji":"🐒","tags":["monkey"]},{"emoji":"🦍","tags":["gorilla"]},{"emoji":"🦧","tags":["ape","orangutan"]},{"emoji":"🐶","tags":["dog","face","pet","puppy"]},{"emoji":"🐕","tags":["dog","pet","puppy"]},{"emoji":"🦮","tags":["accessibility","blind","guide dog","guide","dog","assistance","service"]},{"emoji":"🐕‍🦺","tags":["accessibility","assistance","service","dog"]},{"emoji":"🐩","tags":["dog","poodle"]},{"emoji":"🐺","tags":["face","wolf"]},{"emoji":"🦊","tags":["face","fox"]},{"emoji":"🦝","tags":["curious","raccoon","sly"]},{"emoji":"🐱","tags":["cat","face","pet","kitten","kitty"]},{"emoji":"🐈","tags":["cat","pet","kitten","kitty"]},{"emoji":"🐈‍⬛","tags":["black","cat","unlucky","kitty","kitten"]},{"emoji":"🦁","tags":["face","Leo","zodiac","lion"]},{"emoji":"🐯","tags":["face","tiger"]},{"emoji":"🐅","tags":["tiger"]},{"emoji":"🐆","tags":["leopard","cheetah","jaguar","panther"]},{"emoji":"🐴","tags":["face","horse"]},{"emoji":"🐎","tags":["equestrian","horse","racing","racehorse"]},{"emoji":"🦄","tags":["face","unicorn"]},{"emoji":"🦓","tags":["stripe","zebra"]},{"emoji":"🦌","tags":["deer","elk","moose","antelope","reindeer"]},{"emoji":"🦬","tags":["bison","buffalo","wisent","herd"]},{"emoji":"🐮","tags":["cow","face","moo"]},{"emoji":"🐂","tags":["bull","ox","zodiac","Taurus","cow"]},{"emoji":"🐃","tags":["buffalo","water"]},{"emoji":"🐄","tags":["cow","moo"]},{"emoji":"🐷","tags":["face","pig","piggy"]},{"emoji":"🐖","tags":["pig","sow","piggy"]},{"emoji":"🐗","tags":["boar","pig","piggy"]},{"emoji":"🐽","tags":["face","nose","pig","piggy"]},{"emoji":"🐏","tags":["Aries","male","sheep","ram","zodiac"]},{"emoji":"🐑","tags":["ewe","female","sheep"]},{"emoji":"🐐","tags":["Capricorn","goat","zodiac"]},{"emoji":"🐪","tags":["camel","dromedary","hump","desert"]},{"emoji":"🐫","tags":["bactrian","camel","two-hump camel","hump","desert"]},{"emoji":"🦙","tags":["alpaca","guanaco","vicuña","llama","wool"]},{"emoji":"🦒","tags":["giraffe","spots"]},{"emoji":"🐘","tags":["elephant"]},{"emoji":"🦣","tags":["extinction","large","tusk","mammoth","woolly"]},{"emoji":"🦏","tags":["rhinoceros","rhino"]},{"emoji":"🦛","tags":["hippo","hippopotamus"]},{"emoji":"🐭","tags":["face","mouse"]},{"emoji":"🐁","tags":["mouse"]},{"emoji":"🐀","tags":["rat"]},{"emoji":"🐹","tags":["face","hamster","pet","gerbil","chinchilla","guinea pig"]},{"emoji":"🐰","tags":["bunny","face","rabbit","pet"]},{"emoji":"🐇","tags":["bunny","pet","rabbit"]},{"emoji":"🐿️","tags":["chipmunk","squirrel","nuts","acorn"]},{"emoji":"🦫","tags":["beaver","dam"]},{"emoji":"🦔","tags":["hedgehog","spiny"]},{"emoji":"🦇","tags":["bat","vampire"]},{"emoji":"🐻","tags":["bear","face"]},{"emoji":"🐻‍❄️","tags":["arctic","bear","white","polar bear"]},{"emoji":"🐨","tags":["bear","koala"]},{"emoji":"🐼","tags":["face","panda","bear"]},{"emoji":"🦥","tags":["lazy","sloth","slow"]},{"emoji":"🦦","tags":["fishing","otter","playful"]},{"emoji":"🦨","tags":["skunk","stink"]},{"emoji":"🦘","tags":["Australia","joey","kangaroo","jump","marsupial"]},{"emoji":"🦡","tags":["badger","honey badger","pester"]},{"emoji":"🐾","tags":["feet","paw","print","paw prints"]},{"emoji":"🦃","tags":["bird","turkey"]},{"emoji":"🐔","tags":["bird","chicken","hen"]},{"emoji":"🐓","tags":["bird","rooster","hen","chicken"]},{"emoji":"🐣","tags":["baby","bird","hatching","chick"]},{"emoji":"🐤","tags":["baby","bird","chick"]},{"emoji":"🐥","tags":["baby","bird","front-facing baby chick","chick"]},{"emoji":"🐦","tags":["bird"]},{"emoji":"🐧","tags":["bird","penguin"]},{"emoji":"🕊️","tags":["bird","dove","peace","fly"]},{"emoji":"🦅","tags":["bird","eagle"]},{"emoji":"🦆","tags":["bird","duck"]},{"emoji":"🦢","tags":["bird","cygnet","ugly duckling","swan"]},{"emoji":"🦉","tags":["bird","owl","wise"]},{"emoji":"🦤","tags":["dodo","extinction","Mauritius","large"]},{"emoji":"🪶","tags":["bird","feather","light","flight","plumage"]},{"emoji":"🦩","tags":["flamboyant","flamingo","tropical"]},{"emoji":"🦚","tags":["bird","ostentatious","peahen","peacock","proud"]},{"emoji":"🦜","tags":["bird","parrot","talk","pirate"]},{"emoji":"🐸","tags":["face","frog"]},{"emoji":"🐊","tags":["crocodile"]},{"emoji":"🐢","tags":["terrapin","tortoise","turtle"]},{"emoji":"🦎","tags":["lizard","reptile"]},{"emoji":"🐍","tags":["bearer","Ophiuchus","snake","serpent","zodiac"]},{"emoji":"🐲","tags":["dragon","face","fairy tale"]},{"emoji":"🐉","tags":["dragon","fairy tale"]},{"emoji":"🦕","tags":["brachiosaurus","brontosaurus","sauropod","diplodocus","dinosaur"]},{"emoji":"🦖","tags":["T-Rex","Tyrannosaurus Rex","dinosaur"]},{"emoji":"🐳","tags":["face","spouting","whale"]},{"emoji":"🐋","tags":["whale"]},{"emoji":"🐬","tags":["dolphin","flipper"]},{"emoji":"🦭","tags":["sea lion","seal"]},{"emoji":"🐟","tags":["fish","Pisces","zodiac"]},{"emoji":"🐠","tags":["fish","tropical"]},{"emoji":"🐡","tags":["blowfish","fish"]},{"emoji":"🦈","tags":["fish","shark"]},{"emoji":"🐙","tags":["octopus"]},{"emoji":"🐚","tags":["shell","spiral"]},{"emoji":"🐌","tags":["snail"]},{"emoji":"🦋","tags":["butterfly","insect","pretty"]},{"emoji":"🐛","tags":["bug","insect"]},{"emoji":"🐜","tags":["ant","insect"]},{"emoji":"🐝","tags":["bee","honeybee","insect"]},{"emoji":"🪲","tags":["beetle","bug","insect"]},{"emoji":"🐞","tags":["beetle","insect","ladybird","lady beetle","ladybug"]},{"emoji":"🦗","tags":["cricket","grasshopper"]},{"emoji":"🪳","tags":["cockroach","insect","roach","pest"]},{"emoji":"🕷️","tags":["insect","spider"]},{"emoji":"🕸️","tags":["spider","web"]},{"emoji":"🦂","tags":["scorpio","Scorpio","zodiac","scorpion"]},{"emoji":"🦟","tags":["disease","fever","mosquito","malaria","pest","virus"]},{"emoji":"🪰","tags":["disease","fly","pest","maggot","rotting"]},{"emoji":"🪱","tags":["annelid","earthworm","worm","parasite"]},{"emoji":"🦠","tags":["amoeba","bacteria","virus","microbe"]},{"emoji":"💐","tags":["bouquet","flower"]},{"emoji":"🌸","tags":["blossom","cherry","flower"]},{"emoji":"💮","tags":["flower","white flower"]},{"emoji":"🏵️","tags":["plant","rosette"]},{"emoji":"🌹","tags":["flower","rose"]},{"emoji":"🥀","tags":["flower","wilted"]},{"emoji":"🌺","tags":["flower","hibiscus"]},{"emoji":"🌻","tags":["flower","sun","sunflower"]},{"emoji":"🌼","tags":["blossom","flower"]},{"emoji":"🌷","tags":["flower","tulip"]},{"emoji":"🌱","tags":["seedling","young"]},{"emoji":"🪴","tags":["boring","grow","nurturing","house","plant","potted plant","useless"]},{"emoji":"🌲","tags":["evergreen tree","tree"]},{"emoji":"🌳","tags":["deciduous","shedding","tree"]},{"emoji":"🌴","tags":["palm","tree"]},{"emoji":"🌵","tags":["cactus","plant"]},{"emoji":"🌾","tags":["ear","grain","sheaf of rice","rice"]},{"emoji":"🌿","tags":["herb","leaf"]},{"emoji":"☘️","tags":["clover","shamrock","three-leaf clover","three","leaf"]},{"emoji":"🍀","tags":["4","clover","four-leaf clover","four","leaf"]},{"emoji":"🍁","tags":["falling","leaf","maple"]},{"emoji":"🍂","tags":["fallen leaf","falling","leaf"]},{"emoji":"🍃","tags":["blow","flutter","leaf fluttering in wind","leaf","wind"]},{"emoji":"🍇","tags":["fruit","grape","grapes"]},{"emoji":"🍈","tags":["fruit","melon"]},{"emoji":"🍉","tags":["fruit","watermelon"]},{"emoji":"🍊","tags":["fruit","orange","tangerine"]},{"emoji":"🍋","tags":["citrus","fruit","lemon"]},{"emoji":"🍌","tags":["banana","fruit"]},{"emoji":"🍍","tags":["fruit","pineapple"]},{"emoji":"🥭","tags":["fruit","mango","tropical"]},{"emoji":"🍎","tags":["apple","fruit","red"]},{"emoji":"🍏","tags":["apple","fruit","green"]},{"emoji":"🍐","tags":["fruit","pear"]},{"emoji":"🍑","tags":["fruit","peach"]},{"emoji":"🍒","tags":["berries","cherries","fruit","cherry","red"]},{"emoji":"🍓","tags":["berry","fruit","strawberry"]},{"emoji":"🫐","tags":["berry","bilberry","blueberries","blue","blueberry"]},{"emoji":"🥝","tags":["food","fruit","kiwi"]},{"emoji":"🍅","tags":["fruit","tomato","vegetable"]},{"emoji":"🫒","tags":["food","olive"]},{"emoji":"🥥","tags":["coconut","palm","piña colada"]},{"emoji":"🥑","tags":["avocado","food","fruit"]},{"emoji":"🍆","tags":["aubergine","eggplant","vegetable"]},{"emoji":"🥔","tags":["food","potato","vegetable"]},{"emoji":"🥕","tags":["carrot","food","vegetable"]},{"emoji":"🌽","tags":["corn","ear","maize","ear of corn","maze"]},{"emoji":"🌶️","tags":["hot","pepper"]},{"emoji":"🫑","tags":["bell pepper","capsicum","vegetable","pepper"]},{"emoji":"🥒","tags":["cucumber","food","vegetable","pickle"]},{"emoji":"🥬","tags":["bok choy","cabbage","leafy green","kale","lettuce"]},{"emoji":"🥦","tags":["broccoli","wild cabbage"]},{"emoji":"🧄","tags":["flavoring","garlic"]},{"emoji":"🧅","tags":["flavoring","onion"]},{"emoji":"🍄","tags":["mushroom","toadstool"]},{"emoji":"🥜","tags":["food","nut","peanuts","peanut","vegetable"]},{"emoji":"🌰","tags":["chestnut","plant"]},{"emoji":"🍞","tags":["bread","loaf"]},{"emoji":"🥐","tags":["bread","breakfast","food","croissant","french","roll"]},{"emoji":"🥖","tags":["baguette","bread","french","food"]},{"emoji":"🫓","tags":["arepa","flatbread","naan","lavash","pita"]},{"emoji":"🥨","tags":["pretzel","twisted"]},{"emoji":"🥯","tags":["bagel","bakery","schmear","breakfast"]},{"emoji":"🥞","tags":["breakfast","crêpe","hotcake","food","pancake","pancakes"]},{"emoji":"🧇","tags":["breakfast","indecisive","waffle","iron"]},{"emoji":"🧀","tags":["cheese","cheese wedge"]},{"emoji":"🍖","tags":["bone","meat","meat on bone"]},{"emoji":"🍗","tags":["bone","chicken","leg","drumstick","poultry"]},{"emoji":"🥩","tags":["chop","cut of meat","porkchop","lambchop","steak"]},{"emoji":"🥓","tags":["bacon","breakfast","meat","food"]},{"emoji":"🍔","tags":["burger","hamburger"]},{"emoji":"🍟","tags":["french","fries"]},{"emoji":"🍕","tags":["cheese","pizza","slice"]},{"emoji":"🌭","tags":["frankfurter","hot dog","sausage","hotdog"]},{"emoji":"🥪","tags":["bread","sandwich"]},{"emoji":"🌮","tags":["mexican","taco"]},{"emoji":"🌯","tags":["burrito","mexican","wrap"]},{"emoji":"🫔","tags":["mexican","tamale","wrapped"]},{"emoji":"🥙","tags":["falafel","flatbread","gyro","food","kebab","stuffed","pita"]},{"emoji":"🧆","tags":["chickpea","falafel","meatball"]},{"emoji":"🥚","tags":["breakfast","egg","food"]},{"emoji":"🍳","tags":["breakfast","cooking","frying","egg","pan"]},{"emoji":"🥘","tags":["casserole","food","pan","paella","shallow","shallow pan of food"]},{"emoji":"🍲","tags":["pot","pot of food","stew"]},{"emoji":"🫕","tags":["cheese","chocolate","melted","fondue","pot","Swiss"]},{"emoji":"🥣","tags":["bowl with spoon","breakfast","congee","cereal"]},{"emoji":"🥗","tags":["food","green","salad"]},{"emoji":"🍿","tags":["popcorn"]},{"emoji":"🧈","tags":["butter","dairy"]},{"emoji":"🧂","tags":["condiment","salt","shaker"]},{"emoji":"🥫","tags":["can","canned food"]},{"emoji":"🍱","tags":["bento","box"]},{"emoji":"🍘","tags":["cracker","rice"]},{"emoji":"🍙","tags":["ball","Japanese","rice"]},{"emoji":"🍚","tags":["cooked","rice"]},{"emoji":"🍛","tags":["curry","rice"]},{"emoji":"🍜","tags":["bowl","noodle","steaming","ramen"]},{"emoji":"🍝","tags":["pasta","spaghetti"]},{"emoji":"🍠","tags":["potato","roasted","sweet"]},{"emoji":"🍢","tags":["kebab","oden","skewer","seafood","stick"]},{"emoji":"🍣","tags":["sushi"]},{"emoji":"🍤","tags":["fried","prawn","tempura","shrimp"]},{"emoji":"🍥","tags":["cake","fish","pastry","fish cake with swirl","swirl"]},{"emoji":"🥮","tags":["autumn","festival","yuèbǐng","moon cake"]},{"emoji":"🍡","tags":["dango","dessert","skewer","Japanese","stick","sweet"]},{"emoji":"🥟","tags":["dumpling","empanada","jiaozi","gyōza","pierogi","potsticker"]},{"emoji":"🥠","tags":["fortune cookie","prophecy"]},{"emoji":"🥡","tags":["oyster pail","takeout box"]},{"emoji":"🦀","tags":["Cancer","crab","zodiac"]},{"emoji":"🦞","tags":["bisque","claws","seafood","lobster"]},{"emoji":"🦐","tags":["food","shellfish","small","shrimp"]},{"emoji":"🦑","tags":["food","molusc","squid"]},{"emoji":"🦪","tags":["diving","oyster","pearl"]},{"emoji":"🍦","tags":["cream","dessert","icecream","ice","soft","sweet"]},{"emoji":"🍧","tags":["dessert","ice","sweet","shaved"]},{"emoji":"🍨","tags":["cream","dessert","sweet","ice"]},{"emoji":"🍩","tags":["breakfast","dessert","doughnut","donut","sweet"]},{"emoji":"🍪","tags":["cookie","dessert","chocolate chip","sweet"]},{"emoji":"🎂","tags":["birthday","cake","dessert","celebration","pastry","sweet"]},{"emoji":"🍰","tags":["cake","dessert","shortcake","pastry","slice","sweet"]},{"emoji":"🧁","tags":["bakery","cupcake","sweet"]},{"emoji":"🥧","tags":["filling","pastry","pie"]},{"emoji":"🍫","tags":["bar","chocolate","sweet","dessert"]},{"emoji":"🍬","tags":["candy","dessert","sweet"]},{"emoji":"🍭","tags":["candy","dessert","sweet","lollipop"]},{"emoji":"🍮","tags":["custard","dessert","sweet","pudding"]},{"emoji":"🍯","tags":["honey","honeypot","sweet","pot"]},{"emoji":"🍼","tags":["baby","bottle","milk","drink"]},{"emoji":"🥛","tags":["drink","glass","milk","glass of milk"]},{"emoji":"☕","tags":["beverage","coffee","hot","drink","steaming","tea"]},{"emoji":"🫖","tags":["drink","pot","teapot","tea"]},{"emoji":"🍵","tags":["beverage","cup","tea","drink","teacup","teacup without handle"]},{"emoji":"🍶","tags":["bar","beverage","cup","bottle","drink","sake"]},{"emoji":"🍾","tags":["bar","bottle","cork","bottle with popping cork","drink","popping"]},{"emoji":"🍷","tags":["bar","beverage","glass","drink","wine"]},{"emoji":"🍸","tags":["bar","cocktail","glass","drink"]},{"emoji":"🍹","tags":["bar","drink","tropical"]},{"emoji":"🍺","tags":["bar","beer","mug","drink"]},{"emoji":"🍻","tags":["bar","beer","clinking beer mugs","clink","drink","mug"]},{"emoji":"🥂","tags":["celebrate","clink","drink","clinking glasses","glass"]},{"emoji":"🥃","tags":["glass","liquor","tumbler","shot","whisky"]},{"emoji":"🥤","tags":["cup with straw","juice","soda"]},{"emoji":"🧋","tags":["bubble","milk","tea","pearl"]},{"emoji":"🧃","tags":["beverage","box","straw","juice","sweet"]},{"emoji":"🧉","tags":["drink","mate"]},{"emoji":"🧊","tags":["cold","ice","iceberg","ice cube"]},{"emoji":"🥢","tags":["chopsticks","hashi"]},{"emoji":"🍽️","tags":["cooking","fork","knife","fork and knife with plate","plate"]},{"emoji":"🍴","tags":["cooking","cutlery","fork and knife","fork","knife"]},{"emoji":"🥄","tags":["spoon","tableware"]},{"emoji":"🔪","tags":["cooking","hocho","knife","kitchen knife","tool","weapon"]},{"emoji":"🏺","tags":["amphora","Aquarius","drink","cooking","jug","zodiac"]},{"emoji":"🌍","tags":["Africa","earth","globe","Europe","globe showing Europe-Africa","world"]},{"emoji":"🌎","tags":["Americas","earth","globe showing Americas","globe","world"]},{"emoji":"🌏","tags":["Asia","Australia","globe","earth","globe showing Asia-Australia","world"]},{"emoji":"🌐","tags":["earth","globe","meridians","globe with meridians","world"]},{"emoji":"🗺️","tags":["map","world"]},{"emoji":"🗾","tags":["Japan","map","map of Japan"]},{"emoji":"🧭","tags":["compass","magnetic","orienteering","navigation"]},{"emoji":"🏔️","tags":["cold","mountain","snow-capped mountain","snow"]},{"emoji":"⛰️","tags":["mountain"]},{"emoji":"🌋","tags":["eruption","mountain","volcano"]},{"emoji":"🗻","tags":["fuji","mount fuji","mountain"]},{"emoji":"🏕️","tags":["camping"]},{"emoji":"🏖️","tags":["beach","beach with umbrella","umbrella"]},{"emoji":"🏜️","tags":["desert"]},{"emoji":"🏝️","tags":["desert","island"]},{"emoji":"🏞️","tags":["national park","park"]},{"emoji":"🏟️","tags":["stadium"]},{"emoji":"🏛️","tags":["classical","classical building"]},{"emoji":"🏗️","tags":["building construction","construction"]},{"emoji":"🧱","tags":["brick","bricks","mortar","clay","wall"]},{"emoji":"🪨","tags":["boulder","heavy","solid","rock","stone"]},{"emoji":"🪵","tags":["log","lumber","wood","timber"]},{"emoji":"🛖","tags":["house","hut","yurt","roundhouse"]},{"emoji":"🏘️","tags":["houses"]},{"emoji":"🏚️","tags":["derelict","house"]},{"emoji":"🏠","tags":["home","house"]},{"emoji":"🏡","tags":["garden","home","house with garden","house"]},{"emoji":"🏢","tags":["building","office building"]},{"emoji":"🏣","tags":["Japanese","Japanese post office","post"]},{"emoji":"🏤","tags":["European","post","post office"]},{"emoji":"🏥","tags":["doctor","hospital","medicine"]},{"emoji":"🏦","tags":["bank","building"]},{"emoji":"🏨","tags":["building","hotel"]},{"emoji":"🏩","tags":["hotel","love"]},{"emoji":"🏪","tags":["convenience","store"]},{"emoji":"🏫","tags":["building","school"]},{"emoji":"🏬","tags":["department","store"]},{"emoji":"🏭","tags":["building","factory"]},{"emoji":"🏯","tags":["castle","Japanese"]},{"emoji":"🏰","tags":["castle","European"]},{"emoji":"💒","tags":["chapel","romance","wedding"]},{"emoji":"🗼","tags":["Tokyo","tower"]},{"emoji":"🗽","tags":["liberty","statue","Statue of Liberty"]},{"emoji":"⛪","tags":["Christian","church","religion","cross"]},{"emoji":"🕌","tags":["islam","mosque","religion","Muslim"]},{"emoji":"🛕","tags":["hindu","temple"]},{"emoji":"🕍","tags":["Jew","Jewish","synagogue","religion","temple"]},{"emoji":"⛩️","tags":["religion","shinto","shrine"]},{"emoji":"🕋","tags":["islam","kaaba","religion","Muslim"]},{"emoji":"⛲","tags":["fountain"]},{"emoji":"⛺","tags":["camping","tent"]},{"emoji":"🌁","tags":["fog","foggy"]},{"emoji":"🌃","tags":["night","night with stars","star"]},{"emoji":"🏙️","tags":["city","cityscape"]},{"emoji":"🌄","tags":["morning","mountain","sunrise","sun","sunrise over mountains"]},{"emoji":"🌅","tags":["morning","sun","sunrise"]},{"emoji":"🌆","tags":["city","cityscape at dusk","evening","dusk","landscape","sunset"]},{"emoji":"🌇","tags":["dusk","sun","sunset"]},{"emoji":"🌉","tags":["bridge","bridge at night","night"]},{"emoji":"♨️","tags":["hot springs"]},{"emoji":"🎠","tags":["carousel","horse"]},{"emoji":"🎡","tags":["amusement park","ferris","wheel"]},{"emoji":"🎢","tags":["amusement park","coaster","roller"]},{"emoji":"💈","tags":["barber","haircut","pole"]},{"emoji":"🎪","tags":["circus","tent"]},{"emoji":"🚂","tags":["engine","locomotive","steam","railway","train"]},{"emoji":"🚃","tags":["train car","electric","train","railway","tram","trolleybus"]},{"emoji":"🚄","tags":["high-speed train","railway","speed","shinkansen","train"]},{"emoji":"🚅","tags":["bullet","railway","speed","shinkansen","train"]},{"emoji":"🚆","tags":["railway","train"]},{"emoji":"🚇","tags":["metro","subway"]},{"emoji":"🚈","tags":["light rail","railway"]},{"emoji":"🚉","tags":["railway","station","train"]},{"emoji":"🚊","tags":["tram","trolleybus"]},{"emoji":"🚝","tags":["monorail","vehicle"]},{"emoji":"🚞","tags":["train car","mountain","railway"]},{"emoji":"🚋","tags":["train car","tram","trolleybus"]},{"emoji":"🚌","tags":["bus","vehicle"]},{"emoji":"🚍","tags":["bus","oncoming"]},{"emoji":"🚎","tags":["bus","tram","trolleybus","trolley"]},{"emoji":"🚐","tags":["bus","minibus"]},{"emoji":"🚑","tags":["ambulance","vehicle"]},{"emoji":"🚒","tags":["engine","fire","truck"]},{"emoji":"🚓","tags":["car","patrol","police"]},{"emoji":"🚔","tags":["car","oncoming","police"]},{"emoji":"🚕","tags":["taxi","vehicle"]},{"emoji":"🚖","tags":["oncoming","taxi"]},{"emoji":"🚗","tags":["automobile","car"]},{"emoji":"🚘","tags":["automobile","car","oncoming"]},{"emoji":"🚙","tags":["recreational","sport utility","sport utility vehicle"]},{"emoji":"🛻","tags":["pick-up","pickup","truck"]},{"emoji":"🚚","tags":["delivery","truck"]},{"emoji":"🚛","tags":["articulated lorry","lorry","truck","semi"]},{"emoji":"🚜","tags":["tractor","vehicle"]},{"emoji":"🏎️","tags":["car","racing","race","racecar"]},{"emoji":"🏍️","tags":["motorcycle","racing"]},{"emoji":"🛵","tags":["motor","scooter","moped"]},{"emoji":"🦽","tags":["accessibility","manual wheelchair","wheelchair"]},{"emoji":"🦼","tags":["accessibility","motorized wheelchair","wheelchair"]},{"emoji":"🛺","tags":["auto rickshaw","tuk tuk"]},{"emoji":"🚲","tags":["bicycle","bike"]},{"emoji":"🛴","tags":["kick","scooter"]},{"emoji":"🛹","tags":["board","skateboard"]},{"emoji":"🛼","tags":["roller","skate"]},{"emoji":"🚏","tags":["bus","busstop","stop"]},{"emoji":"🛣️","tags":["highway","motorway","road"]},{"emoji":"🛤️","tags":["railway","railway track","train"]},{"emoji":"🛢️","tags":["drum","oil"]},{"emoji":"⛽","tags":["diesel","fuel","gas","fuelpump","pump","station"]},{"emoji":"🚨","tags":["beacon","police","light","revolving","alarm","alert","emergency","siren"]},{"emoji":"🚥","tags":["horizontal traffic light","light","traffic","signal","stoplight"]},{"emoji":"🚦","tags":["light","signal","vertical traffic light","traffic","stoplight"]},{"emoji":"🛑","tags":["octagonal","sign","stop"]},{"emoji":"🚧","tags":["barrier","construction"]},{"emoji":"⚓","tags":["anchor","ship","tool"]},{"emoji":"⛵","tags":["boat","resort","sea","sailboat","yacht"]},{"emoji":"🛶","tags":["boat","canoe"]},{"emoji":"🚤","tags":["boat","speedboat"]},{"emoji":"🛳️","tags":["passenger","ship"]},{"emoji":"⛴️","tags":["boat","ferry","passenger"]},{"emoji":"🛥️","tags":["boat","motor boat","motorboat"]},{"emoji":"🚢","tags":["boat","passenger","ship"]},{"emoji":"✈️","tags":["aeroplane","airplane","small airplane","plane"]},{"emoji":"🛩️","tags":["aeroplane","airplane","small airplane","plane"]},{"emoji":"🛫","tags":["aeroplane","airplane","departure","check-in","departures","plane"]},{"emoji":"🛬","tags":["aeroplane","airplane","arrivals","airplane arrival","arriving","landing","plane"]},{"emoji":"🪂","tags":["hang-glide","parachute","skydive","parasail"]},{"emoji":"💺","tags":["chair","seat"]},{"emoji":"🚁","tags":["helicopter","vehicle"]},{"emoji":"🚟","tags":["railway","suspension"]},{"emoji":"🚠","tags":["cable","gondola","mountain cableway","mountain"]},{"emoji":"🚡","tags":["aerial","cable","gondola","car","tramway"]},{"emoji":"🛰️","tags":["satellite","space"]},{"emoji":"🚀","tags":["rocket","space","spaceship"]},{"emoji":"🛸","tags":["flying saucer","UFO"]},{"emoji":"🛎️","tags":["bell","bellhop","hotel"]},{"emoji":"🧳","tags":["luggage","packing","travel"]},{"emoji":"⌛","tags":["hourglass done","sand","timer"]},{"emoji":"⏳","tags":["hourglass","hourglass not done","timer","sand"]},{"emoji":"⌚","tags":["clock","watch"]},{"emoji":"⏰","tags":["alarm","clock"]},{"emoji":"⏱️","tags":["clock","stopwatch"]},{"emoji":"⏲️","tags":["clock","timer"]},{"emoji":"🕰️","tags":["clock","mantelpiece clock"]},{"emoji":"🕛","tags":["0","12","clock","12:00","o’clock","twelve"]},{"emoji":"🕧","tags":["12","12:30","thirty","clock","twelve","twelve-thirty"]},{"emoji":"🕐","tags":["0","1","clock","1:00","o’clock","one"]},{"emoji":"🕜","tags":["1","1:30","one","clock","one-thirty","thirty"]},{"emoji":"🕑","tags":["0","2","clock","2:00","o’clock","two"]},{"emoji":"🕝","tags":["2","2:30","thirty","clock","two","two-thirty"]},{"emoji":"🕒","tags":["0","3","clock","3:00","o’clock","three"]},{"emoji":"🕞","tags":["3","3:30","thirty","clock","three","three-thirty"]},{"emoji":"🕓","tags":["0","4","clock","4:00","four","o’clock"]},{"emoji":"🕟","tags":["4","4:30","four","clock","four-thirty","thirty"]},{"emoji":"🕔","tags":["0","5","clock","5:00","five","o’clock"]},{"emoji":"🕠","tags":["5","5:30","five","clock","five-thirty","thirty"]},{"emoji":"🕕","tags":["0","6","clock","6:00","o’clock","six"]},{"emoji":"🕡","tags":["6","6:30","six","clock","six-thirty","thirty"]},{"emoji":"🕖","tags":["0","7","clock","7:00","o’clock","seven"]},{"emoji":"🕢","tags":["7","7:30","seven","clock","seven-thirty","thirty"]},{"emoji":"🕗","tags":["0","8","clock","8:00","eight","o’clock"]},{"emoji":"🕣","tags":["8","8:30","eight","clock","eight-thirty","thirty"]},{"emoji":"🕘","tags":["0","9","clock","9:00","nine","o’clock"]},{"emoji":"🕤","tags":["9","9:30","nine","clock","nine-thirty","thirty"]},{"emoji":"🕙","tags":["0","10","clock","10:00","o’clock","ten"]},{"emoji":"🕥","tags":["10","10:30","ten","clock","ten-thirty","thirty"]},{"emoji":"🕚","tags":["0","11","clock","11:00","eleven","o’clock"]},{"emoji":"🕦","tags":["11","11:30","eleven","clock","eleven-thirty","thirty"]},{"emoji":"🌑","tags":["dark","moon","new moon"]},{"emoji":"🌒","tags":["crescent","moon","waxing"]},{"emoji":"🌓","tags":["first quarter moon","moon","quarter"]},{"emoji":"🌔","tags":["gibbous","moon","waxing"]},{"emoji":"🌕","tags":["full","moon"]},{"emoji":"🌖","tags":["gibbous","moon","waning"]},{"emoji":"🌗","tags":["last quarter moon","moon","quarter"]},{"emoji":"🌘","tags":["crescent","moon","waning"]},{"emoji":"🌙","tags":["crescent","moon"]},{"emoji":"🌚","tags":["face","moon","new moon face"]},{"emoji":"🌛","tags":["face","first quarter moon face","quarter","moon"]},{"emoji":"🌜","tags":["face","last quarter moon face","quarter","moon"]},{"emoji":"🌡️","tags":["thermometer","weather"]},{"emoji":"☀️","tags":["sun","bright"]},{"emoji":"🌝","tags":["bright","face","moon","full"]},{"emoji":"🌞","tags":["bright","face","sun with face","sun"]},{"emoji":"🪐","tags":["ringed planet","saturn","saturnine"]},{"emoji":"⭐","tags":["star"]},{"emoji":"🌟","tags":["glittery","glow","shining","glowing star","sparkle","star"]},{"emoji":"🌠","tags":["falling","shooting","star"]},{"emoji":"🌌","tags":["milky way","space","galaxy"]},{"emoji":"☁️","tags":["cloud"]},{"emoji":"⛅","tags":["cloud","sun","sun behind cloud"]},{"emoji":"⛈️","tags":["cloud","cloud with lightning and rain","thunder","rain"]},{"emoji":"🌤️","tags":["cloud","sun","sun behind small cloud"]},{"emoji":"🌥️","tags":["cloud","sun","sun behind large cloud"]},{"emoji":"🌦️","tags":["cloud","rain","sun behind rain cloud","sun"]},{"emoji":"🌧️","tags":["cloud","cloud with rain","rain"]},{"emoji":"🌨️","tags":["cloud","cloud with snow","snow","cold"]},{"emoji":"🌩️","tags":["cloud","cloud with lightning","lightning"]},{"emoji":"🌪️","tags":["cloud","tornado","whirlwind"]},{"emoji":"🌫️","tags":["cloud","fog"]},{"emoji":"🌬️","tags":["blow","cloud","wind","face"]},{"emoji":"🌀","tags":["cyclone","dizzy","twister","hurricane","typhoon"]},{"emoji":"🌈","tags":["rain","rainbow","lgbt","lgbtq","lgbtqia","pride","gay","lesbian","queer","transgender","trans","intersex","asexual"]},{"emoji":"🌂","tags":["closed umbrella","clothing","umbrella","rain"]},{"emoji":"☂️","tags":["umbrella","rain"]},{"emoji":"☔","tags":["clothing","drop","umbrella","rain","umbrella with rain drops"]},{"emoji":"⛱️","tags":["rain","sun","umbrella on ground","umbrella"]},{"emoji":"⚡","tags":["danger","electric","lightning","high voltage","voltage","zap"]},{"emoji":"❄️","tags":[]},{"emoji":"☃️","tags":["cold","snow","snowman"]},{"emoji":"⛄","tags":["cold","snow","snowman without snow","snowman"]},{"emoji":"☄️","tags":["comet","space"]},{"emoji":"🔥","tags":["fire","flame","tool"]},{"emoji":"💧","tags":["cold","comic","droplet","drop","sweat","water"]},{"emoji":"🌊","tags":["ocean","water","wave"]},{"emoji":"🎃","tags":["celebration","halloween","jack-o-lantern","jack","lantern","pumpkin"]},{"emoji":"🎄","tags":["celebration","Christmas","tree"]},{"emoji":"🎆","tags":["celebration","fireworks"]},{"emoji":"🎇","tags":["celebration","fireworks","sparkler","sparkle"]},{"emoji":"🧨","tags":["dynamite","explosive","fireworks","firecracker"]},{"emoji":"✨","tags":["*","sparkle","star","sparkles"]},{"emoji":"🎈","tags":["balloon","celebration"]},{"emoji":"🎉","tags":["celebration","party","tada","popper","confetti"]},{"emoji":"🎊","tags":["ball","celebration","confetti","party"]},{"emoji":"🎋","tags":["banner","celebration","tanabata tree","Japanese","tree"]},{"emoji":"🎍","tags":["bamboo","celebration","pine","Japanese","pine decoration"]},{"emoji":"🎎","tags":["celebration","doll","Japanese","festival","Japanese dolls"]},{"emoji":"🎏","tags":["carp","celebration","streamer"]},{"emoji":"🎐","tags":["bell","celebration","wind","chime"]},{"emoji":"🎑","tags":["celebration","ceremony","moon viewing ceremony","moon"]},{"emoji":"🧧","tags":["gift","good luck","lai see","hóngbāo","money","red envelope"]},{"emoji":"🎀","tags":["celebration","ribbon","bow"]},{"emoji":"🎁","tags":["box","celebration","present","gift","wrapped"]},{"emoji":"🎗️","tags":["celebration","reminder","ribbon"]},{"emoji":"🎟️","tags":["admission","admission tickets","ticket"]},{"emoji":"🎫","tags":["admission","ticket"]},{"emoji":"🎖️","tags":["celebration","medal","military","award"]},{"emoji":"🏆","tags":["prize","trophy","award","win"]},{"emoji":"🏅","tags":["medal","sports medal","star","win"]},{"emoji":"🥇","tags":["1st place medal","first","medal","gold","1","award","prize","win"]},{"emoji":"🥈","tags":["2nd place medal","medal","silver","second","2","award","prize","win"]},{"emoji":"🥉","tags":["3rd place medal","bronze","third","medal","3","award","prize","win"]},{"emoji":"⚽","tags":["ball","football","soccer"]},{"emoji":"⚾","tags":["ball","baseball"]},{"emoji":"🥎","tags":["ball","glove","underarm","softball"]},{"emoji":"🏀","tags":["ball","basketball","hoop"]},{"emoji":"🏐","tags":["ball","game","volleyball"]},{"emoji":"🏈","tags":["american","ball","football"]},{"emoji":"🏉","tags":["ball","football","rugby"]},{"emoji":"🎾","tags":["ball","racquet","tennis"]},{"emoji":"🥏","tags":["flying disc","ultimate"]},{"emoji":"🎳","tags":["ball","bowling","game"]},{"emoji":"🏏","tags":["ball","bat","game","cricket game"]},{"emoji":"🏑","tags":["ball","field","hockey","game","stick"]},{"emoji":"🏒","tags":["game","hockey","puck","ice","stick"]},{"emoji":"🥍","tags":["ball","goal","stick","lacrosse"]},{"emoji":"🏓","tags":["ball","bat","paddle","game","ping pong","table tennis"]},{"emoji":"🏸","tags":["badminton","birdie","racquet","game","shuttlecock"]},{"emoji":"🥊","tags":["boxing","glove"]},{"emoji":"🥋","tags":["judo","karate","martial arts uniform","martial arts","taekwondo","uniform"]},{"emoji":"🥅","tags":["goal","net"]},{"emoji":"⛳","tags":["flag in hole","golf","hole"]},{"emoji":"⛸️","tags":["ice","skate"]},{"emoji":"🎣","tags":["fish","fishing pole","pole"]},{"emoji":"🤿","tags":["diving","diving mask","snorkeling","scuba"]},{"emoji":"🎽","tags":["athletics","running","shirt","sash"]},{"emoji":"🎿","tags":["ski","skis","snow"]},{"emoji":"🛷","tags":["sled","sledge","sleigh"]},{"emoji":"🥌","tags":["curling stone","game","rock"]},{"emoji":"🎯","tags":["bullseye","dart","game","direct hit","hit","target"]},{"emoji":"🪀","tags":["fluctuate","toy","yo-yo"]},{"emoji":"🪁","tags":["fly","kite","soar"]},{"emoji":"🎱","tags":["8","ball","eight","billiard","game","pool 8 ball"]},{"emoji":"🔮","tags":["ball","crystal","fantasy","fairy tale","fortune","tool"]},{"emoji":"🪄","tags":["magic","magic wand","wizard","witch"]},{"emoji":"🧿","tags":["bead","charm","nazar","evil-eye","nazar amulet","talisman"]},{"emoji":"🎮","tags":["controller","game","video game"]},{"emoji":"🕹️","tags":["game","joystick","video game"]},{"emoji":"🎰","tags":["game","slot","slot machine","gambling","casino"]},{"emoji":"🎲","tags":["dice","die","game"]},{"emoji":"🧩","tags":["clue","interlocking","piece","jigsaw","puzzle"]},{"emoji":"🧸","tags":["plaything","plush","teddy bear","stuffed","toy"]},{"emoji":"🪅","tags":["celebration","party","piñata"]},{"emoji":"🪆","tags":["doll","nesting","russia","nesting dolls","matryoshka"]},{"emoji":"♠️","tags":["spade suit","card suit"]},{"emoji":"♥️","tags":[]},{"emoji":"♦️","tags":["diamond suit","card suit"]},{"emoji":"♣️","tags":["club suit","card suit"]},{"emoji":"♟️","tags":[]},{"emoji":"🃏","tags":["card","game","wildcard","joker"]},{"emoji":"🀄","tags":["game","mahjong","red","mahjong red dragon"]},{"emoji":"🎴","tags":["card","flower","game","flower playing cards","Japanese","playing"]},{"emoji":"🎭","tags":["art","mask","performing arts","performing","theater","theatre"]},{"emoji":"🖼️","tags":["art","frame","museum","framed picture","painting","picture"]},{"emoji":"🎨","tags":["art","artist palette","painting","museum","palette"]},{"emoji":"🧵","tags":["needle","sewing","string","spool","thread"]},{"emoji":"🪡","tags":["embroidery","needle","stitches","sewing","sutures","tailoring"]},{"emoji":"🧶","tags":["ball","crochet","yarn","knit"]},{"emoji":"🪢","tags":["knot","rope","tie","tangled","twine","twist"]},{"emoji":"👓","tags":["clothing","eye","eyewear","eyeglasses","glasses"]},{"emoji":"🕶️","tags":["dark","eye","glasses","eyewear","sunglasses"]},{"emoji":"🥽","tags":["eye protection","goggles","welding","swimming"]},{"emoji":"🥼","tags":["doctor","experiment","scientist","lab coat"]},{"emoji":"🦺","tags":["emergency","safety","vest"]},{"emoji":"👔","tags":["clothing","necktie","tie"]},{"emoji":"👕","tags":["clothing","shirt","tshirt","t-shirt"]},{"emoji":"👖","tags":["clothing","jeans","trousers","pants"]},{"emoji":"🧣","tags":["neck","scarf"]},{"emoji":"🧤","tags":["gloves","hand","mittens"]},{"emoji":"🧥","tags":["coat","jacket"]},{"emoji":"🧦","tags":["socks","stocking"]},{"emoji":"👗","tags":["clothing","dress"]},{"emoji":"👘","tags":["clothing","kimono"]},{"emoji":"🥻","tags":["clothing","dress","sari"]},{"emoji":"🩱","tags":["bathing suit","one-piece swimsuit"]},{"emoji":"🩲","tags":["bathing suit","briefs","swimsuit","one-piece","underwear"]},{"emoji":"🩳","tags":["bathing suit","pants","underwear","shorts"]},{"emoji":"👙","tags":["bikini","clothing","swim"]},{"emoji":"👚","tags":["clothing","woman","woman’s clothes"]},{"emoji":"👛","tags":["clothing","coin","purse"]},{"emoji":"👜","tags":["bag","clothing","purse","handbag"]},{"emoji":"👝","tags":["bag","clothing","pouch","clutch bag"]},{"emoji":"🛍️","tags":["bag","hotel","shopping bags","shopping"]},{"emoji":"🎒","tags":["backpack","bag","satchel","rucksack","school"]},{"emoji":"🩴","tags":["beach sandals","sandals","thong sandals","thong sandal","thongs","zōri"]},{"emoji":"👞","tags":["clothing","man","shoe","man’s shoe"]},{"emoji":"👟","tags":["athletic","clothing","shoe","running shoe","sneaker"]},{"emoji":"🥾","tags":["backpacking","boot","hiking","camping"]},{"emoji":"🥿","tags":["ballet flat","flat shoe","slipper","slip-on"]},{"emoji":"👠","tags":["clothing","heel","shoe","high-heeled shoe","woman"]},{"emoji":"👡","tags":["clothing","sandal","woman","shoe","woman’s sandal"]},{"emoji":"🩰","tags":["ballet","ballet shoes","dance"]},{"emoji":"👢","tags":["boot","clothing","woman","shoe","woman’s boot"]},{"emoji":"👑","tags":["clothing","crown","queen","king"]},{"emoji":"👒","tags":["clothing","hat","woman’s hat","woman"]},{"emoji":"🎩","tags":["clothing","hat","tophat","top"]},{"emoji":"🎓","tags":["cap","celebration","graduation","clothing","hat"]},{"emoji":"🧢","tags":["baseball cap","billed cap"]},{"emoji":"🪖","tags":["army","helmet","soldier","military","warrior"]},{"emoji":"⛑️","tags":["aid","cross","hat","face","helmet","rescue worker’s helmet"]},{"emoji":"📿","tags":["beads","clothing","prayer","necklace","religion"]},{"emoji":"💄","tags":["cosmetics","lipstick","makeup"]},{"emoji":"💍","tags":["diamond","ring"]},{"emoji":"💎","tags":["diamond","gem","jewel","gem stone"]},{"emoji":"🔇","tags":["mute","muted speaker","silent","quiet","speaker","volume"]},{"emoji":"🔈","tags":["soft","speaker low volume"]},{"emoji":"🔉","tags":["medium","speaker medium volume"]},{"emoji":"🔊","tags":["loud","speaker high volume"]},{"emoji":"📢","tags":["loud","loudspeaker","public address"]},{"emoji":"📣","tags":["cheering","megaphone"]},{"emoji":"📯","tags":["horn","post","postal"]},{"emoji":"🔔","tags":["bell","ring"]},{"emoji":"🔕","tags":["bell","bell with slash","mute","forbidden","quiet","silent"]},{"emoji":"🎼","tags":["music","musical score","score"]},{"emoji":"🎵","tags":["music","musical note","note"]},{"emoji":"🎶","tags":["music","musical notes","notes","note"]},{"emoji":"🎙️","tags":["mic","microphone","studio","music"]},{"emoji":"🎚️","tags":["level","music","slider"]},{"emoji":"🎛️","tags":["control","knobs","music"]},{"emoji":"🎤","tags":["karaoke","mic","microphone"]},{"emoji":"🎧","tags":["earbud","headphone"]},{"emoji":"📻","tags":["radio","video"]},{"emoji":"🎷","tags":["instrument","music","saxophone","sax"]},{"emoji":"🪗","tags":["accordion","concertina","squeeze box"]},{"emoji":"🎸","tags":["guitar","instrument","music"]},{"emoji":"🎹","tags":["instrument","keyboard","musical keyboard","music","piano"]},{"emoji":"🎺","tags":["instrument","music","trumpet"]},{"emoji":"🎻","tags":["instrument","music","violin"]},{"emoji":"🪕","tags":["banjo","music","stringed"]},{"emoji":"🥁","tags":["drum","drumsticks","music"]},{"emoji":"🪘","tags":["beat","conga","long drum","drum","rhythm"]},{"emoji":"📱","tags":["cell","mobile","telephone","phone","smartphone"]},{"emoji":"📲","tags":["arrow","cell","mobile phone with arrow","mobile","phone","receive","smartphone"]},{"emoji":"☎️","tags":[]},{"emoji":"📞","tags":["phone","receiver","telephone"]},{"emoji":"📟","tags":["pager","beeper"]},{"emoji":"📠","tags":["fax","fax machine"]},{"emoji":"🔋","tags":["battery"]},{"emoji":"🔌","tags":["electric","electricity","plug"]},{"emoji":"💻","tags":["computer","laptop","personal","pc"]},{"emoji":"🖥️","tags":["computer","desktop","monitor","screen"]},{"emoji":"🖨️","tags":["computer","printer"]},{"emoji":"⌨️","tags":["keyboard","computer keyboard"]},{"emoji":"🖱️","tags":["computer","computer mouse"]},{"emoji":"🖲️","tags":["computer","trackball"]},{"emoji":"💽","tags":["computer","disk","optical","minidisk"]},{"emoji":"💾","tags":["computer","disk","save","floppy"]},{"emoji":"💿","tags":["cd","computer","optical","disk"]},{"emoji":"📀","tags":["blu-ray","computer","dvd","disk","optical"]},{"emoji":"🧮","tags":["abacus","calculation"]},{"emoji":"🎥","tags":["camera","cinema","movie"]},{"emoji":"🎞️","tags":["cinema","film","movie","frames"]},{"emoji":"📽️","tags":["cinema","film","projector","movie","video","camera","blue"]},{"emoji":"🎬","tags":["clapper","clapper board","movie"]},{"emoji":"📺","tags":["television","tv","video"]},{"emoji":"📷","tags":["camera","video"]},{"emoji":"📸","tags":["camera","camera with flash","video","flash"]},{"emoji":"📹","tags":["camera","video","camcorder"]},{"emoji":"📼","tags":["tape","vhs","videocassette","video"]},{"emoji":"🔍","tags":["glass","magnifying","search","magnifying glass tilted left","tool"]},{"emoji":"🔎","tags":["glass","magnifying","search","magnifying glass tilted right","tool"]},{"emoji":"🕯️","tags":["candle","light"]},{"emoji":"💡","tags":["bulb","comic","idea","electric","light","lightbulb"]},{"emoji":"🔦","tags":["electric","flashlight","tool","light","torch"]},{"emoji":"🏮","tags":["bar","lantern","red","light","red paper lantern"]},{"emoji":"🪔","tags":["diya","lamp","oil"]},{"emoji":"📔","tags":["book","cover","notebook","decorated","notebook with decorative cover"]},{"emoji":"📕","tags":["book","closed"]},{"emoji":"📖","tags":["book","open"]},{"emoji":"📗","tags":["book","green"]},{"emoji":"📘","tags":["blue","book"]},{"emoji":"📙","tags":["book","orange"]},{"emoji":"📚","tags":["book","books"]},{"emoji":"📓","tags":["notebook"]},{"emoji":"📒","tags":["ledger","notebook"]},{"emoji":"📃","tags":["curl","document","page with curl","page"]},{"emoji":"📜","tags":["paper","scroll"]},{"emoji":"📄","tags":["document","page","page facing up"]},{"emoji":"📰","tags":["news","newspaper","paper"]},{"emoji":"🗞️","tags":["news","newspaper","rolled","paper","rolled-up newspaper"]},{"emoji":"📑","tags":["bookmark","mark","tabs","marker"]},{"emoji":"🔖","tags":["bookmark","mark"]},{"emoji":"🏷️","tags":["label","tag"]},{"emoji":"💰","tags":["bag","dollar","moneybag","money"]},{"emoji":"🪙","tags":["coin","gold","money","metal","silver","treasure"]},{"emoji":"💴","tags":["banknote","bill","money","currency","note","yen"]},{"emoji":"💵","tags":["banknote","bill","dollar","currency","money","note"]},{"emoji":"💶","tags":["banknote","bill","euro","currency","money","note"]},{"emoji":"💷","tags":["banknote","bill","money","currency","note","pound"]},{"emoji":"💸","tags":["banknote","bill","money","fly","money with wings","wings"]},{"emoji":"💳","tags":["card","credit","money"]},{"emoji":"🧾","tags":["accounting","bookkeeping","proof","evidence","receipt"]},{"emoji":"💹","tags":["chart","chart increasing with yen","growth","graph","money","yen"]},{"emoji":"✉️","tags":["envelope","letter","mail"]},{"emoji":"📧","tags":["e-mail","email","mail","letter"]},{"emoji":"📨","tags":["e-mail","email","incoming","envelope","letter","receive"]},{"emoji":"📩","tags":["arrow","e-mail","envelope","email","envelope with arrow","outgoing"]},{"emoji":"📤","tags":["box","letter","outbox","mail","sent","tray"]},{"emoji":"📥","tags":["box","inbox","mail","letter","receive","tray"]},{"emoji":"📦","tags":["box","package","parcel"]},{"emoji":"📫","tags":["closed","closed mailbox with raised flag","mailbox","mail","postbox"]},{"emoji":"📪","tags":["closed","closed mailbox with lowered flag","mail","lowered","mailbox","postbox"]},{"emoji":"📬","tags":["mail","mailbox","open mailbox with raised flag","open","postbox"]},{"emoji":"📭","tags":["lowered","mail","open","mailbox","open mailbox with lowered flag","postbox"]},{"emoji":"📮","tags":["mail","mailbox","postbox"]},{"emoji":"🗳️","tags":["ballot","ballot box with ballot","box"]},{"emoji":"✏️","tags":[]},{"emoji":"✒️","tags":["pen","pen nib","nib"]},{"emoji":"🖋️","tags":["fountain","pen"]},{"emoji":"🖊️","tags":["ballpoint","pen"]},{"emoji":"🖌️","tags":["paintbrush","painting"]},{"emoji":"🖍️","tags":["crayon"]},{"emoji":"📝","tags":["memo","pencil","pencil and paper","paper","write"]},{"emoji":"💼","tags":["briefcase"]},{"emoji":"📁","tags":["file","folder"]},{"emoji":"📂","tags":["file","folder","open"]},{"emoji":"🗂️","tags":["card","dividers","index"]},{"emoji":"📅","tags":["calendar","date"]},{"emoji":"📆","tags":["calendar","tear-off calendar"]},{"emoji":"🗒️","tags":["note","pad","spiral notepad","spiral"]},{"emoji":"🗓️","tags":["calendar","pad","spiral"]},{"emoji":"📇","tags":["card","index","rolodex"]},{"emoji":"📈","tags":["chart","chart increasing","growth","graph","trend","upward"]},{"emoji":"📉","tags":["chart","chart decreasing","graph","down","trend"]},{"emoji":"📊","tags":["bar","chart","graph"]},{"emoji":"📋","tags":["clipboard"]},{"emoji":"📌","tags":["pin","pushpin"]},{"emoji":"📍","tags":["pin","pushpin","round pushpin"]},{"emoji":"📎","tags":["paperclip"]},{"emoji":"🖇️","tags":["link","linked paperclips","paperclip"]},{"emoji":"📏","tags":["ruler","straight edge","straight ruler"]},{"emoji":"📐","tags":["ruler","set","triangular ruler","triangle"]},{"emoji":"✂️","tags":["scissors","cut"]},{"emoji":"🗃️","tags":["box","card","file"]},{"emoji":"🗄️","tags":["cabinet","file","filing"]},{"emoji":"🗑️","tags":["wastebasket","trash","can"]},{"emoji":"🔒","tags":["closed","locked","lock","padlock"]},{"emoji":"🔓","tags":["lock","open","unlocked","unlock","padlock"]},{"emoji":"🔏","tags":["ink","lock","nib","locked with pen","pen","privacy","padlock"]},{"emoji":"🔐","tags":["closed","key","locked with key","lock","secure","padlock"]},{"emoji":"🔑","tags":["key","lock","password"]},{"emoji":"🗝️","tags":["clue","key","old","lock"]},{"emoji":"🔨","tags":["hammer","tool"]},{"emoji":"🪓","tags":["axe","chop","split","hatchet","wood"]},{"emoji":"⛏️","tags":["mining","pick","tool"]},{"emoji":"⚒️","tags":["hammer","pick"]},{"emoji":"🛠️","tags":["hammer","hammer and wrench","tool","spanner","wrench"]},{"emoji":"🗡️","tags":["dagger","knife","weapon"]},{"emoji":"⚔️","tags":["sword","fencing","crossed swords"]},{"emoji":"🔫","tags":["gun","handgun","revolver","pistol","tool","water","weapon"]},{"emoji":"🪃","tags":["australia","boomerang","repercussion","rebound"]},{"emoji":"🏹","tags":["archer","arrow","bow and arrow","bow","Sagittarius","zodiac"]},{"emoji":"🛡️","tags":["shield","weapon"]},{"emoji":"🪚","tags":["carpenter","carpentry saw","saw","lumber","tool"]},{"emoji":"🔧","tags":["spanner","tool","wrench"]},{"emoji":"🪛","tags":["screw","screwdriver","tool"]},{"emoji":"🔩","tags":["bolt","nut","tool","nut and bolt"]},{"emoji":"⚙️","tags":["gear","cog","machine"]},{"emoji":"🗜️","tags":["clamp","compress","vice","tool"]},{"emoji":"⚖️","tags":["scale","balance","law"]},{"emoji":"🦯","tags":["accessibility","blind","white cane"]},{"emoji":"🔗","tags":["link"]},{"emoji":"⛓️","tags":["chain","chains"]},{"emoji":"🪝","tags":["catch","crook","ensnare","curve","hook","selling point"]},{"emoji":"🧰","tags":["chest","mechanic","toolbox","tool"]},{"emoji":"🧲","tags":["attraction","horseshoe","magnetic","magnet"]},{"emoji":"🪜","tags":["climb","ladder","step","rung"]},{"emoji":"⚗️","tags":[]},{"emoji":"🧪","tags":["chemist","chemistry","lab","experiment","science","test tube"]},{"emoji":"🧫","tags":["bacteria","biologist","culture","biology","lab","petri dish"]},{"emoji":"🧬","tags":["biologist","dna","gene","evolution","genetics","life"]},{"emoji":"🔬","tags":["microscope","science","tool"]},{"emoji":"🔭","tags":["science","telescope","tool"]},{"emoji":"📡","tags":["antenna","dish","satellite"]},{"emoji":"💉","tags":["medicine","needle","sick","shot","syringe"]},{"emoji":"🩸","tags":["bleed","blood donation","injury","drop of blood","medicine","menstruation"]},{"emoji":"💊","tags":["doctor","medicine","sick","pill"]},{"emoji":"🩹","tags":["adhesive bandage","bandage"]},{"emoji":"🩺","tags":["doctor","stethoscope","medicine","listen"]},{"emoji":"🚪","tags":["door"]},{"emoji":"🛗","tags":["accessibility","elevator","lift","hoist"]},{"emoji":"🪞","tags":["mirror","reflection","speculum","reflector"]},{"emoji":"🪟","tags":["frame","fresh air","transparent","opening","view","window"]},{"emoji":"🛏️","tags":["bed","hotel","sleep"]},{"emoji":"🛋️","tags":["couch","couch and lamp","lamp","hotel"]},{"emoji":"🪑","tags":["chair","seat","sit"]},{"emoji":"🚽","tags":["toilet"]},{"emoji":"🪠","tags":["force cup","plumber","suction","plunger","toilet"]},{"emoji":"🚿","tags":["shower","water"]},{"emoji":"🛁","tags":["bath","bathtub","water"]},{"emoji":"🪤","tags":["bait","mouse trap","snare","mousetrap","trap"]},{"emoji":"🪒","tags":["razor","sharp","shave"]},{"emoji":"🧴","tags":["lotion","lotion bottle","shampoo","moisturizer","sunscreen"]},{"emoji":"🧷","tags":["diaper","punk rock","safety pin"]},{"emoji":"🧹","tags":["broom","cleaning","witch","sweeping"]},{"emoji":"🧺","tags":["basket","farming","picnic","laundry"]},{"emoji":"🧻","tags":["paper towels","roll of paper","toilet paper"]},{"emoji":"🪣","tags":["bucket","cask","vat","pail"]},{"emoji":"🧼","tags":["bar","bathing","lather","cleaning","soap","soapdish"]},{"emoji":"🪥","tags":["bathroom","brush","dental","clean","hygiene","teeth","toothbrush"]},{"emoji":"🧽","tags":["absorbing","cleaning","sponge","porous"]},{"emoji":"🧯","tags":["extinguish","fire","quench","fire extinguisher"]},{"emoji":"🛒","tags":["cart","shopping","trolley"]},{"emoji":"🚬","tags":["cigarette","smoking","tobacco"]},{"emoji":"⚰️","tags":["coffin","death","dead","casket","funeral"]},{"emoji":"🪦","tags":["cemetery","grave","headstone","graveyard","tombstone","gravestone"]},{"emoji":"⚱️","tags":["funeral","urn","death","dead"]},{"emoji":"🗿","tags":["face","moai","statue","moyai"]},{"emoji":"🪧","tags":["demonstration","picket","protest","placard","sign"]},{"emoji":"🏧","tags":["atm","ATM sign","bank","automated","teller"]},{"emoji":"🚮","tags":["litter","litter bin","litter in bin sign"]},{"emoji":"🚰","tags":["drinking","potable","water"]},{"emoji":"♿","tags":["access","wheelchair symbol"]},{"emoji":"🚹","tags":["lavatory","man","restroom","men’s room","wc"]},{"emoji":"🚺","tags":["lavatory","restroom","woman","wc","women’s room"]},{"emoji":"🚻","tags":["lavatory","restroom","WC"]},{"emoji":"🚼","tags":["baby","baby symbol","changing"]},{"emoji":"🚾","tags":["closet","lavatory","water","restroom","wc"]},{"emoji":"🛂","tags":["control","passport"]},{"emoji":"🛃","tags":["customs"]},{"emoji":"🛄","tags":["baggage","claim"]},{"emoji":"🛅","tags":["baggage","left luggage","luggage","locker"]},{"emoji":"⚠️","tags":["caution","warning","alert","danger"]},{"emoji":"🚸","tags":["child","children crossing","pedestrian","crossing","traffic"]},{"emoji":"⛔","tags":["entry","forbidden","not","no","prohibited","traffic"]},{"emoji":"🚫","tags":["entry","forbidden","not","no","prohibited"]},{"emoji":"🚳","tags":["bicycle","bike","no","forbidden","no bicycles","prohibited"]},{"emoji":"🚭","tags":["forbidden","no","prohibited","not","smoking"]},{"emoji":"🚯","tags":["forbidden","litter","no littering","no","not","prohibited"]},{"emoji":"🚱","tags":["non-drinking","non-potable","water"]},{"emoji":"🚷","tags":["forbidden","no","not","no pedestrians","pedestrian","prohibited"]},{"emoji":"📵","tags":["cell","forbidden","no","mobile","no mobile phones","phone"]},{"emoji":"🔞","tags":["18","age restriction","no one under eighteen","eighteen","prohibited","underage"]},{"emoji":"☢️","tags":["warning","hazard","danger","radioactive"]},{"emoji":"☣️","tags":["warning","hazard","danger","radioactive"]},{"emoji":"⬆️","tags":["arrow","up"]},{"emoji":"↗️","tags":["arrow","up right"]},{"emoji":"➡️","tags":["arrow","right"]},{"emoji":"↘️","tags":["arrow","down right"]},{"emoji":"⬇️","tags":["arrow","down right"]},{"emoji":"↙️","tags":["arrow","down left"]},{"emoji":"⬅️","tags":["arrow","left"]},{"emoji":"↖️","tags":["arrow","up left"]},{"emoji":"↕️","tags":["arrow","up and down","vertical","height"]},{"emoji":"↔️","tags":["arrow","left and right","horizontal","width"]},{"emoji":"↩️","tags":["arrow","return"]},{"emoji":"↪️","tags":["arrow","forward"]},{"emoji":"⤴️","tags":["arrow","up bend"]},{"emoji":"⤵️","tags":["arrow","down bend"]},{"emoji":"🔃","tags":["arrow","clockwise","reload","clockwise vertical arrows"]},{"emoji":"🔄","tags":["anticlockwise","arrow","counterclockwise arrows button","counterclockwise","withershins"]},{"emoji":"🔙","tags":["arrow","back","BACK arrow"]},{"emoji":"🔚","tags":["arrow","end","END arrow"]},{"emoji":"🔛","tags":["arrow","mark","ON! arrow","on"]},{"emoji":"🔜","tags":["arrow","soon","SOON arrow"]},{"emoji":"🔝","tags":["arrow","top","up","TOP arrow"]},{"emoji":"🛐","tags":["place of worship","religion","worship","pray"]},{"emoji":"⚛️","tags":[]},{"emoji":"🕉️","tags":["Hindu","om","religion"]},{"emoji":"✡️","tags":["star","jewish","start of david"]},{"emoji":"☸️","tags":["wheel","dharma"]},{"emoji":"☯️","tags":["yin","yang","yin yang"]},{"emoji":"✝️","tags":["cross","christianity"]},{"emoji":"☦️","tags":["cross","orthodox cross"]},{"emoji":"☪️","tags":["star and crescent","islam"]},{"emoji":"☮️","tags":["peace","peace sign"]},{"emoji":"🕎","tags":["candelabrum","candlestick","religion","menorah"]},{"emoji":"🔯","tags":["dotted six-pointed star","fortune","star"]},{"emoji":"♈","tags":["Aries","ram","zodiac"]},{"emoji":"♉","tags":["bull","ox","zodiac","Taurus"]},{"emoji":"♊","tags":["Gemini","twins","zodiac"]},{"emoji":"♋","tags":["Cancer","crab","zodiac"]},{"emoji":"♌","tags":["Leo","lion","zodiac"]},{"emoji":"♍","tags":["Virgo","zodiac"]},{"emoji":"♎","tags":["balance","justice","scales","Libra","zodiac"]},{"emoji":"♏","tags":["Scorpio","scorpion","zodiac","scorpius"]},{"emoji":"♐","tags":["archer","Sagittarius","zodiac"]},{"emoji":"♑","tags":["Capricorn","goat","zodiac"]},{"emoji":"♒","tags":["Aquarius","bearer","zodiac","water"]},{"emoji":"♓","tags":["fish","Pisces","zodiac"]},{"emoji":"⛎","tags":["bearer","Ophiuchus","snake","serpent","zodiac"]},{"emoji":"🔀","tags":["arrow","crossed","shuffle tracks button"]},{"emoji":"🔁","tags":["arrow","clockwise","repeat button","repeat"]},{"emoji":"🔂","tags":["arrow","clockwise","repeat single button","once"]},{"emoji":"▶️","tags":["play","go","play button","right arrow","triangle"]},{"emoji":"⏩","tags":["arrow","double","fast-forward button","fast","forward"]},{"emoji":"⏭️","tags":["arrow","next scene","next track button","next track","triangle"]},{"emoji":"⏯️","tags":["arrow","pause","play or pause button","play","right","triangle"]},{"emoji":"◀️","tags":["left arrow","triangle"]},{"emoji":"⏪","tags":["arrow","double","rewind","fast reverse button"]},{"emoji":"⏮️","tags":["arrow","last track button","previous track","previous scene","triangle"]},{"emoji":"🔼","tags":["arrow","button","upwards button","red"]},{"emoji":"⏫","tags":["arrow","double","fast up button"]},{"emoji":"🔽","tags":["arrow","button","downwards button","down","red"]},{"emoji":"⏬","tags":["arrow","double","fast down button","down"]},{"emoji":"⏸️","tags":["bar","double","pause button","pause","vertical"]},{"emoji":"⏹️","tags":["square","stop","stop button"]},{"emoji":"⏺️","tags":["circle","record","record button"]},{"emoji":"⏏️","tags":["eject","eject button"]},{"emoji":"🎦","tags":["camera","cinema","movie","film"]},{"emoji":"🔅","tags":["brightness","dim","low","dim button"]},{"emoji":"🔆","tags":["bright","bright button","brightness"]},{"emoji":"📶","tags":["antenna","antenna bars","cell","bar","mobile","phone"]},{"emoji":"📳","tags":["cell","mobile","phone","mode","telephone","vibration"]},{"emoji":"📴","tags":["cell","mobile","phone","off","telephone"]},{"emoji":"⚧️","tags":["transgender","transgender symbol"]},{"emoji":"✖️","tags":["stop","x","cross"]},{"emoji":"➕","tags":["+","math","sign","plus"]},{"emoji":"➖","tags":["-","−","minus","math","sign"]},{"emoji":"➗","tags":["÷","divide","math","division","sign"]},{"emoji":"♾️","tags":["infinity","infinite","endless"]},{"emoji":"‼️","tags":[]},{"emoji":"⁉️","tags":["!?","exclamation","question"]},{"emoji":"❓","tags":["?","mark","question","punctuation","red question mark"]},{"emoji":"❔","tags":["?","mark","punctuation","outlined","question","white question mark"]},{"emoji":"❕","tags":["!","exclamation","outlined","mark","punctuation","white exclamation mark"]},{"emoji":"❗","tags":["!","exclamation","punctuation","mark","red exclamation mark"]},{"emoji":"〰️","tags":["wave","wavey","wavey dash"]},{"emoji":"💱","tags":["currency","exchange","money"]},{"emoji":"💲","tags":["money","dollars","cash","usd","rich"]},{"emoji":"♻️","tags":[]},{"emoji":"⚜️","tags":["fleur","fleur-de-lis"]},{"emoji":"🔱","tags":["anchor","emblem","tool","ship","trident"]},{"emoji":"📛","tags":["badge","name"]},{"emoji":"🔰","tags":["beginner","chevron","Japanese symbol for beginner","Japanese","leaf"]},{"emoji":"⭕","tags":["circle","hollow red circle","o","large","red","mark"]},{"emoji":"✅","tags":["✓","button","mark","check","yes"]},{"emoji":"☑️","tags":["check","check box","done","todo"]},{"emoji":"✔️","tags":["✓","check","mark","yes"]},{"emoji":"❌","tags":["×","cancel","mark","cross","multiplication","multiply","x","no"]},{"emoji":"❎","tags":["×","cross mark button","square","mark","x","no"]},{"emoji":"➰","tags":["curl","curly loop","loop"]},{"emoji":"➿","tags":["loop","curl","twist","double curly loop"]},{"emoji":"〽️","tags":["part alternation mark"]},{"emoji":"✳️","tags":[]},{"emoji":"✴️","tags":[]},{"emoji":"❇️","tags":["sparkle"]},{"emoji":"©️","tags":["copyright"]},{"emoji":"®️","tags":["registered","reserved"]},{"emoji":"™️","tags":["tm","trademark"]},{"emoji":"🔠","tags":["ABCD","input","letters","latin","uppercase"]},{"emoji":"🔡","tags":["abcd","input","letters","latin","lowercase"]},{"emoji":"🔢","tags":["1234","input","numbers"]},{"emoji":"🔣","tags":["〒♪&%","input","input symbols"]},{"emoji":"🔤","tags":["abc","alphabet","latin","input","letters"]},{"emoji":"🅰️","tags":[]},{"emoji":"🆎","tags":["ab","AB button (blood type)","blood type"]},{"emoji":"🅱️","tags":["b","letter b"]},{"emoji":"🆑","tags":["cl","CL button"]},{"emoji":"🆒","tags":["cool","COOL button"]},{"emoji":"🆓","tags":["free","FREE button"]},{"emoji":"ℹ️","tags":["i","letter i"]},{"emoji":"🆔","tags":["id","ID button","identity"]},{"emoji":"Ⓜ️","tags":["m","m in circle"]},{"emoji":"🆕","tags":["new","NEW button"]},{"emoji":"🆖","tags":["ng","NG button"]},{"emoji":"🅾️","tags":[]},{"emoji":"🆗","tags":["OK","OK button"]},{"emoji":"🅿️","tags":["p","letter p"]},{"emoji":"🆘","tags":["help","sos","SOS button"]},{"emoji":"🆙","tags":["mark","up","UP! button"]},{"emoji":"🆚","tags":["versus","vs","VS button"]},{"emoji":"🈁","tags":["here","Japanese","katakana","Japanese “here” button","ココ"]},{"emoji":"🈂️","tags":[]},{"emoji":"🈷️","tags":[]},{"emoji":"🈶","tags":["not free of charge","ideograph","Japanese “not free of charge” button","Japanese","有"]},{"emoji":"🈯","tags":["reserved","ideograph","Japanese “reserved” button","Japanese","指"]},{"emoji":"🉐","tags":["bargain","ideograph","Japanese “bargain” button","Japanese","得"]},{"emoji":"🈹","tags":["discount","ideograph","Japanese “discount” button","Japanese","割"]},{"emoji":"🈚","tags":["free of charge","ideograph","Japanese “free of charge” button","Japanese","無"]},{"emoji":"🈲","tags":["prohibited","ideograph","Japanese “prohibited” button","Japanese","禁"]},{"emoji":"🉑","tags":["acceptable","ideograph","Japanese “acceptable” button","Japanese","可"]},{"emoji":"🈸","tags":["application","ideograph","Japanese “application” button","Japanese","申"]},{"emoji":"🈴","tags":["passing grade","ideograph","Japanese “passing grade” button","Japanese","合"]},{"emoji":"🈳","tags":["vacancy","ideograph","Japanese “vacancy” button","Japanese","空"]},{"emoji":"㊗️","tags":["congratulations","ideograph","japanese"]},{"emoji":"㊙️","tags":[]},{"emoji":"🈺","tags":["open for business","ideograph","Japanese “open for business” button","Japanese","営"]},{"emoji":"🈵","tags":["no vacancy","ideograph","Japanese “no vacancy” button","Japanese","満"]},{"emoji":"🔴","tags":["circle","geometric","red"]},{"emoji":"🟠","tags":["circle","orange"]},{"emoji":"🟡","tags":["circle","yellow"]},{"emoji":"🟢","tags":["circle","green"]},{"emoji":"🔵","tags":["blue","circle","geometric"]},{"emoji":"🟣","tags":["circle","purple"]},{"emoji":"🟤","tags":["brown","circle"]},{"emoji":"⚫","tags":["black circle","circle","geometric","black"]},{"emoji":"⚪","tags":["circle","geometric","white circle","white"]},{"emoji":"🟥","tags":["red","square"]},{"emoji":"🟧","tags":["orange","square"]},{"emoji":"🟨","tags":["square","yellow"]},{"emoji":"🟩","tags":["green","square"]},{"emoji":"🟦","tags":["blue","square"]},{"emoji":"🟪","tags":["purple","square"]},{"emoji":"🟫","tags":["brown","square"]},{"emoji":"⬛","tags":["black large square","geometric","square","black"]},{"emoji":"⬜","tags":["geometric","square","white large square","white"]},{"emoji":"◼️","tags":[]},{"emoji":"◻️","tags":["geometric","square","white medium square","white"]},{"emoji":"◾","tags":["black medium-small square","geometric","square"]},{"emoji":"◽","tags":["geometric","square","white medium-small square"]},{"emoji":"▪️","tags":[]},{"emoji":"▫️","tags":[]},{"emoji":"🔶","tags":["diamond","geometric","orange","large orange diamond"]},{"emoji":"🔷","tags":["blue","diamond","large blue diamond","geometric"]},{"emoji":"🔸","tags":["diamond","geometric","small orange diamond","orange"]},{"emoji":"🔹","tags":["blue","diamond","small blue diamond","geometric"]},{"emoji":"🔺","tags":["geometric","red","red triangle pointed up"]},{"emoji":"🔻","tags":["down","geometric","red triangle pointed down","red"]},{"emoji":"💠","tags":["comic","diamond","geometric","diamond with a dot","inside"]},{"emoji":"🔘","tags":["button","radio button","circle"]},{"emoji":"🔳","tags":["button","geometric","square","outlined","white square button"]},{"emoji":"🔲","tags":["button","geometric","square","outlined"]},{"emoji":"🏁","tags":["checkered","chequered","racing","chequered flag"]},{"emoji":"🚩","tags":["post","triangular flag"]},{"emoji":"🎌","tags":["celebration","cross","crossed flags","crossed","Japanese"]},{"emoji":"🏴","tags":["black flag","waving"]},{"emoji":"🏳️","tags":["waving","white flag"]},{"emoji":"🏳️‍🌈","tags":["pride","rainbow","rainbow flag","lgbtqia","lgbt","lgbtqa","queer","gay","lesbian","intersex","bisexual","transgender","trans","asexual","questioning"]},{"emoji":"🏴‍☠️","tags":["Jolly Roger","pirate","plunder","pirate flag","treasure"]},{"emoji":"☹️","tags":["face","frown","sad","slightly frowning face"]},{"emoji":"☠️","tags":["death","skull","crossbones","skull and crossbones","bones","dead"]},{"emoji":"❤️","tags":["heart","red heart"]},{"emoji":"♥️","tags":["heart suit","card suit"]},{"emoji":"🗨️","tags":["balloon","bubble","dialog","comic","speech"]},{"emoji":"❄️","tags":["snow","snowflake","cold","ice"]},{"emoji":"☎️","tags":["phone","telephone"]},{"emoji":"✏️","tags":["pencil"]},{"emoji":"⚗️","tags":["alembic","science","chemistry"]},{"emoji":"⚛️","tags":["atom"]},{"emoji":"✳️","tags":["asterisk","eight spoke"]},{"emoji":"✴️","tags":["star","eight pointed"]},{"emoji":"‼️","tags":["!","exclamation","double exclamation"]},{"emoji":"♻️","tags":["recyce","reuse","green"]},{"emoji":"🅰️","tags":["a","letter a"]},{"emoji":"🅾️","tags":["o","letter o"]},{"emoji":"🈂️","tags":["service charger","ideograph","japanese"]},{"emoji":"🈷️","tags":["monthly amount","ideograph","japanese"]},{"emoji":"㊙️","tags":["secret","ideograph","japanese"]},{"emoji":"▪️","tags":["black small square","geometric","square","black"]},{"emoji":"◼️","tags":["black medium square","geometric","square","black"]},{"emoji":"▫️","tags":["geometric","square","white small square","white"]},{"emoji":"#️⃣","tags":["keycap","pound","hash"]},{"emoji":"*️⃣","tags":["keycap","asterisk"]},{"emoji":"0️⃣","tags":["keycap","0","zero"]},{"emoji":"1️⃣","tags":["keycap","1","one"]},{"emoji":"2️⃣","tags":["keycap","2","two"]},{"emoji":"3️⃣","tags":["keycap","3","three"]},{"emoji":"4️⃣","tags":["keycap","4","four"]},{"emoji":"5️⃣","tags":["keycap","5","five"]},{"emoji":"6️⃣","tags":["keycap","6","six"]},{"emoji":"7️⃣","tags":["keycap","7","seven"]},{"emoji":"8️⃣","tags":["keycap","8","eight"]},{"emoji":"9️⃣","tags":["keycap","9","nine"]},{"emoji":"🔟","tags":["keycap","10","ten"]}] \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.kt b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.kt index be90d0eea3..1f9b4734c2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.kt @@ -63,24 +63,20 @@ import org.session.libsession.utilities.Toaster import org.session.libsession.utilities.UsernameUtils import org.session.libsession.utilities.WindowDebouncer import org.session.libsignal.utilities.HTTP.isConnectedToNetwork -import org.session.libsignal.utilities.JsonUtil import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.ThreadUtils.queue import org.signal.aesgcmprovider.AesGcmProvider import org.thoughtcrime.securesms.AppContext.configureKovenant import org.thoughtcrime.securesms.components.TypingStatusSender import org.thoughtcrime.securesms.configs.ConfigUploader -import org.thoughtcrime.securesms.database.EmojiSearchDatabase import org.thoughtcrime.securesms.database.LastSentTimestampCache import org.thoughtcrime.securesms.database.LokiAPIDatabase import org.thoughtcrime.securesms.database.Storage -import org.thoughtcrime.securesms.database.model.EmojiSearchData import org.thoughtcrime.securesms.debugmenu.DebugActivity import org.thoughtcrime.securesms.dependencies.AppComponent import org.thoughtcrime.securesms.dependencies.ConfigFactory import org.thoughtcrime.securesms.dependencies.DatabaseComponent import org.thoughtcrime.securesms.dependencies.DatabaseModule.init -import org.thoughtcrime.securesms.emoji.EmojiSource.Companion.refresh import org.thoughtcrime.securesms.groups.ExpiredGroupManager import org.thoughtcrime.securesms.groups.GroupPollerManager import org.thoughtcrime.securesms.groups.OpenGroupManager.startPolling @@ -108,11 +104,8 @@ import org.thoughtcrime.securesms.webrtc.CallMessageProcessor import org.thoughtcrime.securesms.webrtc.WebRtcCallBridge import org.webrtc.PeerConnectionFactory import org.webrtc.PeerConnectionFactory.InitializationOptions -import java.io.IOException import java.security.Security -import java.util.Arrays import java.util.Timer -import java.util.concurrent.Executors import javax.inject.Inject import kotlin.concurrent.Volatile @@ -183,7 +176,6 @@ class ApplicationContext : Application(), DefaultLifecycleObserver, @Inject lateinit var messageNotifierLazy: Lazy @Inject lateinit var apiDB: LokiAPIDatabase - @Inject lateinit var emojiSearchDb: EmojiSearchDatabase @Inject lateinit var webRtcCallBridge: WebRtcCallBridge @Inject lateinit var legacyClosedGroupPollerV2: LegacyClosedGroupPollerV2 @Inject lateinit var legacyGroupDeprecationManager: LegacyGroupDeprecationManager @@ -305,8 +297,6 @@ class ApplicationContext : Application(), DefaultLifecycleObserver, initializeWebRtc() initializeBlobProvider() resubmitProfilePictureIfNeeded() - loadEmojiSearchIndexIfNeeded() - refresh() val networkConstraint = NetworkConstraint.Factory(this).create() isConnectedToNetwork = { networkConstraint.isMet } @@ -462,29 +452,7 @@ class ApplicationContext : Application(), DefaultLifecycleObserver, private fun resubmitProfilePictureIfNeeded() { resubmitProfilePictureIfNeeded(this) } - - private fun loadEmojiSearchIndexIfNeeded() { - Executors.newSingleThreadExecutor().execute { - if (emojiSearchDb.query("face", 1).isEmpty()) { - try { - assets.open("emoji/emoji_search_index.json").use { inputStream -> - val searchIndex = Arrays.asList( - *JsonUtil.fromJson( - inputStream, - Array::class.java - ) - ) - emojiSearchDb.setSearchIndex(searchIndex) - } - } catch (e: IOException) { - Log.e( - "Loki", - "Failed to load emoji search index" - ) - } - } - } - } // endregion + // endregion companion object { const val PREFERENCES_NAME: String = "SecureSMS-Preferences" diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/AnimatingImageSpan.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/AnimatingImageSpan.java deleted file mode 100644 index d75af0ba5e..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/AnimatingImageSpan.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji; - -import android.graphics.drawable.Drawable; -import android.graphics.drawable.Drawable.Callback; -import android.text.style.ImageSpan; - -public class AnimatingImageSpan extends ImageSpan { - public AnimatingImageSpan(Drawable drawable, Callback callback) { - super(drawable, ALIGN_BOTTOM); - drawable.setCallback(callback); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/CompositeEmojiPageModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/CompositeEmojiPageModel.kt deleted file mode 100644 index 37c30b5974..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/CompositeEmojiPageModel.kt +++ /dev/null @@ -1,39 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji - -import android.net.Uri -import androidx.annotation.AttrRes -import java.util.LinkedList - -class CompositeEmojiPageModel( - @field:AttrRes @param:AttrRes private val iconAttr: Int, - private val models: List -) : EmojiPageModel { - - override fun getKey(): String { - return if (models.isEmpty()) "" else models[0].key - } - - override fun getIconAttr(): Int { return iconAttr } - - override fun getEmoji(): List { - val emojis: MutableList = LinkedList() - for (model in models) { - emojis.addAll(model.emoji) - } - return emojis - } - - override fun getDisplayEmoji(): List { - val emojis: MutableList = LinkedList() - for (model in models) { - emojis.addAll(model.displayEmoji) - } - return emojis - } - - override fun hasSpriteMap(): Boolean { return false } - - override fun getSpriteUri(): Uri? { return null } - - override fun isDynamic(): Boolean { return false } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java deleted file mode 100644 index 757ccc36b6..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; -import android.text.InputFilter; -import android.util.AttributeSet; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.widget.AppCompatEditText; - -import org.session.libsignal.utilities.Log; -import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable; - -import network.loki.messenger.R; - - -public class EmojiEditText extends AppCompatEditText { - private static final String TAG = Log.tag(EmojiEditText.class); - - public EmojiEditText(Context context) { - this(context, null); - } - - public EmojiEditText(Context context, AttributeSet attrs) { - this(context, attrs, R.attr.editTextStyle); - } - - public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - - TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.EmojiTextView, 0, 0); - boolean forceCustom = a.getBoolean(R.styleable.EmojiTextView_emoji_forceCustom, false); - boolean jumboEmoji = a.getBoolean(R.styleable.EmojiTextView_emoji_forceJumbo, false); - a.recycle(); - - if (!isInEditMode() && forceCustom) { - setFilters(appendEmojiFilter(this.getFilters(), jumboEmoji)); - } - } - - public void insertEmoji(String emoji) { - final int start = getSelectionStart(); - final int end = getSelectionEnd(); - - getText().replace(Math.min(start, end), Math.max(start, end), emoji); - setSelection(start + emoji.length()); - } - - @Override - public void invalidateDrawable(@NonNull Drawable drawable) { - if (drawable instanceof EmojiDrawable) invalidate(); - else super.invalidateDrawable(drawable); - } - - private InputFilter[] appendEmojiFilter(@Nullable InputFilter[] originalFilters, boolean jumboEmoji) { - InputFilter[] result; - - if (originalFilters != null) { - result = new InputFilter[originalFilters.length + 1]; - System.arraycopy(originalFilters, 0, result, 1, originalFilters.length); - } else { - result = new InputFilter[1]; - } - - result[0] = new EmojiFilter(this, jumboEmoji); - - return result; - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEventListener.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEventListener.java deleted file mode 100644 index 608aa0c394..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEventListener.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji; - -import android.view.KeyEvent; - -public interface EmojiEventListener { - void onEmojiSelected(String emoji); - - void onKeyEvent(KeyEvent keyEvent); -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiFilter.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiFilter.java deleted file mode 100644 index b60650dbee..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiFilter.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji; - -import android.text.InputFilter; -import android.text.Spannable; -import android.text.Spanned; -import android.text.TextUtils; -import android.widget.TextView; - -public class EmojiFilter implements InputFilter { - private TextView view; - private boolean jumboEmoji; - - public EmojiFilter(TextView view, boolean jumboEmoji) { - this.view = view; - this.jumboEmoji = jumboEmoji; - } - - @Override - public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) - { - char[] v = new char[end - start]; - TextUtils.getChars(source, start, end, v, 0); - - Spannable emojified = EmojiProvider.emojify(new String(v), view, jumboEmoji); - - if (source instanceof Spanned && emojified != null) { - TextUtils.copySpansFrom((Spanned) source, start, end, null, emojified, 0); - } - - return emojified; - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiImageView.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiImageView.java index 5e8338b5c6..efdd28bc13 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiImageView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiImageView.java @@ -34,7 +34,8 @@ public void setImageEmoji(CharSequence emoji) { if (isInEditMode()) { setImageResource(R.drawable.ic_emoji); } else { - Drawable emojiDrawable = EmojiProvider.getEmojiDrawable(getContext(), emoji); + //todo: EMOJI commented out + Drawable emojiDrawable = null;//EmojiProvider.getEmojiDrawable(getContext(), emoji); if (emojiDrawable == null) { // fallback setImageResource(R.drawable.ic_square_x); diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiItemDecoration.kt b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiItemDecoration.kt deleted file mode 100644 index bed28b0b18..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiItemDecoration.kt +++ /dev/null @@ -1,53 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji - -import android.graphics.Canvas -import android.graphics.Rect -import android.graphics.drawable.Drawable -import android.view.View -import androidx.appcompat.widget.AppCompatTextView -import androidx.recyclerview.widget.RecyclerView -import org.thoughtcrime.securesms.components.emoji.EmojiPageViewGridAdapter.EmojiModel -import org.thoughtcrime.securesms.conversation.v2.ViewUtil -import org.thoughtcrime.securesms.util.InsetItemDecoration - -private val EDGE_LENGTH: Int = ViewUtil.dpToPx(6) -private val HORIZONTAL_INSET: Int = ViewUtil.dpToPx(6) -private val EMOJI_VERTICAL_INSET: Int = ViewUtil.dpToPx(5) -private val HEADER_VERTICAL_INSET: Int = ViewUtil.dpToPx(8) - -/** - * Use super class to add insets to the emojis and use the [onDrawOver] to draw the variation - * hint if the emoji has more than one variation. - */ -class EmojiItemDecoration(private val allowVariations: Boolean, private val variationsDrawable: Drawable) : InsetItemDecoration(SetInset()) { - - override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) { - super.onDrawOver(canvas, parent, state) - - val adapter: EmojiPageViewGridAdapter? = parent.adapter as? EmojiPageViewGridAdapter - if (allowVariations && adapter != null) { - for (i in 0 until parent.childCount) { - val child: View = parent.getChildAt(i) - val position: Int = parent.getChildAdapterPosition(child) - if (position >= 0 && position <= adapter.itemCount) { - val model = adapter.currentList[position] - if (model is EmojiModel && model.emoji.hasMultipleVariations()) { - variationsDrawable.setBounds(child.right, child.bottom - EDGE_LENGTH, child.right + EDGE_LENGTH, child.bottom) - variationsDrawable.draw(canvas) - } - } - } - } - } - - private class SetInset : InsetItemDecoration.SetInset() { - override fun setInset(outRect: Rect, view: View, parent: RecyclerView) { - val isHeader = view.javaClass == AppCompatTextView::class.java - - outRect.left = HORIZONTAL_INSET - outRect.right = HORIZONTAL_INSET - outRect.top = if (isHeader) HEADER_VERTICAL_INSET else EMOJI_VERTICAL_INSET - outRect.bottom = if (isHeader) 0 else EMOJI_VERTICAL_INSET - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java deleted file mode 100644 index 4b9abf9810..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java +++ /dev/null @@ -1,209 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -import androidx.annotation.LayoutRes; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.LinearSmoothScroller; -import androidx.recyclerview.widget.RecyclerView; - -import org.thoughtcrime.securesms.components.emoji.EmojiPageViewGridAdapter.EmojiHeader; -import org.thoughtcrime.securesms.components.emoji.EmojiPageViewGridAdapter.EmojiNoResultsModel; -import org.thoughtcrime.securesms.components.emoji.EmojiPageViewGridAdapter.VariationSelectorListener; -import org.thoughtcrime.securesms.conversation.v2.ViewUtil; -import org.thoughtcrime.securesms.util.ContextUtil; -import org.thoughtcrime.securesms.util.DrawableUtil; -import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel; - -import java.util.List; -import java.util.Optional; - -import network.loki.messenger.R; - -public class EmojiPageView extends RecyclerView implements VariationSelectorListener { - private AdapterFactory adapterFactory; - private LinearLayoutManager layoutManager; - private RecyclerView.OnItemTouchListener scrollDisabler; - private VariationSelectorListener variationSelectorListener; - private EmojiVariationSelectorPopup popup; - - public EmojiPageView(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - } - - public EmojiPageView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - public EmojiPageView(@NonNull Context context, - @NonNull EmojiEventListener emojiSelectionListener, - @NonNull VariationSelectorListener variationSelectorListener, - boolean allowVariations) - { - super(context); - initialize(emojiSelectionListener, variationSelectorListener, allowVariations); - } - - public EmojiPageView(@NonNull Context context, - @NonNull EmojiEventListener emojiSelectionListener, - @NonNull VariationSelectorListener variationSelectorListener, - boolean allowVariations, - @NonNull LinearLayoutManager layoutManager, - @LayoutRes int displayEmojiLayoutResId, - @LayoutRes int displayEmoticonLayoutResId) - { - super(context); - initialize(emojiSelectionListener, variationSelectorListener, allowVariations, layoutManager, displayEmojiLayoutResId, displayEmoticonLayoutResId); - } - - public void initialize(@NonNull EmojiEventListener emojiSelectionListener, - @NonNull VariationSelectorListener variationSelectorListener, - boolean allowVariations) - { - initialize(emojiSelectionListener, variationSelectorListener, allowVariations, new GridLayoutManager(getContext(), 8), R.layout.emoji_display_item_grid, R.layout.emoji_text_display_item_grid); - } - - public void initialize(@NonNull EmojiEventListener emojiSelectionListener, - @NonNull VariationSelectorListener variationSelectorListener, - boolean allowVariations, - @NonNull LinearLayoutManager layoutManager, - @LayoutRes int displayEmojiLayoutResId, - @LayoutRes int displayEmoticonLayoutResId) - { - this.variationSelectorListener = variationSelectorListener; - - this.layoutManager = layoutManager; - this.scrollDisabler = new ScrollDisabler(); - this.popup = new EmojiVariationSelectorPopup(getContext(), emojiSelectionListener); - this.adapterFactory = () -> new EmojiPageViewGridAdapter(popup, - emojiSelectionListener, - this, - allowVariations, - displayEmojiLayoutResId, - displayEmoticonLayoutResId); - - if (this.layoutManager instanceof GridLayoutManager) { - GridLayoutManager gridLayout = (GridLayoutManager) this.layoutManager; - gridLayout.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { - @Override - public int getSpanSize(int position) { - if (getAdapter() != null) { - Optional> model = getAdapter().getModel(position); - if (model.isPresent() && (model.get() instanceof EmojiHeader || model.get() instanceof EmojiNoResultsModel)) { - return gridLayout.getSpanCount(); - } - } - return 1; - } - }); - } - - setLayoutManager(layoutManager); - - Drawable drawable = DrawableUtil.tint(ContextUtil.requireDrawable(getContext(), R.drawable.triangle_bottom_right_corner), ContextCompat.getColor(getContext(), R.color.signal_button_secondary_text_disabled)); - addItemDecoration(new EmojiItemDecoration(allowVariations, drawable)); - } - - public void presentForEmojiKeyboard() { - setPadding(getPaddingLeft(), - getPaddingTop(), - getPaddingRight(), - getPaddingBottom() + ViewUtil.dpToPx(56)); - - setClipToPadding(false); - } - - public void onSelected() { - if (getAdapter() != null) { - getAdapter().notifyDataSetChanged(); - } - } - - public void setList(@NonNull List> list, @Nullable Runnable commitCallback) { - EmojiPageViewGridAdapter adapter = adapterFactory.create(); - setAdapter(adapter); - adapter.submitList(list, commitCallback); - } - - @Override - protected void onVisibilityChanged(@NonNull View changedView, int visibility) { - if (visibility != VISIBLE) { - popup.dismiss(); - } - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - if (layoutManager instanceof GridLayoutManager) { - int viewWidth = w - getPaddingStart() - getPaddingEnd(); - int idealWidth = getContext().getResources().getDimensionPixelOffset(R.dimen.emoji_drawer_item_width); - int spanCount = Math.max(viewWidth / idealWidth, 1); - - ((GridLayoutManager) layoutManager).setSpanCount(spanCount); - } - } - - @Override - public void onVariationSelectorStateChanged(boolean open) { - if (open) { - addOnItemTouchListener(scrollDisabler); - } else { - post(() -> removeOnItemTouchListener(scrollDisabler)); - } - - if (variationSelectorListener != null) { - variationSelectorListener.onVariationSelectorStateChanged(open); - } - } - - public void setRecyclerNestedScrollingEnabled(boolean enabled) { - setNestedScrollingEnabled(enabled); - } - - public void smoothScrollToPositionTop(int position) { - int currentPosition = layoutManager.findFirstCompletelyVisibleItemPosition(); - boolean shortTrip = Math.abs(currentPosition - position) < 475; - - if (shortTrip) { - RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(getContext()) { - @Override - protected int getVerticalSnapPreference() { - return LinearSmoothScroller.SNAP_TO_START; - } - }; - smoothScroller.setTargetPosition(position); - layoutManager.startSmoothScroll(smoothScroller); - } else { - layoutManager.scrollToPositionWithOffset(position, 0); - } - } - - public @Nullable EmojiPageViewGridAdapter getAdapter() { - return (EmojiPageViewGridAdapter) super.getAdapter(); - } - - private static class ScrollDisabler implements RecyclerView.OnItemTouchListener { - @Override - public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent motionEvent) { - return true; - } - - @Override - public void onTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent motionEvent) { } - - @Override - public void onRequestDisallowInterceptTouchEvent(boolean b) { } - } - - private interface AdapterFactory { - EmojiPageViewGridAdapter create(); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageViewGridAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageViewGridAdapter.java deleted file mode 100644 index 69b7279ed3..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageViewGridAdapter.java +++ /dev/null @@ -1,240 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji; - -import android.graphics.drawable.Drawable; -import android.view.View; -import android.widget.ImageView; -import android.widget.PopupWindow; -import android.widget.TextView; - -import androidx.annotation.LayoutRes; -import androidx.annotation.NonNull; - -import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory; -import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter; -import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel; -import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder; - -import network.loki.messenger.R; - -public class EmojiPageViewGridAdapter extends MappingAdapter implements PopupWindow.OnDismissListener { - - private final VariationSelectorListener variationSelectorListener; - - public EmojiPageViewGridAdapter(@NonNull EmojiVariationSelectorPopup popup, - @NonNull EmojiEventListener emojiEventListener, - @NonNull VariationSelectorListener variationSelectorListener, - boolean allowVariations, - @LayoutRes int displayEmojiLayoutResId, - @LayoutRes int displayEmoticonLayoutResId) - { - this.variationSelectorListener = variationSelectorListener; - - popup.setOnDismissListener(this); - - registerFactory(EmojiHeader.class, new LayoutFactory<>(EmojiHeaderViewHolder::new, R.layout.emoji_grid_header)); - registerFactory(EmojiModel.class, new LayoutFactory<>(v -> new EmojiViewHolder(v, emojiEventListener, variationSelectorListener, popup, allowVariations), displayEmojiLayoutResId)); - registerFactory(EmojiTextModel.class, new LayoutFactory<>(v -> new EmojiTextViewHolder(v, emojiEventListener), displayEmoticonLayoutResId)); - registerFactory(EmojiNoResultsModel.class, new LayoutFactory<>(MappingViewHolder.SimpleViewHolder::new, R.layout.emoji_grid_no_results)); - } - - @Override - public void onDismiss() { - variationSelectorListener.onVariationSelectorStateChanged(false); - } - - public static class EmojiHeader implements MappingModel, HasKey { - - private final String key; - private final int title; - - public EmojiHeader(@NonNull String key, int title) { - this.key = key; - this.title = title; - } - - @Override - public @NonNull String getKey() { - return key; - } - - @Override - public boolean areItemsTheSame(@NonNull EmojiHeader newItem) { - return title == newItem.title; - } - - @Override - public boolean areContentsTheSame(@NonNull EmojiHeader newItem) { - return areItemsTheSame(newItem); - } - } - - static class EmojiHeaderViewHolder extends MappingViewHolder { - - private final TextView title; - - public EmojiHeaderViewHolder(@NonNull View itemView) { - super(itemView); - title = findViewById(R.id.emoji_grid_header_title); - } - - @Override - public void bind(@NonNull EmojiHeader model) { - title.setText(model.title); - } - } - - public static class EmojiModel implements MappingModel, HasKey { - - private final String key; - private final Emoji emoji; - - public EmojiModel(@NonNull String key, @NonNull Emoji emoji) { - this.key = key; - this.emoji = emoji; - } - - @Override - public @NonNull String getKey() { - return key; - } - - public @NonNull Emoji getEmoji() { - return emoji; - } - - @Override - public boolean areItemsTheSame(@NonNull EmojiModel newItem) { - return newItem.emoji.getValue().equals(emoji.getValue()); - } - - @Override - public boolean areContentsTheSame(@NonNull EmojiModel newItem) { - return areItemsTheSame(newItem); - } - } - - static class EmojiViewHolder extends MappingViewHolder { - - private final EmojiVariationSelectorPopup popup; - private final VariationSelectorListener variationSelectorListener; - private final EmojiEventListener emojiEventListener; - private final boolean allowVariations; - - private final ImageView imageView; - - public EmojiViewHolder(@NonNull View itemView, - @NonNull EmojiEventListener emojiEventListener, - @NonNull VariationSelectorListener variationSelectorListener, - @NonNull EmojiVariationSelectorPopup popup, - boolean allowVariations) - { - super(itemView); - - this.popup = popup; - this.variationSelectorListener = variationSelectorListener; - this.emojiEventListener = emojiEventListener; - this.allowVariations = allowVariations; - - this.imageView = itemView.findViewById(R.id.emoji_image); - } - - @Override - public void bind(@NonNull EmojiModel model) { - final Drawable drawable = EmojiProvider.getEmojiDrawable(imageView.getContext(), model.emoji.getValue()); - - if (drawable != null) { - imageView.setVisibility(View.VISIBLE); - imageView.setImageDrawable(drawable); - } - - itemView.setOnClickListener(v -> { - emojiEventListener.onEmojiSelected(model.emoji.getValue()); - }); - - if (allowVariations && model.emoji.hasMultipleVariations()) { - itemView.setOnLongClickListener(v -> { - popup.dismiss(); - popup.setVariations(model.emoji.getVariations()); - popup.showAsDropDown(itemView, 0, -(2 * itemView.getHeight())); - variationSelectorListener.onVariationSelectorStateChanged(true); - return true; - }); - } else { - itemView.setOnLongClickListener(null); - } - } - } - - public static class EmojiTextModel implements MappingModel, HasKey { - private final String key; - private final Emoji emoji; - - public EmojiTextModel(@NonNull String key, @NonNull Emoji emoji) { - this.key = key; - this.emoji = emoji; - } - - @Override - public @NonNull String getKey() { - return key; - } - - public @NonNull Emoji getEmoji() { - return emoji; - } - - @Override - public boolean areItemsTheSame(@NonNull EmojiTextModel newItem) { - return newItem.emoji.getValue().equals(emoji.getValue()); - } - - @Override - public boolean areContentsTheSame(@NonNull EmojiTextModel newItem) { - return areItemsTheSame(newItem); - } - } - - static class EmojiTextViewHolder extends MappingViewHolder { - - private final EmojiEventListener emojiEventListener; - private final AsciiEmojiView textView; - - public EmojiTextViewHolder(@NonNull View itemView, - @NonNull EmojiEventListener emojiEventListener) - { - super(itemView); - - this.emojiEventListener = emojiEventListener; - this.textView = itemView.findViewById(R.id.emoji_text); - } - - @Override - public void bind(@NonNull EmojiTextModel model) { - textView.setEmoji(model.emoji.getValue()); - - itemView.setOnClickListener(v -> { - emojiEventListener.onEmojiSelected(model.emoji.getValue()); - }); - } - } - - public static class EmojiNoResultsModel implements MappingModel { - @Override - public boolean areItemsTheSame(@NonNull EmojiNoResultsModel newItem) { - return true; - } - - @Override - public boolean areContentsTheSame(@NonNull EmojiNoResultsModel newItem) { - return true; - } - } - - public interface HasKey { - @NonNull String getKey(); - } - - public interface VariationSelectorListener { - void onVariationSelectorStateChanged(boolean open); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java deleted file mode 100644 index e51abe1ca3..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java +++ /dev/null @@ -1,205 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji; - -import static org.session.libsession.utilities.Util.runOnMain; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.text.Spannable; -import android.text.SpannableStringBuilder; -import android.text.TextUtils; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.session.libsession.utilities.FutureTaskListener; -import org.session.libsignal.utilities.Log; -import org.thoughtcrime.securesms.components.emoji.parsing.EmojiDrawInfo; -import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser; -import org.thoughtcrime.securesms.emoji.EmojiPageCache; -import org.thoughtcrime.securesms.emoji.EmojiSource; -import org.thoughtcrime.securesms.util.Util; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicBoolean; - -public class EmojiProvider { - - private static final String TAG = Log.tag(EmojiProvider.class); - private static final Paint PAINT = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG); - - public static @Nullable EmojiParser.CandidateList getCandidates(@Nullable CharSequence text) { - if (text == null) return null; - return new EmojiParser(EmojiSource.getLatest().getEmojiTree()).findCandidates(text); - } - - static @Nullable Spannable emojify(@Nullable CharSequence text, @NonNull TextView tv, boolean jumboEmoji) { - if (tv.isInEditMode()) { - return null; - } else { - return emojify(getCandidates(text), text, tv, jumboEmoji); - } - } - - static @Nullable Spannable emojify(@Nullable EmojiParser.CandidateList matches, - @Nullable CharSequence text, - @NonNull TextView tv, - boolean jumboEmoji) - { - if (matches == null || text == null || tv.isInEditMode()) return null; - SpannableStringBuilder builder = new SpannableStringBuilder(text); - - for (EmojiParser.Candidate candidate : matches) { - Drawable drawable = getEmojiDrawable(tv.getContext(), candidate.getDrawInfo(), tv::requestLayout, jumboEmoji); - - if (drawable != null) { - builder.setSpan(new EmojiSpan(drawable, tv), candidate.getStartIndex(), candidate.getEndIndex(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } - - return builder; - } - - static @Nullable Drawable getEmojiDrawable(@NonNull Context context, @Nullable CharSequence emoji) { - return getEmojiDrawable(context, emoji, false); - } - - static @Nullable Drawable getEmojiDrawable(@NonNull Context context, @Nullable CharSequence emoji, boolean jumboEmoji) { - if (TextUtils.isEmpty(emoji)) { - return null; - } - - EmojiDrawInfo drawInfo = EmojiSource.getLatest().getEmojiTree().getEmoji(emoji, 0, emoji.length()); - return getEmojiDrawable(context, drawInfo, null, jumboEmoji); - } - - /** - * Gets an EmojiDrawable from the Page Cache - * - * @param context Context object used in reading and writing from disk - * @param drawInfo Information about the emoji being displayed - * @param onEmojiLoaded Runnable which will trigger when an emoji is loaded from disk - */ - private static @Nullable Drawable getEmojiDrawable(@NonNull Context context, @Nullable EmojiDrawInfo drawInfo, @Nullable Runnable onEmojiLoaded, boolean jumboEmoji) { - if (drawInfo == null) { - return null; - } - - final int lowMemoryDecodeScale = Util.isLowMemory(context) ? 2 : 1; - final EmojiSource source = EmojiSource.getLatest(); - final EmojiDrawable drawable = new EmojiDrawable(source, drawInfo, lowMemoryDecodeScale); - final AtomicBoolean jumboLoaded = new AtomicBoolean(false); - - EmojiPageCache.LoadResult loadResult = EmojiPageCache.INSTANCE.load(context, drawInfo.getPage(), lowMemoryDecodeScale); - - if (loadResult instanceof EmojiPageCache.LoadResult.Immediate) { - runOnMain(() -> drawable.setBitmap(((EmojiPageCache.LoadResult.Immediate) loadResult).getBitmap())); - } else if (loadResult instanceof EmojiPageCache.LoadResult.Async) { - ((EmojiPageCache.LoadResult.Async) loadResult).getTask().addListener(new FutureTaskListener() { - @Override - public void onSuccess(Bitmap result) { - runOnMain(() -> { - if (!jumboLoaded.get()) { - drawable.setBitmap(result); - if (onEmojiLoaded != null) { - onEmojiLoaded.run(); - } - } - }); - } - - @Override - public void onFailure(ExecutionException exception) { - Log.d(TAG, "Failed to load emoji bitmap resource", exception); - } - }); - } else { - throw new IllegalStateException("Unexpected subclass " + loadResult.getClass()); - } - - return drawable; - } - - static final class EmojiDrawable extends Drawable { - private final float intrinsicWidth; - private final float intrinsicHeight; - private final Rect emojiBounds; - - private Bitmap bmp; - private boolean isSingleBitmap; - - @Override - public int getIntrinsicWidth() { - return (int) intrinsicWidth; - } - - @Override - public int getIntrinsicHeight() { - return (int) intrinsicHeight; - } - - EmojiDrawable(@NonNull EmojiSource source, @NonNull EmojiDrawInfo info, int lowMemoryDecodeScale) { - this.intrinsicWidth = (source.getMetrics().getRawWidth() * source.getDecodeScale()) / lowMemoryDecodeScale; - this.intrinsicHeight = (source.getMetrics().getRawHeight() * source.getDecodeScale()) / lowMemoryDecodeScale; - - final int glyphWidth = (int) (intrinsicWidth); - final int glyphHeight = (int) (intrinsicHeight); - final int index = info.getIndex(); - final int emojiPerRow = source.getMetrics().getPerRow(); - final int xStart = (index % emojiPerRow) * glyphWidth; - final int yStart = (index / emojiPerRow) * glyphHeight; - - this.emojiBounds = new Rect(xStart + 1, - yStart + 1, - xStart + glyphWidth - 1, - yStart + glyphHeight - 1); - } - - @Override - public void draw(@NonNull Canvas canvas) { - if (bmp == null) { - return; - } - - canvas.drawBitmap(bmp, - isSingleBitmap ? null : emojiBounds, - getBounds(), - PAINT); - } - - public void setBitmap(Bitmap bitmap) { - setBitmap(bitmap, false); - } - - public void setSingleBitmap(Bitmap bitmap) { - setBitmap(bitmap, true); - } - - private void setBitmap(Bitmap bitmap, boolean isSingleBitmap) { - this.isSingleBitmap = isSingleBitmap; - if (bmp == null || !bmp.sameAs(bitmap)) { - bmp = bitmap; - invalidateSelf(); - } - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - - @Override - public void setAlpha(int alpha) { } - - @Override - public void setColorFilter(ColorFilter cf) { } - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiSpan.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiSpan.java deleted file mode 100644 index 11714f09ce..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiSpan.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Paint.FontMetricsInt; -import android.graphics.drawable.Drawable; -import android.widget.TextView; - -import androidx.annotation.NonNull; - -import network.loki.messenger.R; - -public class EmojiSpan extends AnimatingImageSpan { - - private final float SHIFT_FACTOR = 1.5f; - - private int size; - private FontMetricsInt fontMetrics; - - public EmojiSpan(@NonNull Drawable drawable, @NonNull TextView tv) { - super(drawable, tv); - fontMetrics = tv.getPaint().getFontMetricsInt(); - size = fontMetrics != null ? Math.abs(fontMetrics.descent) + Math.abs(fontMetrics.ascent) - : tv.getResources().getDimensionPixelSize(R.dimen.conversation_item_body_text_size); - getDrawable().setBounds(0, 0, size, size); - } - - public EmojiSpan(@NonNull Context context, @NonNull Drawable drawable, @NonNull Paint paint) { - super(drawable, null); - fontMetrics = paint.getFontMetricsInt(); - size = fontMetrics != null ? Math.abs(fontMetrics.descent) + Math.abs(fontMetrics.ascent) - : context.getResources().getDimensionPixelSize(R.dimen.conversation_item_body_text_size); - - getDrawable().setBounds(0, 0, size, size); - } - - @Override - public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) { - if (fm != null && this.fontMetrics != null) { - fm.ascent = this.fontMetrics.ascent; - fm.descent = this.fontMetrics.descent; - fm.top = this.fontMetrics.top; - fm.bottom = this.fontMetrics.bottom; - fm.leading = this.fontMetrics.leading; - } else { - this.fontMetrics = paint.getFontMetricsInt(); - this.size = Math.abs(this.fontMetrics.descent) + Math.abs(this.fontMetrics.ascent); - - getDrawable().setBounds(0, 0, size, size); - } - - return size; - } - - @Override - public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { - int height = bottom - top; - int centeringMargin = (height - size) / 2; - int adjustedMargin = (int) (centeringMargin * SHIFT_FACTOR); - int adjustedBottom = bottom - adjustedMargin; - super.draw(canvas, text, start, end, x, top, y, bottom - adjustedMargin, paint); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java index 4ccb16ed5e..288f6fa9eb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java @@ -1,32 +1,35 @@ package org.thoughtcrime.securesms.components.emoji; +import static androidx.emoji2.text.EmojiCompat.LOAD_STATE_SUCCEEDED; + import android.content.Context; -import android.content.res.TypedArray; import android.graphics.drawable.Drawable; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.widget.TextViewCompat; -import androidx.appcompat.widget.AppCompatTextView; +import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.core.widget.TextViewCompat; +import androidx.emoji2.text.EmojiCompat; +import androidx.emoji2.text.EmojiSpan; + import network.loki.messenger.R; -import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable; -import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser; import org.session.libsession.utilities.Util; import org.session.libsignal.utilities.guava.Optional; +import org.thoughtcrime.securesms.util.EmojiUtils; public class EmojiTextView extends AppCompatTextView { private final boolean scaleEmojis; - private static final char ELLIPSIS = '…'; private CharSequence previousText; - private BufferType previousBufferType = BufferType.NORMAL; - private float originalFontSize; - private boolean sizeChangeInProgress; - private int maxLength; + private BufferType previousBufferType = BufferType.NORMAL; + private float originalFontSize; + private boolean sizeChangeInProgress; + private int maxLength; private CharSequence overflowText; private CharSequence previousOverflowText; @@ -34,92 +37,75 @@ public EmojiTextView(Context context) { this(context, null); } - public EmojiTextView(Context context, AttributeSet attrs) { + public EmojiTextView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } - public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr) { + public EmojiTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - scaleEmojis = true; - maxLength = 1000; + maxLength = 1000; originalFontSize = getResources().getDimension(R.dimen.medium_font_size); } - @Override public void setText(@Nullable CharSequence text, BufferType type) { - // No need to do anything special if the text is null or empty + @Override + public void setText(@Nullable CharSequence text, BufferType type) { if (text == null || text.length() == 0) { - previousText = text; + previousText = text; previousOverflowText = overflowText; - previousBufferType = type; + previousBufferType = type; super.setText(text, type); return; } - EmojiParser.CandidateList candidates = EmojiProvider.getCandidates(text); - - if (scaleEmojis && candidates != null && candidates.allEmojis) { - int emojis = candidates.size(); - float scale = 1.0f; - - if (emojis <= 8) scale += 0.25f; - if (emojis <= 6) scale += 0.25f; - if (emojis <= 4) scale += 0.25f; - if (emojis <= 2) scale += 0.25f; - - super.setTextSize(TypedValue.COMPLEX_UNIT_PX, originalFontSize * scale); - } else if (scaleEmojis) { - super.setTextSize(TypedValue.COMPLEX_UNIT_PX, originalFontSize); - } - if (unchanged(text, overflowText, type)) { return; } - previousText = text; + if(scaleEmojis) { + int emojiCount = EmojiUtils.INSTANCE.getOnlyEmojiCount(text); + if(emojiCount > 0){ + float scale = 1.0f; + if (emojiCount <= 8) scale += 0.35f; + if (emojiCount <= 6) scale += 0.35f; + if (emojiCount <= 4) scale += 0.35f; + if (emojiCount <= 2) scale += 0.35f; + if (emojiCount <= 1) scale += 0.35f; + super.setTextSize(TypedValue.COMPLEX_UNIT_PX, originalFontSize * scale); + } else { + super.setTextSize(TypedValue.COMPLEX_UNIT_PX, originalFontSize); + } + } else { + super.setTextSize(TypedValue.COMPLEX_UNIT_PX, originalFontSize); + } + + previousText = text; previousOverflowText = overflowText; - previousBufferType = type; + previousBufferType = type; - if (candidates == null || candidates.size() == 0) { - super.setText(new SpannableStringBuilder(Optional.fromNullable(text).or("")).append(Optional.fromNullable(overflowText).or("")), BufferType.NORMAL); + // Let EmojiCompat (already initialized elsewhere) do its work. + SpannableStringBuilder builder = new SpannableStringBuilder(); + builder.append(text).append(Optional.fromNullable(overflowText).or("")); + super.setText(builder, BufferType.SPANNABLE); - if (getEllipsize() == TextUtils.TruncateAt.END && maxLength > 0) { + // Android fails to ellipsize spannable strings. (https://issuetracker.google.com/issues/36991688) + // We ellipsize them ourselves by manually truncating the appropriate section. + if (getEllipsize() == TextUtils.TruncateAt.END) { + if (maxLength > 0) { ellipsizeAnyTextForMaxLength(); - } - } else { - CharSequence emojified = EmojiProvider.emojify(candidates, text, this, false); - super.setText(new SpannableStringBuilder(emojified).append(Optional.fromNullable(overflowText).or("")), BufferType.SPANNABLE); - - // Android fails to ellipsize spannable strings. (https://issuetracker.google.com/issues/36991688) - // We ellipsize them ourselves by manually truncating the appropriate section. - if (getEllipsize() == TextUtils.TruncateAt.END) { - if (maxLength > 0) { - ellipsizeAnyTextForMaxLength(); - } else { - ellipsizeEmojiTextForMaxLines(); - } + } else { + ellipsizeEmojiTextForMaxLines(); } } } - public void setOverflowText(@Nullable CharSequence overflowText) { - this.overflowText = overflowText; - setText(previousText, BufferType.SPANNABLE); - } - private void ellipsizeAnyTextForMaxLength() { if (maxLength > 0 && getText().length() > maxLength + 1) { SpannableStringBuilder newContent = new SpannableStringBuilder(); - newContent.append(getText().subSequence(0, maxLength)).append(ELLIPSIS).append(Optional.fromNullable(overflowText).or("")); - - EmojiParser.CandidateList newCandidates = EmojiProvider.getCandidates(newContent); - - if (newCandidates == null || newCandidates.size() == 0) { - super.setText(newContent, BufferType.NORMAL); - } else { - CharSequence emojified = EmojiProvider.emojify(newCandidates, newContent, this, false); - super.setText(emojified, BufferType.SPANNABLE); - } + newContent.append(getText().subSequence(0, maxLength)) + .append(ELLIPSIS) + .append(Optional.fromNullable(overflowText).or("")); + super.setText(newContent, BufferType.SPANNABLE); } } @@ -129,27 +115,20 @@ private void ellipsizeEmojiTextForMaxLines() { ellipsizeEmojiTextForMaxLines(); return; } - int maxLines = TextViewCompat.getMaxLines(EmojiTextView.this); if (maxLines <= 0 && maxLength < 0) { return; } - int lineCount = getLineCount(); if (lineCount > maxLines) { int overflowStart = getLayout().getLineStart(maxLines - 1); CharSequence overflow = getText().subSequence(overflowStart, getText().length()); CharSequence ellipsized = TextUtils.ellipsize(overflow, getPaint(), getWidth(), TextUtils.TruncateAt.END); - SpannableStringBuilder newContent = new SpannableStringBuilder(); newContent.append(getText().subSequence(0, overflowStart)) - .append(ellipsized.subSequence(0, ellipsized.length())) - .append(Optional.fromNullable(overflowText).or("")); - - EmojiParser.CandidateList newCandidates = EmojiProvider.getCandidates(newContent); - CharSequence emojified = EmojiProvider.emojify(newCandidates, newContent, this, false); - - super.setText(emojified, BufferType.SPANNABLE); + .append(ellipsized.subSequence(0, ellipsized.length())) + .append(Optional.fromNullable(overflowText).or("")); + super.setText(newContent, BufferType.SPANNABLE); } }); } @@ -159,18 +138,15 @@ private boolean unchanged(CharSequence text, CharSequence overflowText, BufferTy CharSequence finalText = (text == null || text.length() == 0 ? "" : text); CharSequence finalPrevOverflowText = (previousOverflowText == null || previousOverflowText.length() == 0 ? "" : previousOverflowText); CharSequence finalOverflowText = (overflowText == null || overflowText.length() == 0 ? "" : overflowText); - - return Util.equals(finalPrevText, finalText) && - Util.equals(finalPrevOverflowText, finalOverflowText) && - Util.equals(previousBufferType, bufferType) && - !sizeChangeInProgress; + return Util.equals(finalPrevText, finalText) + && Util.equals(finalPrevOverflowText, finalOverflowText) + && Util.equals(previousBufferType, bufferType) + && !sizeChangeInProgress; } - @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); - if (!sizeChangeInProgress) { sizeChangeInProgress = true; setText(previousText, previousBufferType); @@ -180,11 +156,7 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) { @Override public void invalidateDrawable(@NonNull Drawable drawable) { - if (drawable instanceof EmojiDrawable) { - invalidate(); - } else { - super.invalidateDrawable(drawable); - } + super.invalidateDrawable(drawable); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiUtil.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiUtil.java deleted file mode 100644 index 1748f3b22c..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiUtil.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji; - -import androidx.annotation.NonNull; - -import org.thoughtcrime.securesms.emoji.EmojiSource; -import org.thoughtcrime.securesms.emoji.ObsoleteEmoji; - -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Pattern; - -public final class EmojiUtil { - private static final Pattern EMOJI_PATTERN = Pattern.compile("^(?:(?:[\u00a9\u00ae\u203c\u2049\u2122\u2139\u2194-\u2199\u21a9-\u21aa\u231a-\u231b\u2328\u23cf\u23e9-\u23f3\u23f8-\u23fa\u24c2\u25aa-\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614-\u2615\u2618\u261d\u2620\u2622-\u2623\u2626\u262a\u262e-\u262f\u2638-\u263a\u2648-\u2653\u2660\u2663\u2665-\u2666\u2668\u267b\u267f\u2692-\u2694\u2696-\u2697\u2699\u269b-\u269c\u26a0-\u26a1\u26aa-\u26ab\u26b0-\u26b1\u26bd-\u26be\u26c4-\u26c5\u26c8\u26ce-\u26cf\u26d1\u26d3-\u26d4\u26e9-\u26ea\u26f0-\u26f5\u26f7-\u26fa\u26fd\u2702\u2705\u2708-\u270d\u270f\u2712\u2714\u2716\u271d\u2721\u2728\u2733-\u2734\u2744\u2747\u274c\u274e\u2753-\u2755\u2757\u2763-\u2764\u2795-\u2797\u27a1\u27b0\u27bf\u2934-\u2935\u2b05-\u2b07\u2b1b-\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299\ud83c\udc04\ud83c\udccf\ud83c\udd70-\ud83c\udd71\ud83c\udd7e-\ud83c\udd7f\ud83c\udd8e\ud83c\udd91-\ud83c\udd9a\ud83c\ude01-\ud83c\ude02\ud83c\ude1a\ud83c\ude2f\ud83c\ude32-\ud83c\ude3a\ud83c\ude50-\ud83c\ude51\u200d\ud83c\udf00-\ud83d\uddff\ud83d\ude00-\ud83d\ude4f\ud83d\ude80-\ud83d\udeff\ud83e\udd00-\ud83e\uddff\udb40\udc20-\udb40\udc7f]|\u200d[\u2640\u2642]|[\ud83c\udde6-\ud83c\uddff]{2}|.[\u20e0\u20e3\ufe0f]+)+)+$"); - private static final String EMOJI_REGEX = "[^\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\p{Cs}\\s]"; - - private EmojiUtil() {} - - /** - * This will return all ways we know of expressing a singular emoji. This is to aid in search, - * where some platforms may send an emoji we've locally marked as 'obsolete'. - */ - public static @NonNull Set getAllRepresentations(@NonNull String emoji) { - Set out = new HashSet<>(); - - out.add(emoji); - - for (ObsoleteEmoji obsoleteEmoji : EmojiSource.getLatest().getObsolete()) { - if (obsoleteEmoji.getObsolete().equals(emoji)) { - out.add(obsoleteEmoji.getReplaceWith()); - } else if (obsoleteEmoji.getReplaceWith().equals(emoji)) { - out.add(obsoleteEmoji.getObsolete()); - } - } - - return out; - } - - /** - * When provided an emoji that is a skin variation of another, this will return the default yellow - * version. This is to aid in search, so using a variation will still find all emojis tagged with - * the default version. - * - * If the emoji has no skin variations, this function will return the original emoji. - */ - public static @NonNull String getCanonicalRepresentation(@NonNull String emoji) { - String canonical = EmojiSource.getLatest().getVariationsToCanonical().get(emoji); - return canonical != null ? canonical : emoji; - } - - public static boolean isCanonicallyEqual(@NonNull String left, @NonNull String right) { - return getCanonicalRepresentation(left).equals(getCanonicalRepresentation(right)); - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiVariationSelectorPopup.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiVariationSelectorPopup.java deleted file mode 100644 index 14a901b3ba..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiVariationSelectorPopup.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji; - -import android.content.Context; -import android.graphics.drawable.ColorDrawable; -import android.view.LayoutInflater; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.PopupWindow; - -import androidx.annotation.NonNull; - -import org.session.libsession.utilities.ThemeUtil; - -import java.util.List; - -import network.loki.messenger.R; - -public class EmojiVariationSelectorPopup extends PopupWindow { - - private final Context context; - private final ViewGroup list; - private final EmojiEventListener listener; - - public EmojiVariationSelectorPopup(@NonNull Context context, @NonNull EmojiEventListener listener) { - super(LayoutInflater.from(context).inflate(R.layout.emoji_variation_selector, null), - ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - this.context = context; - this.listener = listener; - this.list = (ViewGroup) getContentView(); - - setBackgroundDrawable( - new ColorDrawable(ThemeUtil.getThemedColor(context, R.attr.colorPrimary)) - ); - setOutsideTouchable(true); - } - - public void setVariations(List variations) { - list.removeAllViews(); - - for (String variation : variations) { - ImageView imageView = (ImageView) LayoutInflater.from(context).inflate(R.layout.emoji_variation_selector_item, list, false); - imageView.setImageDrawable(EmojiProvider.getEmojiDrawable(context, variation)); - imageView.setOnClickListener(v -> { - listener.onEmojiSelected(variation); - dismiss(); - }); - list.addView(imageView); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java deleted file mode 100644 index 812b9d648c..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji; - -import android.net.Uri; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.annimon.stream.Collectors; -import com.annimon.stream.Stream; - -import org.thoughtcrime.securesms.emoji.EmojiCategory; - -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -public class StaticEmojiPageModel implements EmojiPageModel { - private final @NonNull EmojiCategory category; - private final @NonNull List emoji; - private final @Nullable Uri sprite; - - public StaticEmojiPageModel(@NonNull EmojiCategory category, @NonNull String[] strings, @Nullable Uri sprite) { - this(category, Stream.of(strings).map(s -> new Emoji(Collections.singletonList(s))).collect(Collectors.toList()), sprite); - } - - public StaticEmojiPageModel(@NonNull EmojiCategory category, @NonNull List emoji, @Nullable Uri sprite) { - this.category = category; - this.emoji = Collections.unmodifiableList(emoji); - this.sprite = sprite; - } - - @Override - public String getKey() { - return category.getKey(); - } - - public int getIconAttr() { - return category.getIcon(); - } - - @Override - public @NonNull List getEmoji() { - List emojis = new LinkedList<>(); - for (Emoji e : emoji) { - emojis.addAll(e.getVariations()); - } - return emojis; - } - - @Override - public @NonNull List getDisplayEmoji() { - return emoji; - } - - @Override - public boolean hasSpriteMap() { - return sprite != null; - } - - @Override - public @Nullable Uri getSpriteUri() { - return sprite; - } - - @Override - public boolean isDynamic() { - return false; - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/parsing/EmojiDrawInfo.kt b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/parsing/EmojiDrawInfo.kt deleted file mode 100644 index 28de3aca78..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/parsing/EmojiDrawInfo.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji.parsing - -import org.thoughtcrime.securesms.emoji.EmojiPage - -data class EmojiDrawInfo(val page: EmojiPage, val index: Int, private val emoji: String, val rawEmoji: String?, val jumboSheet: String?) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/parsing/EmojiParser.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/parsing/EmojiParser.java deleted file mode 100644 index b582d7afe1..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/parsing/EmojiParser.java +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Copyright (c) 2014-present Vincent DURMONT vdurmont@gmail.com - * 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. - */ - -package org.thoughtcrime.securesms.components.emoji.parsing; - - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -/** - * Based in part on code from emoji-java - */ -public class EmojiParser { - - private final EmojiTree emojiTree; - - public EmojiParser(EmojiTree emojiTree) { - this.emojiTree = emojiTree; - } - - public @NonNull CandidateList findCandidates(@Nullable CharSequence text) { - List results = new LinkedList<>(); - - if (text == null) return new CandidateList(results, false); - - boolean allEmojis = text.length() > 0; - - for (int i = 0; i < text.length(); i++) { - int emojiEnd = getEmojiEndPos(text, i); - - if (emojiEnd != -1) { - EmojiDrawInfo drawInfo = emojiTree.getEmoji(text, i, emojiEnd); - - if (emojiEnd + 2 <= text.length()) { - if (Fitzpatrick.fitzpatrickFromUnicode(text, emojiEnd) != null) { - emojiEnd += 2; - } - } - - results.add(new Candidate(i, emojiEnd, drawInfo)); - - i = emojiEnd - 1; - } else { - allEmojis = false; - } - } - - return new CandidateList(results, allEmojis); - } - - private int getEmojiEndPos(CharSequence text, int startPos) { - int best = -1; - - for (int j = startPos + 1; j <= text.length(); j++) { - EmojiTree.Matches status = emojiTree.isEmoji(text, startPos, j); - - if (status.exactMatch()) { - best = j; - } else if (status.impossibleMatch()) { - return best; - } - } - - return best; - } - - public static class Candidate { - - private final int startIndex; - private final int endIndex; - private final EmojiDrawInfo drawInfo; - - Candidate(int startIndex, int endIndex, EmojiDrawInfo drawInfo) { - this.startIndex = startIndex; - this.endIndex = endIndex; - this.drawInfo = drawInfo; - } - - public EmojiDrawInfo getDrawInfo() { - return drawInfo; - } - - public int getEndIndex() { - return endIndex; - } - - public int getStartIndex() { - return startIndex; - } - } - - public static class CandidateList implements Iterable { - public final List list; - public final boolean allEmojis; - - public CandidateList(List candidates, boolean allEmojis) { - this.list = candidates; - this.allEmojis = allEmojis; - } - - public int size() { - return list.size(); - } - - @Override - public @NonNull Iterator iterator() { - return list.iterator(); - } - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/parsing/EmojiTree.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/parsing/EmojiTree.java deleted file mode 100644 index 399df58f6b..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/parsing/EmojiTree.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Copyright (c) 2014-present Vincent DURMONT vdurmont@gmail.com - * 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. - */ - -package org.thoughtcrime.securesms.components.emoji.parsing; - -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Map; - -/** - * Based in part on code from emoji-java - */ -public class EmojiTree { - - private final EmojiTreeNode root = new EmojiTreeNode(); - - private static final char TERMINATOR = '\ufe0f'; - - public void add(String emojiEncoding, EmojiDrawInfo emoji) { - EmojiTreeNode tree = root; - - for (char c: emojiEncoding.toCharArray()) { - if (!tree.hasChild(c)) { - tree.addChild(c); - } - - tree = tree.getChild(c); - } - - tree.setEmoji(emoji); - } - - public Matches isEmoji(CharSequence sequence, int startPosition, int endPosition) { - if (sequence == null) { - return Matches.POSSIBLY; - } - - EmojiTreeNode tree = root; - - for (int i=startPosition; i children = new HashMap<>(); - private EmojiDrawInfo emoji; - - public void setEmoji(EmojiDrawInfo emoji) { - this.emoji = emoji; - } - - public @Nullable EmojiDrawInfo getEmoji() { - return emoji; - } - - boolean hasChild(char child) { - return children.containsKey(child); - } - - void addChild(char child) { - children.put(child, new EmojiTreeNode()); - } - - EmojiTreeNode getChild(char child) { - return children.get(child); - } - - boolean isEndOfEmoji() { - return emoji != null; - } - } - - public enum Matches { - EXACTLY, POSSIBLY, IMPOSSIBLE; - - public boolean exactMatch() { - return this == EXACTLY; - } - - public boolean impossibleMatch() { - return this == IMPOSSIBLE; - } - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/parsing/Fitzpatrick.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/parsing/Fitzpatrick.java deleted file mode 100644 index 68315a6eb6..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/parsing/Fitzpatrick.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.thoughtcrime.securesms.components.emoji.parsing; - - -public enum Fitzpatrick { - /** - * Fitzpatrick modifier of type 1/2 (pale white/white) - */ - TYPE_1_2("\uD83C\uDFFB"), - - /** - * Fitzpatrick modifier of type 3 (cream white) - */ - TYPE_3("\uD83C\uDFFC"), - - /** - * Fitzpatrick modifier of type 4 (moderate brown) - */ - TYPE_4("\uD83C\uDFFD"), - - /** - * Fitzpatrick modifier of type 5 (dark brown) - */ - TYPE_5("\uD83C\uDFFE"), - - /** - * Fitzpatrick modifier of type 6 (black) - */ - TYPE_6("\uD83C\uDFFF"); - - /** - * The unicode representation of the Fitzpatrick modifier - */ - public final String unicode; - - Fitzpatrick(String unicode) { - this.unicode = unicode; - } - - - public static Fitzpatrick fitzpatrickFromUnicode(CharSequence unicode, int index) { - for (Fitzpatrick v : values()) { - boolean match = true; - - for (int i=0;i + private lateinit var emojiViews: List private var contextMenu: ConversationContextMenu? = null private var touchDownDeadZoneSize = 0f private var distanceFromTouchDownPointToBottomOfScrubberDeadZone = 0f @@ -109,12 +106,6 @@ class ConversationReactionOverlay : FrameLayout { private val scope = CoroutineScope(Dispatchers.Default) private var job: Job? = null - private val iconMore by lazy { - val d = ContextCompat.getDrawable(context, R.drawable.ic_plus) - d?.setTint(context.getColorFromAttr(android.R.attr.textColor)) - d - } - constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) @@ -281,8 +272,6 @@ class ConversationReactionOverlay : FrameLayout { foregroundView.x = scrubberX foregroundView.y = reactionBarBackgroundY + reactionBarHeight / 2f - foregroundView.height / 2f - backgroundView.x = scrubberX - backgroundView.y = reactionBarBackgroundY verticalScrubBoundary.update(reactionBarBackgroundY, lastSeenDownPoint.y + distanceFromTouchDownPointToBottomOfScrubberDeadZone) updateBoundsOnLayoutChanged() @@ -293,7 +282,7 @@ class ConversationReactionOverlay : FrameLayout { isMessageOnLeft -> scrubberRight + menuPadding else -> scrubberX - contextMenu.getMaxWidth() - menuPadding } - contextMenu.show(offsetX.toInt(), Math.min(backgroundView.y, (overlayHeight - contextMenu.getMaxHeight()).toFloat()).toInt()) + contextMenu.show(offsetX.toInt(), Math.min(foregroundView.y, (overlayHeight - contextMenu.getMaxHeight()).toFloat()).toInt()) } else { val contentX = if (isMessageOnLeft) scrubberHorizontalMargin.toFloat() else selectedConversationModel.bubbleX val offsetX = when { @@ -385,7 +374,7 @@ class ConversationReactionOverlay : FrameLayout { } private fun updateBoundsOnLayoutChanged() { - backgroundView.getGlobalVisibleRect(emojiStripViewBounds) + foregroundView.getGlobalVisibleRect(emojiStripViewBounds) emojiViews[0].getGlobalVisibleRect(emojiViewGlobalRect) emojiStripViewBounds.left = getStart(emojiViewGlobalRect) emojiViews[emojiViews.size - 1].getGlobalVisibleRect(emojiViewGlobalRect) @@ -457,12 +446,12 @@ class ConversationReactionOverlay : FrameLayout { view.scaleX = 1.0f view.scaleY = 1.0f view.translationY = 0f + val isAtCustomIndex = i == customEmojiIndex if (isAtCustomIndex) { - view.setImageDrawable(iconMore) view.tag = null } else { - view.setImageEmoji(emojis[i]) + (view as? TextView)?.text = emojis[i] } } } @@ -656,14 +645,15 @@ class ConversationReactionOverlay : FrameLayout { private fun initAnimators() { val revealDuration = context.resources.getInteger(R.integer.reaction_scrubber_reveal_duration) val revealOffset = context.resources.getInteger(R.integer.reaction_scrubber_reveal_offset) - val reveals = emojiViews.mapIndexed { idx: Int, v: EmojiImageView? -> + + val reveals = emojiViews.mapIndexed { idx: Int, v: View? -> AnimatorInflaterCompat.loadAnimator(context, R.animator.reactions_scrubber_reveal).apply { setTarget(v) startDelay = (idx * animationEmojiStartDelayFactor).toLong() } } + AnimatorInflaterCompat.loadAnimator(context, android.R.animator.fade_in).apply { setTarget(backgroundView) - setDuration(revealDuration.toLong()) + duration = revealDuration.toLong() startDelay = revealOffset.toLong() } revealAnimatorSet.interpolator = INTERPOLATOR diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/EmojiReactionsView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/EmojiReactionsView.kt index 27714fbc05..392ca5dca3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/EmojiReactionsView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/EmojiReactionsView.kt @@ -10,7 +10,6 @@ import android.widget.LinearLayout import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat -import androidx.core.view.setPadding import com.google.android.flexbox.JustifyContent import com.squareup.phrase.Phrase import network.loki.messenger.R @@ -18,8 +17,6 @@ import network.loki.messenger.databinding.ViewEmojiReactionsBinding import org.session.libsession.utilities.StringSubstitutionConstants.COUNT_KEY import org.session.libsession.utilities.TextSecurePreferences.Companion.getLocalNumber import org.session.libsession.utilities.ThemeUtil -import org.thoughtcrime.securesms.components.emoji.EmojiImageView -import org.thoughtcrime.securesms.components.emoji.EmojiUtil import org.thoughtcrime.securesms.conversation.v2.ViewUtil import org.thoughtcrime.securesms.database.model.MessageId import org.thoughtcrime.securesms.database.model.ReactionRecord @@ -155,7 +152,7 @@ class EmojiReactionsView : ConstraintLayout, OnTouchListener { val counters: MutableMap = LinkedHashMap() records.forEach { - val baseEmoji = EmojiUtil.getCanonicalRepresentation(it.emoji) + val baseEmoji = it.emoji val info = counters[baseEmoji] if (info == null) { @@ -180,18 +177,16 @@ class EmojiReactionsView : ConstraintLayout, OnTouchListener { private fun buildPill(context: Context, parent: ViewGroup, reaction: Reaction, isCompact: Boolean): View { val root = LayoutInflater.from(context).inflate(R.layout.reactions_pill, parent, false) - val emojiView = root.findViewById(R.id.reactions_pill_emoji) + val emojiView = root.findViewById(R.id.reactions_pill_emoji) val countView = root.findViewById(R.id.reactions_pill_count) val spacer = root.findViewById(R.id.reactions_pill_spacer) if (isCompact) { - root.setPadding(0) - val layoutParams = root.layoutParams - layoutParams.height = overflowItemSize - layoutParams.width = overflowItemSize - root.layoutParams = layoutParams + val paddingV = ViewUtil.dpToPx(2) + val paddingH = ViewUtil.dpToPx(3) + root.setPadding(paddingH, paddingV, paddingH, paddingV) } if (reaction.emoji != null) { - emojiView.setImageEmoji(reaction.emoji) + emojiView.text = reaction.emoji if (reaction.count >= 1) { countView.text = getFormattedNumber(reaction.count) } else { @@ -203,6 +198,7 @@ class EmojiReactionsView : ConstraintLayout, OnTouchListener { spacer.visibility = GONE countView.text = Phrase.from(context, R.string.andMore).put(COUNT_KEY, reaction.count.toInt()).format() } + if (reaction.userWasSender && !isCompact) { root.background = ContextCompat.getDrawable(context, R.drawable.reaction_pill_background_selected) countView.setTextColor(ThemeUtil.getThemedColor(context, R.attr.reactionsPillSelectedTextColor)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/EmojiSearchDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/EmojiSearchDatabase.kt deleted file mode 100644 index f6e389a47d..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/database/EmojiSearchDatabase.kt +++ /dev/null @@ -1,101 +0,0 @@ -package org.thoughtcrime.securesms.database - -import android.content.Context -import androidx.core.content.contentValuesOf -import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper -import org.thoughtcrime.securesms.database.model.EmojiSearchData -import org.thoughtcrime.securesms.util.CursorUtil -import kotlin.math.max -import kotlin.math.roundToInt - -/** - * Contains all info necessary for full-text search of emoji tags. - */ -class EmojiSearchDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper) { - - companion object { - const val TABLE_NAME = "emoji_search" - const val LABEL = "label" - const val EMOJI = "emoji" - const val CREATE_EMOJI_SEARCH_TABLE_COMMAND = "CREATE VIRTUAL TABLE $TABLE_NAME USING fts5($LABEL, $EMOJI UNINDEXED)" - } - - /** - * @param query A search query. Doesn't need any special formatted -- it'll be sanitized. - * @return A list of emoji that are related to the search term, ordered by relevance. - */ - fun query(originalQuery: String, originalLimit: Int): List { - val query: String = originalQuery.trim() - - if (query.isEmpty()) { - return emptyList() - } - - val limit: Int = max(originalLimit, 100) - val entries = mutableListOf() - - readableDatabase.query(TABLE_NAME, arrayOf(LABEL, EMOJI), "$LABEL LIKE ?", arrayOf("%$query%"), null, null, null, "$limit") - .use { cursor -> - while (cursor.moveToNext()) { - entries += Entry( - label = CursorUtil.requireString(cursor, LABEL), - emoji = CursorUtil.requireString(cursor, EMOJI) - ) - } - } - - return entries - .sortedWith { lhs, rhs -> - similarityScore(query, lhs.label) - similarityScore(query, rhs.label) - } - .distinctBy { it.emoji } - .take(originalLimit) - .map { it.emoji } - } - - /** - * Deletes the content of the current search index and replaces it with the new one. - */ - fun setSearchIndex(searchIndex: List) { - writableDatabase.beginTransaction() - writableDatabase.delete(TABLE_NAME, null, null) - - for (searchData in searchIndex) { - for (label in searchData.tags) { - val values = contentValuesOf( - LABEL to label, - EMOJI to searchData.emoji - ) - writableDatabase.insert(TABLE_NAME, null, values) - } - } - writableDatabase.setTransactionSuccessful() - writableDatabase.endTransaction() - } - - /** - * Ranks how "similar" a match is to the original search term. - * A lower score means more similar, with 0 being a perfect match. - * - * We know that the `searchTerm` must be a substring of the `match`. - * We determine similarity by how many letters appear before or after the `searchTerm` in the `match`. - * We give letters that come before the term a bigger weight than those that come after as a way to prefer matches that are prefixed by the `searchTerm`. - */ - private fun similarityScore(searchTerm: String, match: String): Int { - if (searchTerm == match) { - return 0 - } - - val startIndex = match.indexOf(searchTerm) - - val prefixCount = startIndex - val suffixCount = match.length - (startIndex + searchTerm.length) - - val prefixRankWeight = 1.5f - val suffixRankWeight = 1f - - return ((prefixCount * prefixRankWeight) + (suffixCount * suffixRankWeight)).roundToInt() - } - - private data class Entry(val label: String, val emoji: String) -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index e1568933cb..e29b0623cf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -6,15 +6,17 @@ import android.app.NotificationManager; import android.content.Context; import android.database.Cursor; + import androidx.annotation.NonNull; import androidx.core.app.NotificationCompat; + import com.squareup.phrase.Phrase; -import java.io.File; + import net.zetetic.database.sqlcipher.SQLiteConnection; import net.zetetic.database.sqlcipher.SQLiteDatabase; import net.zetetic.database.sqlcipher.SQLiteDatabaseHook; import net.zetetic.database.sqlcipher.SQLiteOpenHelper; -import network.loki.messenger.R; + import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsignal.utilities.Log; import org.thoughtcrime.securesms.crypto.DatabaseSecret; @@ -22,7 +24,6 @@ import org.thoughtcrime.securesms.database.BlindedIdMappingDatabase; import org.thoughtcrime.securesms.database.ConfigDatabase; import org.thoughtcrime.securesms.database.DraftDatabase; -import org.thoughtcrime.securesms.database.EmojiSearchDatabase; import org.thoughtcrime.securesms.database.ExpirationConfigurationDatabase; import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.GroupMemberDatabase; @@ -43,6 +44,10 @@ import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities; +import java.io.File; + +import network.loki.messenger.R; + public class SQLCipherOpenHelper extends SQLiteOpenHelper { @SuppressWarnings("unused") @@ -343,7 +348,6 @@ public void onCreate(SQLiteDatabase db) { db.execSQL(BlindedIdMappingDatabase.CREATE_BLINDED_ID_MAPPING_TABLE_COMMAND); db.execSQL(GroupMemberDatabase.CREATE_GROUP_MEMBER_TABLE_COMMAND); db.execSQL(LokiAPIDatabase.RESET_SEQ_NO); // probably not needed but consistent with all migrations - db.execSQL(EmojiSearchDatabase.CREATE_EMOJI_SEARCH_TABLE_COMMAND); db.execSQL(ReactionDatabase.CREATE_REACTION_TABLE_COMMAND); db.execSQL(ThreadDatabase.getUnreadMentionCountCommand()); db.execSQL(SmsDatabase.CREATE_HAS_MENTION_COMMAND); @@ -589,10 +593,6 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { executeStatements(db, ReactionDatabase.CREATE_REACTION_TRIGGERS); } - if (oldVersion < lokiV38) { - db.execSQL(EmojiSearchDatabase.CREATE_EMOJI_SEARCH_TABLE_COMMAND); - } - if (oldVersion < lokiV39) { executeStatements(db, ReactionDatabase.CREATE_INDEXS); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/EmojiSearchData.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/EmojiSearchData.java deleted file mode 100644 index ad5cfe94bf..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/EmojiSearchData.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.thoughtcrime.securesms.database.model; - -import androidx.annotation.NonNull; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -/** - * Ties together an emoji with it's associated search tags. - */ -public final class EmojiSearchData { - @JsonProperty - private String emoji; - - @JsonProperty - private List tags; - - public EmojiSearchData() {} - - public @NonNull String getEmoji() { - return emoji; - } - - public @NonNull List getTags() { - return tags; - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt index ad5eac883f..515dc54855 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt @@ -5,10 +5,32 @@ import dagger.hilt.EntryPoint import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import org.session.libsession.database.MessageDataProvider -import org.session.libsession.database.StorageProtocol import org.thoughtcrime.securesms.ApplicationContext -import org.thoughtcrime.securesms.database.* +import org.thoughtcrime.securesms.database.AttachmentDatabase +import org.thoughtcrime.securesms.database.BlindedIdMappingDatabase +import org.thoughtcrime.securesms.database.ConfigDatabase +import org.thoughtcrime.securesms.database.DraftDatabase +import org.thoughtcrime.securesms.database.ExpirationConfigurationDatabase +import org.thoughtcrime.securesms.database.GroupDatabase +import org.thoughtcrime.securesms.database.GroupMemberDatabase +import org.thoughtcrime.securesms.database.GroupReceiptDatabase +import org.thoughtcrime.securesms.database.LokiAPIDatabase +import org.thoughtcrime.securesms.database.LokiBackupFilesDatabase +import org.thoughtcrime.securesms.database.LokiMessageDatabase +import org.thoughtcrime.securesms.database.LokiThreadDatabase +import org.thoughtcrime.securesms.database.LokiUserDatabase +import org.thoughtcrime.securesms.database.MediaDatabase +import org.thoughtcrime.securesms.database.MmsDatabase import org.thoughtcrime.securesms.database.MmsSmsDatabase +import org.thoughtcrime.securesms.database.PushDatabase +import org.thoughtcrime.securesms.database.ReactionDatabase +import org.thoughtcrime.securesms.database.RecipientDatabase +import org.thoughtcrime.securesms.database.SearchDatabase +import org.thoughtcrime.securesms.database.SessionContactDatabase +import org.thoughtcrime.securesms.database.SessionJobDatabase +import org.thoughtcrime.securesms.database.SmsDatabase +import org.thoughtcrime.securesms.database.Storage +import org.thoughtcrime.securesms.database.ThreadDatabase import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper @EntryPoint @@ -43,7 +65,6 @@ interface DatabaseComponent { fun sessionJobDatabase(): SessionJobDatabase fun sessionContactDatabase(): SessionContactDatabase fun reactionDatabase(): ReactionDatabase - fun emojiSearchDatabase(): EmojiSearchDatabase fun storage(): Storage fun attachmentProvider(): MessageDataProvider fun blindedIdMappingDatabase(): BlindedIdMappingDatabase diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt index 179a463fc8..edf945ffdd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt @@ -15,7 +15,6 @@ import org.thoughtcrime.securesms.database.AttachmentDatabase import org.thoughtcrime.securesms.database.BlindedIdMappingDatabase import org.thoughtcrime.securesms.database.ConfigDatabase import org.thoughtcrime.securesms.database.DraftDatabase -import org.thoughtcrime.securesms.database.EmojiSearchDatabase import org.thoughtcrime.securesms.database.ExpirationConfigurationDatabase import org.thoughtcrime.securesms.database.GroupDatabase import org.thoughtcrime.securesms.database.GroupMemberDatabase @@ -149,10 +148,6 @@ object DatabaseModule { @Singleton fun provideReactionDatabase(@ApplicationContext context: Context, openHelper: SQLCipherOpenHelper) = ReactionDatabase(context, openHelper) - @Provides - @Singleton - fun provideEmojiSearchDatabase(@ApplicationContext context: Context, openHelper: SQLCipherOpenHelper) = EmojiSearchDatabase(context, openHelper) - @Provides @Singleton fun provideExpirationConfigurationDatabase(@ApplicationContext context: Context, openHelper: SQLCipherOpenHelper) = ExpirationConfigurationDatabase(context, openHelper) diff --git a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiCategory.kt b/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiCategory.kt deleted file mode 100644 index c9a59b2107..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiCategory.kt +++ /dev/null @@ -1,45 +0,0 @@ -package org.thoughtcrime.securesms.emoji - -import androidx.annotation.AttrRes -import androidx.annotation.StringRes -import network.loki.messenger.R - -/** - * All the different Emoji categories the app is aware of in the order we want to display them. - */ -enum class EmojiCategory(val priority: Int, val key: String, @AttrRes val icon: Int) { - PEOPLE(0, "People", R.attr.emoji_category_people), - NATURE(1, "Nature", R.attr.emoji_category_nature), - FOODS(2, "Foods", R.attr.emoji_category_foods), - ACTIVITY(3, "Activity", R.attr.emoji_category_activity), - PLACES(4, "Places", R.attr.emoji_category_places), - OBJECTS(5, "Objects", R.attr.emoji_category_objects), - SYMBOLS(6, "Symbols", R.attr.emoji_category_symbol), - FLAGS(7, "Flags", R.attr.emoji_category_flags); - - @StringRes - fun getCategoryLabel(): Int { - return getCategoryLabel(icon) - } - - companion object { - @JvmStatic - fun forKey(key: String) = values().first { it.key == key } - - @JvmStatic - @StringRes - fun getCategoryLabel(@AttrRes iconAttr: Int): Int { - return when (iconAttr) { - R.attr.emoji_category_people -> R.string.emojiCategorySmileys - R.attr.emoji_category_nature -> R.string.emojiCategoryAnimals - R.attr.emoji_category_foods -> R.string.emojiCategoryFood - R.attr.emoji_category_activity -> R.string.emojiCategoryActivities - R.attr.emoji_category_places -> R.string.emojiCategoryTravel - R.attr.emoji_category_objects -> R.string.emojiCategoryObjects - R.attr.emoji_category_symbol -> R.string.emojiCategorySymbols - R.attr.emoji_category_flags -> R.string.emojiCategoryFlags - else -> throw AssertionError() - } - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiJsonParser.kt b/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiJsonParser.kt deleted file mode 100644 index 97be172adb..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiJsonParser.kt +++ /dev/null @@ -1,138 +0,0 @@ -package org.thoughtcrime.securesms.emoji - -import android.net.Uri -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import org.session.libsignal.utilities.Hex -import org.thoughtcrime.securesms.components.emoji.CompositeEmojiPageModel -import org.thoughtcrime.securesms.components.emoji.Emoji -import org.thoughtcrime.securesms.components.emoji.EmojiPageModel -import org.thoughtcrime.securesms.components.emoji.StaticEmojiPageModel -import java.io.InputStream -import java.nio.charset.Charset - -typealias UriFactory = (sprite: String, format: String) -> Uri - -/** - * Takes an emoji_data.json file data and parses it into an EmojiSource - */ -object EmojiJsonParser { - private val OBJECT_MAPPER = ObjectMapper() - private const val ESTIMATED_EMOJI_COUNT = 3500 - - @JvmStatic - fun verify(body: InputStream) { - parse(body) { _, _ -> Uri.EMPTY }.getOrThrow() - } - - fun parse(body: InputStream, uriFactory: UriFactory): Result { - return try { - Result.success(buildEmojiSourceFromNode(OBJECT_MAPPER.readTree(body), uriFactory)) - } catch (e: Exception) { - Result.failure(e) - } - } - - private fun buildEmojiSourceFromNode(node: JsonNode, uriFactory: UriFactory): ParsedEmojiData { - val format: String = node["format"].textValue() - val obsolete: List = node["obsolete"].toObseleteList() - val dataPages: List = getDataPages(format, node["emoji"], uriFactory) - val jumboPages: Map = getJumboPages(node["jumbomoji"]) - val displayPages: List = mergeToDisplayPages(dataPages) - val metrics: EmojiMetrics = node["metrics"].toEmojiMetrics() - val densities: List = node["densities"].toDensityList() - - return ParsedEmojiData(metrics, densities, format, displayPages, dataPages, jumboPages, obsolete) - } - - private fun getDataPages(format: String, emoji: JsonNode, uriFactory: UriFactory): List { - return emoji.fields() - .asSequence() - .sortedWith { lhs, rhs -> - val lhsCategory = EmojiCategory.forKey(lhs.key.asCategoryKey()) - val rhsCategory = EmojiCategory.forKey(rhs.key.asCategoryKey()) - val comp = lhsCategory.priority.compareTo(rhsCategory.priority) - - if (comp == 0) { - val lhsIndex = lhs.key.getPageIndex() - val rhsIndex = rhs.key.getPageIndex() - - lhsIndex.compareTo(rhsIndex) - } else { - comp - } - } - .map { createPage(it.key, format, it.value, uriFactory) } - .toList() - } - - private fun getJumboPages(jumbo: JsonNode?): Map { - if (jumbo != null) { - return jumbo.fields() - .asSequence() - .map { (page: String, node: JsonNode) -> - node.associate { it.textValue() to page } - } - .flatMap { it.entries } - .associateTo(HashMap(ESTIMATED_EMOJI_COUNT)) { it.key to it.value } - } - return emptyMap() - } - - private fun createPage(pageName: String, format: String, page: JsonNode, uriFactory: UriFactory): EmojiPageModel { - val category = EmojiCategory.forKey(pageName.asCategoryKey()) - val pageList = page.mapIndexed { i, data -> - if (data.size() == 0) { - throw IllegalStateException("Page index $pageName.$i had no data") - } else { - val variations: MutableList = mutableListOf() - val rawVariations: MutableList = mutableListOf() - data.forEach { - variations += it.textValue().encodeAsUtf16() - rawVariations += it.textValue() - } - - Emoji(variations, rawVariations) - } - } - - return StaticEmojiPageModel(category, pageList, uriFactory(pageName, format)) - } - - private fun mergeToDisplayPages(dataPages: List): List { - return dataPages.groupBy { it.iconAttr } - .map { (icon, pages) -> if (pages.size <= 1) pages.first() else CompositeEmojiPageModel(icon, pages) } - } -} - -private fun JsonNode?.toObseleteList(): List { - return if (this == null) { - listOf() - } else { - map { node -> - ObsoleteEmoji(node["obsoleted"].textValue().encodeAsUtf16(), node["replace_with"].textValue().encodeAsUtf16()) - }.toList() - } -} - -private fun JsonNode.toEmojiMetrics(): EmojiMetrics { - return EmojiMetrics(this["raw_width"].asInt(), this["raw_height"].asInt(), this["per_row"].asInt()) -} - -private fun JsonNode.toDensityList(): List { - return map { it.textValue() } -} - -private fun String.encodeAsUtf16() = String(Hex.fromStringCondensed(this), Charset.forName("UTF-16")) -private fun String.asCategoryKey() = replace("(_\\d+)*$".toRegex(), "") -private fun String.getPageIndex() = "^.*_(\\d+)+$".toRegex().find(this)?.let { it.groupValues[1] }?.toInt() ?: throw IllegalStateException("No index.") - -data class ParsedEmojiData( - override val metrics: EmojiMetrics, - override val densities: List, - override val format: String, - override val displayPages: List, - override val dataPages: List, - override val jumboPages: Map, - override val obsolete: List -) : EmojiData diff --git a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiPageCache.kt b/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiPageCache.kt deleted file mode 100644 index 56ff13141e..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiPageCache.kt +++ /dev/null @@ -1,85 +0,0 @@ -package org.thoughtcrime.securesms.emoji - -import android.content.Context -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import androidx.annotation.MainThread -import androidx.annotation.WorkerThread -import org.session.libsession.utilities.ListenableFutureTask -import org.session.libsession.utilities.SoftHashMap -import org.session.libsession.utilities.concurrent.SimpleTask -import org.session.libsignal.utilities.Log -import java.io.IOException -import java.io.InputStream - -object EmojiPageCache { - - private val TAG = Log.tag(EmojiPageCache::class.java) - - private val cache: SoftHashMap = SoftHashMap() - private val tasks: HashMap> = hashMapOf() - - @MainThread - fun load(context: Context, emojiPage: EmojiPage, inSampleSize: Int): LoadResult { - val applicationContext = context.applicationContext - val emojiPageRequest = EmojiPageRequest(emojiPage, inSampleSize) - val bitmap: Bitmap? = cache[emojiPageRequest] - val task: ListenableFutureTask? = tasks[emojiPageRequest] - - return when { - bitmap != null -> LoadResult.Immediate(bitmap) - task != null -> LoadResult.Async(task) - else -> { - val newTask = ListenableFutureTask { - try { - Log.i(TAG, "Loading page $emojiPageRequest") - loadInternal(applicationContext, emojiPageRequest) - } catch (e: IOException) { - Log.w(TAG, e) - null - } - } - - tasks[emojiPageRequest] = newTask - - SimpleTask.run(newTask::run) { - try { - val newBitmap: Bitmap? = newTask.get() - if (newBitmap == null) { - Log.w(TAG, "Failed to load emoji bitmap for request $emojiPageRequest") - } else { - cache[emojiPageRequest] = newBitmap - } - } finally { - tasks.remove(emojiPageRequest) - } - } - - LoadResult.Async(newTask) - } - } - } - - fun clear() { - cache.clear() - } - - @WorkerThread - private fun loadInternal(context: Context, emojiPageRequest: EmojiPageRequest): Bitmap? { - val inputStream: InputStream = when (emojiPageRequest.emojiPage) { - is EmojiPage.Asset -> context.assets.open(emojiPageRequest.emojiPage.uri.toString().replace("file:///android_asset/", "")) - } - - val bitmapOptions = BitmapFactory.Options() - bitmapOptions.inSampleSize = emojiPageRequest.inSampleSize - - return inputStream.use { BitmapFactory.decodeStream(it, null, bitmapOptions) } - } - - private data class EmojiPageRequest(val emojiPage: EmojiPage, val inSampleSize: Int) - - sealed class LoadResult { - data class Immediate(val bitmap: Bitmap) : LoadResult() - data class Async(val task: ListenableFutureTask) : LoadResult() - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiSource.kt b/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiSource.kt deleted file mode 100644 index 75b1496cc4..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiSource.kt +++ /dev/null @@ -1,141 +0,0 @@ -package org.thoughtcrime.securesms.emoji - -import android.net.Uri -import androidx.annotation.WorkerThread -import org.session.libsession.messaging.MessagingModuleConfiguration -import org.thoughtcrime.securesms.ApplicationContext -import org.thoughtcrime.securesms.components.emoji.Emoji -import org.thoughtcrime.securesms.components.emoji.EmojiPageModel -import org.thoughtcrime.securesms.components.emoji.StaticEmojiPageModel -import org.thoughtcrime.securesms.components.emoji.parsing.EmojiDrawInfo -import org.thoughtcrime.securesms.components.emoji.parsing.EmojiTree -import org.thoughtcrime.securesms.util.ScreenDensity -import java.io.InputStream -import java.util.concurrent.CountDownLatch -import java.util.concurrent.atomic.AtomicReference - -/** - * The entry point for the application to request Emoji data for custom emojis. - */ -class EmojiSource( - val decodeScale: Float, - private val emojiData: EmojiData, - private val emojiPageFactory: EmojiPageFactory -) : EmojiData by emojiData { - - val variationsToCanonical: Map by lazy { - val map = mutableMapOf() - - for (page: EmojiPageModel in dataPages) { - for (emoji: Emoji in page.displayEmoji) { - for (variation: String in emoji.variations) { - map[variation] = emoji.value - } - } - } - - map - } - - val canonicalToVariations: Map> by lazy { - val map = mutableMapOf>() - - for (page: EmojiPageModel in dataPages) { - for (emoji: Emoji in page.displayEmoji) { - map[emoji.value] = emoji.variations - } - } - - map - } - - val maxEmojiLength: Int by lazy { - dataPages.map { it.emoji.map(String::length) } - .flatten() - .maxOrZero() - } - - val emojiTree: EmojiTree by lazy { - val tree = EmojiTree() - - dataPages - .filter { it.spriteUri != null } - .forEach { page -> - val emojiPage = emojiPageFactory(page.spriteUri!!) - - var overallIndex = 0 - page.displayEmoji.forEach { emoji: Emoji -> - emoji.variations.forEachIndexed { variationIndex, variation -> - val raw = emoji.getRawVariation(variationIndex) - tree.add(variation, EmojiDrawInfo(emojiPage, overallIndex++, variation, raw, jumboPages[raw])) - } - } - } - - obsolete.forEach { - tree.add(it.obsolete, tree.getEmoji(it.replaceWith, 0, it.replaceWith.length)) - } - - tree - } - - companion object { - - private val emojiSource = AtomicReference() - private val emojiLatch = CountDownLatch(1) - - @JvmStatic - val latest: EmojiSource - get() { - emojiLatch.await() - return emojiSource.get() - } - - @JvmStatic - @WorkerThread - fun refresh() { - emojiSource.set(getEmojiSource()) - emojiLatch.countDown() - } - - private fun getEmojiSource(): EmojiSource { - return loadAssetBasedEmojis() - } - - private fun loadAssetBasedEmojis(): EmojiSource { - val context = MessagingModuleConfiguration.shared.context - val emojiData: InputStream = ApplicationContext.getInstance(context).assets.open("emoji/emoji_data.json") - - emojiData.use { - val parsedData: ParsedEmojiData = EmojiJsonParser.parse(it, ::getAssetsUri).getOrThrow() - return EmojiSource( - ScreenDensity.xhdpiRelativeDensityScaleFactor("xhdpi"), - - parsedData.copy( - displayPages = parsedData.displayPages, - dataPages = parsedData.dataPages - ) - - ) { uri: Uri -> EmojiPage.Asset(uri) } - } - } - } -} - -private fun List.maxOrZero(): Int = maxOrNull() ?: 0 - -interface EmojiData { - val metrics: EmojiMetrics - val densities: List - val format: String - val displayPages: List - val dataPages: List - val jumboPages: Map - val obsolete: List -} - -data class ObsoleteEmoji(val obsolete: String, val replaceWith: String) - -data class EmojiMetrics(val rawHeight: Int, val rawWidth: Int, val perRow: Int) - -private fun getAssetsUri(name: String, format: String): Uri = Uri.parse("file:///android_asset/emoji/$name.$format") diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyboard/emoji/search/EmojiSearchRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/keyboard/emoji/search/EmojiSearchRepository.kt deleted file mode 100644 index 6d888389aa..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/keyboard/emoji/search/EmojiSearchRepository.kt +++ /dev/null @@ -1,67 +0,0 @@ -package org.thoughtcrime.securesms.keyboard.emoji.search - -import android.content.Context -import android.net.Uri -import io.reactivex.Single -import io.reactivex.schedulers.Schedulers -import org.session.libsession.utilities.TextSecurePreferences -import org.session.libsession.utilities.concurrent.SignalExecutors -import org.thoughtcrime.securesms.components.emoji.Emoji -import org.thoughtcrime.securesms.components.emoji.EmojiPageModel -import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel -import org.thoughtcrime.securesms.database.EmojiSearchDatabase -import org.thoughtcrime.securesms.dependencies.DatabaseComponent -import org.thoughtcrime.securesms.emoji.EmojiSource -import java.util.function.Consumer - -private const val MINIMUM_QUERY_THRESHOLD = 1 -private const val MINIMUM_INLINE_QUERY_THRESHOLD = 2 -private const val EMOJI_SEARCH_LIMIT = 20 - -private val NOT_PUNCTUATION = "[A-Za-z0-9 ]".toRegex() - -class EmojiSearchRepository(private val context: Context) { - - private val emojiSearchDatabase: EmojiSearchDatabase = DatabaseComponent.get(context).emojiSearchDatabase() - - fun submitQuery(query: String, limit: Int = EMOJI_SEARCH_LIMIT): Single> { - val result = if (query.length >= MINIMUM_INLINE_QUERY_THRESHOLD && NOT_PUNCTUATION.matches(query.substring(query.lastIndex))) { - Single.fromCallable { emojiSearchDatabase.query(query, limit) } - } else { - Single.just(emptyList()) - } - - return result.subscribeOn(Schedulers.io()) - } - - fun submitQuery(query: String, limit: Int = EMOJI_SEARCH_LIMIT, consumer: Consumer) { - SignalExecutors.SERIAL.execute { - val emoji: List = emojiSearchDatabase.query(query, limit) - - val displayEmoji: List = emoji - .mapNotNull { canonical -> EmojiSource.latest.canonicalToVariations[canonical] } - .map { Emoji(it) } - - consumer.accept(EmojiSearchResultsPageModel(emoji, displayEmoji)) - } - } - - private class EmojiSearchResultsPageModel( - private val emoji: List, - private val displayEmoji: List - ) : EmojiPageModel { - override fun getKey(): String = "" - - override fun getIconAttr(): Int = -1 - - override fun getEmoji(): List = emoji - - override fun getDisplayEmoji(): List = displayEmoji - - override fun hasSpriteMap(): Boolean = false - - override fun getSpriteUri(): Uri? = null - - override fun isDynamic(): Boolean = false - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/reactions/ReactionRecipientsAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/reactions/ReactionRecipientsAdapter.java index 28662e894a..aef3dfe0eb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/reactions/ReactionRecipientsAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/reactions/ReactionRecipientsAdapter.java @@ -1,22 +1,21 @@ package org.thoughtcrime.securesms.reactions; -import static org.session.libsession.utilities.IdUtilKt.truncateIdForDisplay; - import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; -import org.session.libsignal.utilities.AccountId; +import org.thoughtcrime.securesms.components.ProfilePictureView; +import org.thoughtcrime.securesms.database.model.MessageId; + import java.util.Collections; import java.util.List; + import network.loki.messenger.R; -import org.thoughtcrime.securesms.components.ProfilePictureView; -import org.thoughtcrime.securesms.components.emoji.EmojiImageView; -import org.thoughtcrime.securesms.database.model.MessageId; final class ReactionRecipientsAdapter extends RecyclerView.Adapter { @@ -126,8 +125,8 @@ private void bind(@NonNull final EmojiCount emoji, final MessageId messageId, bo clearAll.setOnClickListener(isUserModerator ? (View.OnClickListener) v -> { callback.onClearAll(emoji.getBaseEmoji(), messageId); } : null); - EmojiImageView emojiView = itemView.findViewById(R.id.header_view_emoji); - emojiView.setImageEmoji(emoji.getDisplayEmoji()); + TextView emojiView = itemView.findViewById(R.id.header_view_emoji); + emojiView.setText(emoji.getDisplayEmoji()); TextView count = itemView.findViewById(R.id.header_view_emoji_count); count.setText(String.format(" • %s", emoji.getCount())); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsDialogFragment.java b/app/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsDialogFragment.java index e9da05212b..67d0ab520c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsDialogFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsDialogFragment.java @@ -109,12 +109,12 @@ private void setUpTabMediator(@Nullable Bundle savedInstanceState) { tab.setCustomView(R.layout.reactions_pill_large); View customView = Objects.requireNonNull(tab.getCustomView()); - EmojiImageView emoji = customView.findViewById(R.id.reactions_pill_emoji); + TextView emoji = customView.findViewById(R.id.reactions_pill_emoji); TextView text = customView.findViewById(R.id.reactions_pill_count); EmojiCount emojiCount = recipientsAdapter.getEmojiCount(position); customView.setBackground(ContextCompat.getDrawable(requireContext(), R.drawable.reaction_pill_dialog_background)); - emoji.setImageEmoji(emojiCount.getDisplayEmoji()); + emoji.setText(emojiCount.getDisplayEmoji()); text.setText(NumberUtil.getFormattedNumber(emojiCount.getCount())); }); diff --git a/app/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsRepository.kt index 8687a0f9bb..2e7c2d393f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsRepository.kt @@ -6,7 +6,6 @@ import io.reactivex.schedulers.Schedulers import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.utilities.Address import org.session.libsession.utilities.recipients.Recipient -import org.thoughtcrime.securesms.components.emoji.EmojiUtil import org.thoughtcrime.securesms.database.model.MessageId import org.thoughtcrime.securesms.database.model.ReactionRecord import org.thoughtcrime.securesms.dependencies.DatabaseComponent @@ -26,7 +25,7 @@ class ReactionsRepository { return reactions.map { reaction -> ReactionDetails( sender = Recipient.from(context, Address.fromSerialized(reaction.author), false), - baseEmoji = EmojiUtil.getCanonicalRepresentation(reaction.emoji), + baseEmoji = reaction.emoji, displayEmoji = reaction.emoji, timestamp = reaction.dateReceived, serverId = reaction.serverId, diff --git a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiDialogFragment.java b/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiDialogFragment.java deleted file mode 100644 index 2fd547eab3..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiDialogFragment.java +++ /dev/null @@ -1,211 +0,0 @@ -package org.thoughtcrime.securesms.reactions.any; - -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.DialogFragment; -import androidx.lifecycle.ViewModelProvider; -import androidx.loader.app.LoaderManager; - -import com.google.android.material.bottomsheet.BottomSheetBehavior; -import com.google.android.material.bottomsheet.BottomSheetDialog; -import com.google.android.material.bottomsheet.BottomSheetDialogFragment; -import com.google.android.material.shape.CornerFamily; -import com.google.android.material.shape.ShapeAppearanceModel; - -import org.thoughtcrime.securesms.components.emoji.EmojiEventListener; -import org.thoughtcrime.securesms.components.emoji.EmojiPageView; -import org.thoughtcrime.securesms.components.emoji.EmojiPageViewGridAdapter; -import org.thoughtcrime.securesms.conversation.v2.ViewUtil; -import org.thoughtcrime.securesms.database.model.MessageId; -import org.thoughtcrime.securesms.database.model.MessageRecord; -import org.thoughtcrime.securesms.keyboard.emoji.KeyboardPageSearchView; -import org.thoughtcrime.securesms.util.LifecycleDisposable; - -import network.loki.messenger.R; - -public final class ReactWithAnyEmojiDialogFragment extends BottomSheetDialogFragment implements EmojiEventListener, - EmojiPageViewGridAdapter.VariationSelectorListener -{ - - private static final String ARG_MESSAGE_ID = "arg_message_id"; - private static final String ARG_IS_MMS = "arg_is_mms"; - private static final String ARG_START_PAGE = "arg_start_page"; - private static final String ARG_SHADOWS = "arg_shadows"; - - private ReactWithAnyEmojiViewModel viewModel; - private Callback callback; - private EmojiPageView emojiPageView; - private KeyboardPageSearchView search; - - private final LifecycleDisposable disposables = new LifecycleDisposable(); - - public static DialogFragment createForMessageRecord(@NonNull MessageRecord messageRecord, int startingPage) { - DialogFragment fragment = new ReactWithAnyEmojiDialogFragment(); - Bundle args = new Bundle(); - - args.putLong(ARG_MESSAGE_ID, messageRecord.getId()); - args.putBoolean(ARG_IS_MMS, messageRecord.isMms()); - args.putInt(ARG_START_PAGE, startingPage); - fragment.setArguments(args); - - return fragment; - } - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - - if (getParentFragment() instanceof Callback) { - callback = (Callback) getParentFragment(); - } else { - callback = (Callback) context; - } - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - - @Override - public @NonNull Dialog onCreateDialog(Bundle savedInstanceState) { - BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState); - dialog.getBehavior().setPeekHeight((int) (getResources().getDisplayMetrics().heightPixels * 0.50)); - - ShapeAppearanceModel shapeAppearanceModel = ShapeAppearanceModel.builder() - .setTopLeftCorner(CornerFamily.ROUNDED, ViewUtil.dpToPx(requireContext(), 18)) - .setTopRightCorner(CornerFamily.ROUNDED, ViewUtil.dpToPx(requireContext(), 18)) - .build(); - - boolean shadows = requireArguments().getBoolean(ARG_SHADOWS, true); - if (!shadows) { - Window window = dialog.getWindow(); - if (window != null) { - window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); - } - } - - return dialog; - } - - @Override - public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.react_with_any_emoji_dialog_fragment, container, false); - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - disposables.bindTo(getViewLifecycleOwner()); - - emojiPageView = view.findViewById(R.id.react_with_any_emoji_page_view); - emojiPageView.initialize(this, this, true); - - search = view.findViewById(R.id.react_with_any_emoji_search); - - initializeViewModel(); - -// EmojiKeyboardPageCategoriesAdapter categoriesAdapter = new EmojiKeyboardPageCategoriesAdapter(key -> { -// scrollTo(key); -// viewModel.selectPage(key); -// }); - - disposables.add(viewModel.getEmojiList().subscribe(pages -> emojiPageView.setList(pages, null))); -// disposables.add(viewModel.getCategories().subscribe(categoriesAdapter::submitList)); -// disposables.add(viewModel.getSelectedKey().subscribe(key -> categoriesRecycler.post(() -> { -// int index = categoriesAdapter.indexOfFirst(EmojiKeyboardPageCategoryMappingModel.class, m -> m.getKey().equals(key)); -// -// if (index != -1) { -// categoriesRecycler.smoothScrollToPosition(index); -// } -// }))); - - search.setCallbacks(new SearchCallbacks()); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - LoaderManager.getInstance(requireActivity()).destroyLoader((int) requireArguments().getLong(ARG_MESSAGE_ID)); - } - - @Override - public void onDismiss(@NonNull DialogInterface dialog) { - super.onDismiss(dialog); - - callback.onReactWithAnyEmojiDialogDismissed(); - } - - private void initializeViewModel() { - Bundle args = requireArguments(); - ReactWithAnyEmojiRepository repository = new ReactWithAnyEmojiRepository(requireContext()); - ReactWithAnyEmojiViewModel.Factory factory = new ReactWithAnyEmojiViewModel.Factory(repository, args.getLong(ARG_MESSAGE_ID), args.getBoolean(ARG_IS_MMS)); - - viewModel = new ViewModelProvider(this, factory).get(ReactWithAnyEmojiViewModel.class); - } - - @Override - public void onEmojiSelected(String emoji) { - viewModel.onEmojiSelected(emoji); - Bundle args = requireArguments(); - MessageId messageId = new MessageId(args.getLong(ARG_MESSAGE_ID), args.getBoolean(ARG_IS_MMS)); - callback.onReactWithAnyEmojiSelected(emoji, messageId); - dismiss(); - } - - @Override - public void onKeyEvent(KeyEvent keyEvent) { - } - - @Override - public void onVariationSelectorStateChanged(boolean open) { } - - public interface Callback { - void onReactWithAnyEmojiDialogDismissed(); - - void onReactWithAnyEmojiSelected(@NonNull String emoji, MessageId messageId); - } - - private class SearchCallbacks implements KeyboardPageSearchView.Callbacks { - @Override - public void onQueryChanged(@NonNull String query) { - boolean hasQuery = !TextUtils.isEmpty(query); - search.enableBackNavigation(hasQuery); - /*if (hasQuery) { - ViewUtil.fadeOut(tabBar, 250, View.INVISIBLE); - } else { - ViewUtil.fadeIn(tabBar, 250); - }*/ - viewModel.onQueryChanged(query); - } - - @Override - public void onNavigationClicked() { - search.clearQuery(); - search.clearFocus(); - ViewUtil.hideKeyboard(requireContext(), requireView()); - } - - @Override - public void onFocusGained() { - ((BottomSheetDialog) requireDialog()).getBehavior().setState(BottomSheetBehavior.STATE_EXPANDED); - } - - @Override - public void onClicked() { } - - @Override - public void onFocusLost() { } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiDialogFragment.kt new file mode 100644 index 0000000000..e1524bb3db --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiDialogFragment.kt @@ -0,0 +1,115 @@ +package org.thoughtcrime.securesms.reactions.any + +import android.app.Dialog +import android.content.Context +import android.content.DialogInterface +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import androidx.emoji2.emojipicker.EmojiPickerView +import androidx.fragment.app.DialogFragment +import androidx.loader.app.LoaderManager +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import network.loki.messenger.R +import org.thoughtcrime.securesms.database.model.MessageId +import org.thoughtcrime.securesms.database.model.MessageRecord + +class ReactWithAnyEmojiDialogFragment : BottomSheetDialogFragment() { + private var callback: Callback? = null + + override fun onAttach(context: Context) { + super.onAttach(context) + + callback = + if (parentFragment is Callback) { + parentFragment as Callback + } else { + context as Callback + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val dialog = BottomSheetDialog(requireContext(), R.style.Theme_Session_BottomSheet) + dialog.behavior.peekHeight = (resources.displayMetrics.heightPixels * 0.8).toInt() + + // dialog.getBehavior().setDraggable(false); + val shadows = requireArguments().getBoolean(ARG_SHADOWS, true) + if (!shadows) { + val window = dialog.window + window?.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + } + + return dialog + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.react_with_any_emoji_dialog_fragment, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + (view.findViewById(R.id.emoji_picker) as EmojiPickerView).setOnEmojiPickedListener{ + onEmojiSelected(it.emoji) + } + } + + override fun onDestroyView() { + super.onDestroyView() + LoaderManager.getInstance(requireActivity()).destroyLoader( + requireArguments().getLong( + ARG_MESSAGE_ID + ).toInt() + ) + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + + callback!!.onReactWithAnyEmojiDialogDismissed() + } + + fun onEmojiSelected(emoji: String) { + val args = requireArguments() + val messageId = MessageId(args.getLong(ARG_MESSAGE_ID), args.getBoolean(ARG_IS_MMS)) + callback!!.onReactWithAnyEmojiSelected(emoji, messageId) + dismiss() + } + + interface Callback { + fun onReactWithAnyEmojiDialogDismissed() + + fun onReactWithAnyEmojiSelected(emoji: String, messageId: MessageId) + } + + companion object { + private const val ARG_MESSAGE_ID = "arg_message_id" + private const val ARG_IS_MMS = "arg_is_mms" + private const val ARG_START_PAGE = "arg_start_page" + private const val ARG_SHADOWS = "arg_shadows" + + fun createForMessageRecord( + messageRecord: MessageRecord, + startingPage: Int + ): DialogFragment { + val fragment: DialogFragment = ReactWithAnyEmojiDialogFragment() + val args = Bundle() + + args.putLong(ARG_MESSAGE_ID, messageRecord.getId()) + args.putBoolean(ARG_IS_MMS, messageRecord.isMms) + args.putInt(ARG_START_PAGE, startingPage) + fragment.arguments = args + + return fragment + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiPage.java b/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiPage.java deleted file mode 100644 index 46d8bbcd80..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiPage.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.thoughtcrime.securesms.reactions.any; - -import androidx.annotation.AttrRes; -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; - -import org.session.libsignal.utilities.guava.Preconditions; - -import java.util.List; -import java.util.Objects; - -/** - * Represents a swipeable page in the ReactWithAnyEmoji dialog fragment, encapsulating any - * {@link ReactWithAnyEmojiPageBlock}s contained on that page. It is assumed that there is at least - * one page present. - * - * This class also exposes several properties based off of that list, in order to allow the ReactWithAny - * bottom sheet to properly lay out its tabs and assign labels as the user moves between pages. - */ -class ReactWithAnyEmojiPage { - - private final List pageBlocks; - - ReactWithAnyEmojiPage(@NonNull List pageBlocks) { - Preconditions.checkArgument(!pageBlocks.isEmpty()); - - this.pageBlocks = pageBlocks; - } - - public @NonNull String getKey() { - return pageBlocks.get(0).getPageModel().getKey(); - } - - public @StringRes int getLabel() { - return pageBlocks.get(0).getLabel(); - } - - public boolean hasEmoji() { - return !pageBlocks.get(0).getPageModel().getEmoji().isEmpty(); - } - - public List getPageBlocks() { - return pageBlocks; - } - - public @AttrRes int getIconAttr() { - return pageBlocks.get(0).getPageModel().getIconAttr(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ReactWithAnyEmojiPage that = (ReactWithAnyEmojiPage) o; - return pageBlocks.equals(that.pageBlocks); - } - - @Override - public int hashCode() { - return Objects.hash(pageBlocks); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiPageBlock.java b/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiPageBlock.java deleted file mode 100644 index d3099d1fa4..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiPageBlock.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.thoughtcrime.securesms.reactions.any; - -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; - -import org.thoughtcrime.securesms.components.emoji.EmojiPageModel; - -import java.util.Objects; - -/** - * Wraps a single "class" of Emojis, be it a predefined category, recents, etc. and provides - * a label for that "class". - */ -class ReactWithAnyEmojiPageBlock { - - private final int label; - private final EmojiPageModel pageModel; - - ReactWithAnyEmojiPageBlock(@StringRes int label, @NonNull EmojiPageModel pageModel) { - this.label = label; - this.pageModel = pageModel; - } - - public @StringRes int getLabel() { - return label; - } - - public EmojiPageModel getPageModel() { - return pageModel; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ReactWithAnyEmojiPageBlock that = (ReactWithAnyEmojiPageBlock) o; - return label == that.label && - pageModel.getIconAttr() == that.pageModel.getIconAttr() && - Objects.equals(pageModel.getEmoji(), that.pageModel.getEmoji()); - } - - @Override - public int hashCode() { - return Objects.hash(label, pageModel.getEmoji()); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiRepository.java b/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiRepository.java deleted file mode 100644 index bab8591cb6..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiRepository.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.thoughtcrime.securesms.reactions.any; - -import android.content.Context; - -import androidx.annotation.NonNull; - -import com.annimon.stream.Stream; - -import org.session.libsignal.utilities.Log; -import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel; -import org.thoughtcrime.securesms.emoji.EmojiCategory; -import org.thoughtcrime.securesms.emoji.EmojiSource; - -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -import network.loki.messenger.R; - -final class ReactWithAnyEmojiRepository { - - private static final String TAG = Log.tag(ReactWithAnyEmojiRepository.class); - - private final Context context; - private final RecentEmojiPageModel recentEmojiPageModel; - private final List emojiPages; - - ReactWithAnyEmojiRepository(@NonNull Context context) { - this.context = context; - this.recentEmojiPageModel = new RecentEmojiPageModel(context); - this.emojiPages = new LinkedList<>(); - - emojiPages.addAll(Stream.of(EmojiSource.getLatest().getDisplayPages()) - .map(page -> new ReactWithAnyEmojiPage(Collections.singletonList(new ReactWithAnyEmojiPageBlock(EmojiCategory.getCategoryLabel(page.getIconAttr()), page)))) - .toList()); - } - - List getEmojiPageModels() { - List pages = new LinkedList<>(); - - pages.add(new ReactWithAnyEmojiPage(Collections.singletonList(new ReactWithAnyEmojiPageBlock(R.string.emojiCategoryRecentlyUsed, recentEmojiPageModel)))); - pages.addAll(emojiPages); - - return pages; - } - - void addEmojiToMessage(@NonNull String emoji) { - recentEmojiPageModel.onCodePointSelected(emoji); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiViewModel.java deleted file mode 100644 index 0ac6cf18f4..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiViewModel.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.thoughtcrime.securesms.reactions.any; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.lifecycle.ViewModel; -import androidx.lifecycle.ViewModelProvider; - -import com.annimon.stream.Stream; - -import org.session.libsession.messaging.MessagingModuleConfiguration; -import org.thoughtcrime.securesms.components.emoji.EmojiPageModel; -import org.thoughtcrime.securesms.components.emoji.EmojiPageViewGridAdapter; -import org.thoughtcrime.securesms.database.model.MessageId; -import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchRepository; -import org.thoughtcrime.securesms.reactions.ReactionsRepository; -import org.thoughtcrime.securesms.util.adapter.mapping.MappingModelList; - -import java.util.List; - -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.subjects.BehaviorSubject; - -public final class ReactWithAnyEmojiViewModel extends ViewModel { - - private static final int SEARCH_LIMIT = 40; - private final EmojiSearchRepository emojiSearchRepository; - - private final ReactWithAnyEmojiRepository repository; - private final Observable emojiList; - private final BehaviorSubject searchResults; - - private ReactWithAnyEmojiViewModel(@NonNull ReactWithAnyEmojiRepository repository, - long messageId, - boolean isMms, - @NonNull EmojiSearchRepository emojiSearchRepository) - { - this.repository = repository; - this.emojiSearchRepository = emojiSearchRepository; - this.searchResults = BehaviorSubject.createDefault(new EmojiSearchResult()); - - Observable> emojiPages = new ReactionsRepository().getReactions(new MessageId(messageId, isMms)) - .map(thisMessagesReactions -> repository.getEmojiPageModels()); - - Observable emojiList = emojiPages.map(pages -> { - MappingModelList list = new MappingModelList(); - - for (ReactWithAnyEmojiPage page : pages) { - String key = page.getKey(); - for (ReactWithAnyEmojiPageBlock block : page.getPageBlocks()) { - list.add(new EmojiPageViewGridAdapter.EmojiHeader(key, block.getLabel())); - list.addAll(toMappingModels(block.getPageModel())); - } - } - - return list; - }); - - this.emojiList = Observable.combineLatest(emojiList, searchResults.distinctUntilChanged(), (all, search) -> { - if (search.query.isEmpty()) { - return all; - } else { - if (search.model.getDisplayEmoji().isEmpty()) { - return MappingModelList.singleton(new EmojiPageViewGridAdapter.EmojiNoResultsModel()); - } - return toMappingModels(search.model); - } - }); - } - - @NonNull Observable getEmojiList() { - return emojiList.observeOn(AndroidSchedulers.mainThread()); - } - - void onEmojiSelected(@NonNull String emoji) { - repository.addEmojiToMessage(emoji); - } - - public void onQueryChanged(String query) { - emojiSearchRepository.submitQuery(query, SEARCH_LIMIT, m -> searchResults.onNext(new EmojiSearchResult(query, m))); - } - - private static @NonNull MappingModelList toMappingModels(@NonNull EmojiPageModel model) { - return Stream.of(model.getDisplayEmoji()) - .map(e -> new EmojiPageViewGridAdapter.EmojiModel(model.getKey(), e)) - .collect(MappingModelList.collect()); - } - - private static class EmojiSearchResult { - private final String query; - private final EmojiPageModel model; - - private EmojiSearchResult(@NonNull String query, @Nullable EmojiPageModel model) { - this.query = query; - this.model = model; - } - - public EmojiSearchResult() { - this("", null); - } - } - - static class Factory implements ViewModelProvider.Factory { - - private final ReactWithAnyEmojiRepository repository; - private final long messageId; - private final boolean isMms; - - Factory(@NonNull ReactWithAnyEmojiRepository repository, long messageId, boolean isMms) { - this.repository = repository; - this.messageId = messageId; - this.isMms = isMms; - } - - @Override - public @NonNull T create(@NonNull Class modelClass) { - //noinspection ConstantConditions - return modelClass.cast(new ReactWithAnyEmojiViewModel(repository, messageId, isMms, new EmojiSearchRepository(MessagingModuleConfiguration.getShared().getContext()))); - } - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/EmojiUtils.kt b/app/src/main/java/org/thoughtcrime/securesms/util/EmojiUtils.kt new file mode 100644 index 0000000000..63efbba60a --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/util/EmojiUtils.kt @@ -0,0 +1,127 @@ +package org.thoughtcrime.securesms.util + +import android.text.Spannable +import androidx.emoji2.text.EmojiCompat +import androidx.emoji2.text.EmojiCompat.LOAD_STATE_SUCCEEDED +import androidx.emoji2.text.EmojiSpan +import kotlin.math.max +import kotlin.math.min + +object EmojiUtils { + + /** + * Checks if a Unicode codepoint is considered an emoji. + */ + private fun isEmoji(codePoint: Int): Boolean { + return (codePoint >= 0x1F000 && codePoint <= 0x1FFFF) || // Most emojis live here + (codePoint >= 0x2000 && codePoint <= 0x2BFF) || // Includes arrows, symbols + (codePoint >= 0x2300 && codePoint <= 0x23FF) || // Technical misc + (codePoint >= 0x2600 && codePoint <= 0x27EF) || // Dingbats, misc symbols + (codePoint >= 0x2900 && codePoint <= 0x297F) || // Supplemental arrows + (codePoint >= 0x2B00 && codePoint <= 0x2BFF) || // More symbols + (codePoint >= 0x3000 && codePoint <= 0x303F) || // CJK symbols + (codePoint >= 0x3200 && codePoint <= 0x32FF) || // Enclosed CJK + (codePoint >= 0xFE00 && codePoint <= 0xFE0F) || // Variation selectors + (codePoint >= 0x1F900 && codePoint <= 0x1F9FF) || // Supplemental symbols + (codePoint >= 0x1FA70 && codePoint <= 0x1FAFF) // Extended symbols + } + + /** + * Returns true if the text (ignoring whitespace) is only emojis. + */ + private fun isAllEmojis(text: CharSequence?): Boolean { + if (text == null || text.length == 0) return false + val len = text.length + var emojiCount = 0 + var offset = 0 + while (offset < len) { + val codePoint = Character.codePointAt(text, offset) + if (!Character.isWhitespace(codePoint)) { + if (!isEmoji(codePoint)) { + return false + } + emojiCount++ + } + offset += Character.charCount(codePoint) + } + return emojiCount > 0 + } + + /** + * Counts the number of emoji codepoints in the text (ignoring whitespace). + */ + private fun countEmojis(text: CharSequence?): Int { + if (text == null || text.length == 0) return 0 + val len = text.length + var emojiCount = 0 + var offset = 0 + while (offset < len) { + val codePoint = Character.codePointAt(text, offset) + if (!Character.isWhitespace(codePoint) && isEmoji(codePoint)) { + emojiCount++ + } + offset += Character.charCount(codePoint) + } + return emojiCount + } + + /** + * Checks if the given text only contains emojis by going through the spans + * @param text + * @return true if the text only contains emojis, false otherwise + */ + private fun isTextOnlyEmojiUsingSpans(text: Spannable?): Boolean { + if (text == null || text.length == 0) { + // Depending on how you define "only emoji," empty text might be false or true. + return false + } + + val length = text.length + val spans = text.getSpans(0, length, EmojiSpan::class.java) + + // If there are no spans at all, but the text isn't empty, it can't be all emoji + if (spans == null || spans.size == 0) { + return false + } + + // Track coverage for each character + val coverage = BooleanArray(length) + for (span in spans) { + val start = max(0.0, text.getSpanStart(span).toDouble()).toInt() + val end = min(length.toDouble(), text.getSpanEnd(span).toDouble()).toInt() + + for (i in start.. + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/conversation_reaction_scrubber.xml b/app/src/main/res/layout/conversation_reaction_scrubber.xml index 61067952a1..ce4c2798da 100644 --- a/app/src/main/res/layout/conversation_reaction_scrubber.xml +++ b/app/src/main/res/layout/conversation_reaction_scrubber.xml @@ -5,6 +5,8 @@ android:id="@+id/conversation_reaction_scrubber" android:layout_width="match_parent" android:layout_height="match_parent" + android:clipToPadding="false" + android:clipChildren="false" android:background="@color/conversation_overlay_scrim" android:visibility="gone" tools:visibility="visible"> @@ -38,112 +40,115 @@ - - - + + + tools:text="🩷" /> - + tools:text="🩷" /> - + tools:text="🩷" /> - + tools:text="🩷" /> - + tools:text="🩷" /> - + tools:text="🩷" /> - + tools:alpha="100" + tools:translationY="0dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/emoji_display_item_grid.xml b/app/src/main/res/layout/emoji_display_item_grid.xml deleted file mode 100644 index e1729197e7..0000000000 --- a/app/src/main/res/layout/emoji_display_item_grid.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/emoji_grid_header.xml b/app/src/main/res/layout/emoji_grid_header.xml deleted file mode 100644 index 34a6a55a1f..0000000000 --- a/app/src/main/res/layout/emoji_grid_header.xml +++ /dev/null @@ -1,13 +0,0 @@ - - diff --git a/app/src/main/res/layout/emoji_grid_layout.xml b/app/src/main/res/layout/emoji_grid_layout.xml deleted file mode 100644 index ccbd5c85df..0000000000 --- a/app/src/main/res/layout/emoji_grid_layout.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/emoji_grid_no_results.xml b/app/src/main/res/layout/emoji_grid_no_results.xml deleted file mode 100644 index fe70b2b4c7..0000000000 --- a/app/src/main/res/layout/emoji_grid_no_results.xml +++ /dev/null @@ -1,8 +0,0 @@ - - diff --git a/app/src/main/res/layout/emoji_text_display_item_grid.xml b/app/src/main/res/layout/emoji_text_display_item_grid.xml deleted file mode 100644 index 32555bfe65..0000000000 --- a/app/src/main/res/layout/emoji_text_display_item_grid.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/emoji_variation_selector.xml b/app/src/main/res/layout/emoji_variation_selector.xml deleted file mode 100644 index faeaed3394..0000000000 --- a/app/src/main/res/layout/emoji_variation_selector.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/emoji_variation_selector_item.xml b/app/src/main/res/layout/emoji_variation_selector_item.xml deleted file mode 100644 index 5fb46b900f..0000000000 --- a/app/src/main/res/layout/emoji_variation_selector_item.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/keyboard_pager_search_bar.xml b/app/src/main/res/layout/keyboard_pager_search_bar.xml index 3b54712d66..ed162cf68c 100644 --- a/app/src/main/res/layout/keyboard_pager_search_bar.xml +++ b/app/src/main/res/layout/keyboard_pager_search_bar.xml @@ -62,7 +62,7 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/labeled_edit_text_default.xml b/app/src/main/res/layout/labeled_edit_text_default.xml deleted file mode 100644 index 435f2459dc..0000000000 --- a/app/src/main/res/layout/labeled_edit_text_default.xml +++ /dev/null @@ -1,14 +0,0 @@ - - diff --git a/app/src/main/res/layout/react_with_any_emoji_dialog_fragment.xml b/app/src/main/res/layout/react_with_any_emoji_dialog_fragment.xml index 9bb0488c6f..1e784712e1 100644 --- a/app/src/main/res/layout/react_with_any_emoji_dialog_fragment.xml +++ b/app/src/main/res/layout/react_with_any_emoji_dialog_fragment.xml @@ -1,55 +1,10 @@ - + android:nestedScrollingEnabled="true" + app:emojiGridColumns="9" /> - - - - - - - - - - - - diff --git a/app/src/main/res/layout/reactions_bottom_sheet_dialog_fragment.xml b/app/src/main/res/layout/reactions_bottom_sheet_dialog_fragment.xml index 065ba5a622..7f8213ce61 100644 --- a/app/src/main/res/layout/reactions_bottom_sheet_dialog_fragment.xml +++ b/app/src/main/res/layout/reactions_bottom_sheet_dialog_fragment.xml @@ -18,6 +18,7 @@ app:tabMinWidth="48dp" app:tabMode="scrollable" app:tabPaddingEnd="5dp" + app:tabRippleColor="@color/transparent" app:tabSelectedTextColor="?android:textColorPrimary" app:tabTextColor="?android:textColorTertiary" app:tabPaddingStart="5dp" /> diff --git a/app/src/main/res/layout/reactions_bottom_sheet_dialog_fragment_recycler_header.xml b/app/src/main/res/layout/reactions_bottom_sheet_dialog_fragment_recycler_header.xml index 09c9498940..330d1e2fcb 100644 --- a/app/src/main/res/layout/reactions_bottom_sheet_dialog_fragment_recycler_header.xml +++ b/app/src/main/res/layout/reactions_bottom_sheet_dialog_fragment_recycler_header.xml @@ -15,15 +15,17 @@ android:layout_width="match_parent" android:layout_marginHorizontal="@dimen/medium_spacing" android:gravity="center_vertical"> - + + android:layout_height="wrap_content" + android:foreground="@drawable/reaction_pill_dialog_foreground" + android:paddingVertical="2dp" + android:paddingHorizontal="@dimen/small_spacing"> - + android:textSize="11sp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + tools:text="🩷"/> + android:layout_height="6dp" /> + android:layout_height="wrap_content" + android:foreground="@drawable/reaction_pill_dialog_foreground" + android:paddingVertical="@dimen/very_small_spacing" + android:paddingHorizontal="@dimen/small_spacing"> - + android:textSize="@dimen/medium_font_size" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + tools:text="🩷"/> + android:layout_height="10dp" /> - \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 36aef5d685..e9cd6eddd5 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -8,6 +8,7 @@ 16sp 20sp 26sp + 26sp 18sp diff --git a/gradle.properties b/gradle.properties index 4a2a35d2f1..d16edfd73b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,6 +21,7 @@ kspVersion=2.1.10-1.0.31 navVersion=2.8.0-beta05 android.useAndroidX=true appcompatVersion=1.7.0 +emoji2Version=1.5.0 coreVersion=1.13.1 coroutinesVersion=1.9.0 curve25519Version=0.6.0