Commit 0c9dbf79 authored by Stan Hu's avatar Stan Hu

Merge branch 'brodock/tanuki_emoji' into 'master'

Switch from `Gemojione` to `TanukiEmoji`

See merge request gitlab-org/gitlab!68787
parents 1e7c0d24 d229bbf9
......@@ -290,7 +290,7 @@ gem 'autoprefixer-rails', '10.2.5.1'
gem 'terser', '1.0.2'
gem 'addressable', '~> 2.8'
gem 'gemojione', '~> 3.3'
gem 'tanuki_emoji', '~> 0.5'
gem 'gon', '~> 6.4.0'
gem 'request_store', '~> 1.5'
gem 'base32', '~> 0.3.0'
......@@ -348,6 +348,8 @@ group :development do
# thin instead webrick
gem 'thin', '~> 1.8.0'
gem 'sprite-factory', '~> 1.7'
end
group :development, :test do
......
......@@ -436,8 +436,6 @@ GEM
ruby-progressbar (~> 1.4)
fuzzyurl (0.9.0)
gemoji (3.0.1)
gemojione (3.3.0)
json
get_process_mem (0.2.5)
ffi (~> 1.0)
gettext (3.3.6)
......@@ -1216,6 +1214,7 @@ GEM
spring (2.1.1)
spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
sprite-factory (1.7.1)
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
......@@ -1246,6 +1245,7 @@ GEM
sys-filesystem (1.1.9)
ffi
sysexits (1.2.0)
tanuki_emoji (0.5.0)
temple (0.8.2)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
......@@ -1454,7 +1454,6 @@ DEPENDENCIES
fog-rackspace (~> 0.1.1)
fugit (~> 1.2.1)
fuubar (~> 2.2.0)
gemojione (~> 3.3)
gettext (~> 3.3)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
......@@ -1622,11 +1621,13 @@ DEPENDENCIES
spamcheck (~> 0.1.0)
spring (~> 2.1.0)
spring-commands-rspec (~> 1.0.4)
sprite-factory (~> 1.7)
sprockets (~> 3.7.0)
sshkey (~> 2.0)
stackprof (~> 0.2.15)
state_machines-activerecord (~> 0.8.0)
sys-filesystem (~> 1.1.6)
tanuki_emoji (~> 0.5)
terser (= 1.0.2)
test-prof (~> 1.0.7)
test_file_finder (~> 0.1.3)
......
......@@ -9,6 +9,7 @@ let emojiMap = null;
let validEmojiNames = null;
export const FALLBACK_EMOJI_KEY = 'grey_question';
// Keep the version in sync with `lib/gitlab/emoji.rb`
export const EMOJI_VERSION = '1';
const isLocalStorageAvailable = AccessorUtilities.canUseLocalStorage();
......
......@@ -40,7 +40,7 @@ class AwardEmojisFinder
def validate_name_param
return unless params[:name]
raise ArgumentError, 'Invalid name param' unless params[:name].to_s.in?(Gitlab::Emoji.emojis_names)
raise ArgumentError, 'Invalid name param' unless TanukiEmoji.find_by_alpha_code(params[:name].to_s)
end
def validate_awarded_by_param
......
# frozen_string_literal: true
module EmojiHelper
def emoji_icon(*args)
raw Gitlab::Emoji.gl_emoji_tag(*args)
def emoji_icon(emoji_name, *options)
emoji = TanukiEmoji.find_by_alpha_code(emoji_name)
raw Gitlab::Emoji.gl_emoji_tag(emoji, *options)
end
end
......@@ -7,7 +7,8 @@ module ReminderEmailsHelper
s_('InviteReminderEmail|Invitation pending')
when 1
if format == :html
s_('InviteReminderEmail|Hey there %{wave_emoji}').html_safe % { wave_emoji: Gitlab::Emoji.gl_emoji_tag('wave') }
wave_emoji_tag = Gitlab::Emoji.gl_emoji_tag(TanukiEmoji.find_by_alpha_code('wave'))
s_('InviteReminderEmail|Hey there %{wave_emoji}').html_safe % { wave_emoji: wave_emoji_tag }
else
s_('InviteReminderEmail|Hey there!')
end
......
......@@ -14,7 +14,7 @@ class AwardEmoji < ApplicationRecord
validates :user, presence: true
validates :awardable, presence: true, unless: :importing?
validates :name, presence: true, inclusion: { in: Gitlab::Emoji.emojis_names }
validates :name, presence: true, 'gitlab/emoji_name': true
validates :name, uniqueness: { scope: [:user, :awardable_type, :awardable_id] }, unless: -> { ghost_user? || importing? }
participant :user
......
......@@ -31,7 +31,7 @@ class CustomEmoji < ApplicationRecord
private
def valid_emoji_name
if Gitlab::Emoji.emoji_exists?(name)
if TanukiEmoji.find_by_alpha_code(name)
errors.add(:name, _('%{name} is already being used for another emoji') % { name: self.name })
end
end
......
......@@ -22,7 +22,7 @@ class UserStatus < ApplicationRecord
enum availability: { not_set: 0, busy: 1 }
validates :user, presence: true
validates :emoji, inclusion: { in: Gitlab::Emoji.emojis_names }
validates :emoji, 'gitlab/emoji_name': true
validates :message, length: { maximum: 100 }, allow_blank: true
scope :scheduled_for_cleanup, -> { where(arel_table[:clear_status_at].lteq(Time.current)) }
......
......@@ -4,24 +4,24 @@ class AwardEmojiPresenter < Gitlab::View::Presenter::Delegated
presents ::AwardEmoji, as: :award_emoji
def description
as_emoji['description']
as_emoji&.description
end
def unicode
as_emoji['unicode']
as_emoji&.hex
end
def emoji
as_emoji['moji']
as_emoji&.codepoints
end
def unicode_version
Gitlab::Emoji.emoji_unicode_version(award_emoji.name)
as_emoji&.unicode_version
end
private
def as_emoji
@emoji ||= Gitlab::Emoji.emojis[award_emoji.name] || {}
@emoji ||= TanukiEmoji.find_by_alpha_code(award_emoji.name)
end
end
......@@ -14,7 +14,7 @@ module AwardEmojis
private
def normalize_name(name)
Gitlab::Emoji.normalize_emoji_name(name)
TanukiEmoji.find_by_alpha_code(name)&.name || name
end
# Provide more error state data than what BaseService allows.
......
# frozen_string_literal: true
# Gitlab::EmojiNameValidator
#
# Validates that the provided value matches an indexed emoji alpha code
#
# @example Usage
# class AwardEmoji < ApplicationRecord
# validate :name, 'gitlab/emoji_name': true
# end
module Gitlab
class EmojiNameValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless TanukiEmoji.find_by_alpha_code(value.to_s)
record.errors.add(attribute, (options[:message] || 'is not a valid emoji name'))
end
end
end
end
......@@ -199,7 +199,7 @@ module Gitlab
config.assets.enabled = true
# Support legacy unicode file named img emojis, `1F939.png`
config.assets.paths << Gemojione.images_path
config.assets.paths << TanukiEmoji.images_path
config.assets.paths << "#{config.root}/vendor/assets/fonts"
config.assets.precompile << "application_utilities.css"
......
require './spec/support/sidekiq_middleware'
Gitlab::Seeder.quiet do
EMOJI = Gitlab::Emoji.emojis.keys
def seed_award_emoji(klass)
klass.order(Gitlab::Database.random).limit(klass.count / 2).each do |awardable|
awardable.project.authorized_users.where('project_authorizations.access_level > ?', Gitlab::Access::GUEST).sample(2).each do |user|
AwardEmojis::AddService.new(awardable, EMOJI.sample, user).execute
AwardEmojis::AddService.new(awardable, TanukiEmoji.index.all.sample.name, user).execute
awardable.notes.user.sample(2).each do |note|
AwardEmojis::AddService.new(note, EMOJI.sample, user).execute
AwardEmojis::AddService.new(note, TanukiEmoji.index.all.sample.name, user).execute
end
print '.'
......
{
"100": "6.0",
"1234": "6.0",
"grinning": "6.1",
"grin": "6.0",
"joy": "6.0",
"rofl": "9.0",
"rolling_on_the_floor_laughing": "9.0",
"smiley": "6.0",
"smile": "6.0",
"sweat_smile": "6.0",
"laughing": "6.0",
"satisfied": "6.0",
"wink": "6.0",
"blush": "6.0",
"yum": "6.0",
"sunglasses": "6.0",
"heart_eyes": "6.0",
"kissing_heart": "6.0",
"kissing": "6.1",
"kissing_smiling_eyes": "6.1",
"kissing_closed_eyes": "6.0",
"relaxed": "1.1",
"slight_smile": "7.0",
"slightly_smiling_face": "7.0",
"hugging": "8.0",
"hugging_face": "8.0",
"thinking": "8.0",
"thinking_face": "8.0",
"neutral_face": "6.0",
"expressionless": "6.1",
"no_mouth": "6.0",
"rolling_eyes": "8.0",
"face_with_rolling_eyes": "8.0",
"smirk": "6.0",
"persevere": "6.0",
"disappointed_relieved": "6.0",
"open_mouth": "6.1",
"zipper_mouth": "8.0",
"zipper_mouth_face": "8.0",
"hushed": "6.1",
"sleepy": "6.0",
"tired_face": "6.0",
"sleeping": "6.1",
"relieved": "6.0",
"nerd": "8.0",
"nerd_face": "8.0",
"stuck_out_tongue": "6.1",
"stuck_out_tongue_winking_eye": "6.0",
"stuck_out_tongue_closed_eyes": "6.0",
"drooling_face": "9.0",
"drool": "9.0",
"unamused": "6.0",
"sweat": "6.0",
"pensive": "6.0",
"confused": "6.1",
"upside_down": "8.0",
"upside_down_face": "8.0",
"money_mouth": "8.0",
"money_mouth_face": "8.0",
"astonished": "6.0",
"frowning2": "1.1",
"white_frowning_face": "1.1",
"slight_frown": "7.0",
"slightly_frowning_face": "7.0",
"confounded": "6.0",
"disappointed": "6.0",
"worried": "6.1",
"triumph": "6.0",
"cry": "6.0",
"sob": "6.0",
"frowning": "6.1",
"anguished": "6.1",
"fearful": "6.0",
"weary": "6.0",
"grimacing": "6.1",
"cold_sweat": "6.0",
"scream": "6.0",
"flushed": "6.0",
"dizzy_face": "6.0",
"rage": "6.0",
"angry": "6.0",
"innocent": "6.0",
"cowboy": "9.0",
"face_with_cowboy_hat": "9.0",
"clown": "9.0",
"clown_face": "9.0",
"lying_face": "9.0",
"liar": "9.0",
"mask": "6.0",
"thermometer_face": "8.0",
"face_with_thermometer": "8.0",
"head_bandage": "8.0",
"face_with_head_bandage": "8.0",
"nauseated_face": "9.0",
"sick": "9.0",
"sneezing_face": "9.0",
"sneeze": "9.0",
"smiling_imp": "6.0",
"imp": "6.0",
"japanese_ogre": "6.0",
"japanese_goblin": "6.0",
"skull": "6.0",
"skeleton": "6.0",
"skull_crossbones": "1.1",
"skull_and_crossbones": "1.1",
"ghost": "6.0",
"alien": "6.0",
"space_invader": "6.0",
"robot": "8.0",
"robot_face": "8.0",
"poop": "6.0",
"shit": "6.0",
"hankey": "6.0",
"poo": "6.0",
"smiley_cat": "6.0",
"smile_cat": "6.0",
"joy_cat": "6.0",
"heart_eyes_cat": "6.0",
"smirk_cat": "6.0",
"kissing_cat": "6.0",
"scream_cat": "6.0",
"crying_cat_face": "6.0",
"pouting_cat": "6.0",
"see_no_evil": "6.0",
"hear_no_evil": "6.0",
"speak_no_evil": "6.0",
"boy": "6.0",
"boy_tone1": "8.0",
"boy_tone2": "8.0",
"boy_tone3": "8.0",
"boy_tone4": "8.0",
"boy_tone5": "8.0",
"girl": "6.0",
"girl_tone1": "8.0",
"girl_tone2": "8.0",
"girl_tone3": "8.0",
"girl_tone4": "8.0",
"girl_tone5": "8.0",
"man": "6.0",
"man_tone1": "8.0",
"man_tone2": "8.0",
"man_tone3": "8.0",
"man_tone4": "8.0",
"man_tone5": "8.0",
"woman": "6.0",
"woman_tone1": "8.0",
"woman_tone2": "8.0",
"woman_tone3": "8.0",
"woman_tone4": "8.0",
"woman_tone5": "8.0",
"older_man": "6.0",
"older_man_tone1": "8.0",
"older_man_tone2": "8.0",
"older_man_tone3": "8.0",
"older_man_tone4": "8.0",
"older_man_tone5": "8.0",
"older_woman": "6.0",
"grandma": "6.0",
"older_woman_tone1": "8.0",
"grandma_tone1": "8.0",
"older_woman_tone2": "8.0",
"grandma_tone2": "8.0",
"older_woman_tone3": "8.0",
"grandma_tone3": "8.0",
"older_woman_tone4": "8.0",
"grandma_tone4": "8.0",
"older_woman_tone5": "8.0",
"grandma_tone5": "8.0",
"baby": "6.0",
"baby_tone1": "8.0",
"baby_tone2": "8.0",
"baby_tone3": "8.0",
"baby_tone4": "8.0",
"baby_tone5": "8.0",
"angel": "6.0",
"angel_tone1": "8.0",
"angel_tone2": "8.0",
"angel_tone3": "8.0",
"angel_tone4": "8.0",
"angel_tone5": "8.0",
"cop": "6.0",
"cop_tone1": "8.0",
"cop_tone2": "8.0",
"cop_tone3": "8.0",
"cop_tone4": "8.0",
"cop_tone5": "8.0",
"spy": "7.0",
"sleuth_or_spy": "7.0",
"spy_tone1": "8.0",
"sleuth_or_spy_tone1": "8.0",
"spy_tone2": "8.0",
"sleuth_or_spy_tone2": "8.0",
"spy_tone3": "8.0",
"sleuth_or_spy_tone3": "8.0",
"spy_tone4": "8.0",
"sleuth_or_spy_tone4": "8.0",
"spy_tone5": "8.0",
"sleuth_or_spy_tone5": "8.0",
"guardsman": "6.0",
"guardsman_tone1": "8.0",
"guardsman_tone2": "8.0",
"guardsman_tone3": "8.0",
"guardsman_tone4": "8.0",
"guardsman_tone5": "8.0",
"construction_worker": "6.0",
"construction_worker_tone1": "8.0",
"construction_worker_tone2": "8.0",
"construction_worker_tone3": "8.0",
"construction_worker_tone4": "8.0",
"construction_worker_tone5": "8.0",
"man_with_turban": "6.0",
"man_with_turban_tone1": "8.0",
"man_with_turban_tone2": "8.0",
"man_with_turban_tone3": "8.0",
"man_with_turban_tone4": "8.0",
"man_with_turban_tone5": "8.0",
"person_with_blond_hair": "6.0",
"person_with_blond_hair_tone1": "8.0",
"person_with_blond_hair_tone2": "8.0",
"person_with_blond_hair_tone3": "8.0",
"person_with_blond_hair_tone4": "8.0",
"person_with_blond_hair_tone5": "8.0",
"santa": "6.0",
"santa_tone1": "8.0",
"santa_tone2": "8.0",
"santa_tone3": "8.0",
"santa_tone4": "8.0",
"santa_tone5": "8.0",
"mrs_claus": "9.0",
"mother_christmas": "9.0",
"mrs_claus_tone1": "9.0",
"mother_christmas_tone1": "9.0",
"mrs_claus_tone2": "9.0",
"mother_christmas_tone2": "9.0",
"mrs_claus_tone3": "9.0",
"mother_christmas_tone3": "9.0",
"mrs_claus_tone4": "9.0",
"mother_christmas_tone4": "9.0",
"mrs_claus_tone5": "9.0",
"mother_christmas_tone5": "9.0",
"princess": "6.0",
"princess_tone1": "8.0",
"princess_tone2": "8.0",
"princess_tone3": "8.0",
"princess_tone4": "8.0",
"princess_tone5": "8.0",
"prince": "9.0",
"prince_tone1": "9.0",
"prince_tone2": "9.0",
"prince_tone3": "9.0",
"prince_tone4": "9.0",
"prince_tone5": "9.0",
"bride_with_veil": "6.0",
"bride_with_veil_tone1": "8.0",
"bride_with_veil_tone2": "8.0",
"bride_with_veil_tone3": "8.0",
"bride_with_veil_tone4": "8.0",
"bride_with_veil_tone5": "8.0",
"man_in_tuxedo": "9.0",
"man_in_tuxedo_tone1": "9.0",
"tuxedo_tone1": "9.0",
"man_in_tuxedo_tone2": "9.0",
"tuxedo_tone2": "9.0",
"man_in_tuxedo_tone3": "9.0",
"tuxedo_tone3": "9.0",
"man_in_tuxedo_tone4": "9.0",
"tuxedo_tone4": "9.0",
"man_in_tuxedo_tone5": "9.0",
"tuxedo_tone5": "9.0",
"pregnant_woman": "9.0",
"expecting_woman": "9.0",
"pregnant_woman_tone1": "9.0",
"expecting_woman_tone1": "9.0",
"pregnant_woman_tone2": "9.0",
"expecting_woman_tone2": "9.0",
"pregnant_woman_tone3": "9.0",
"expecting_woman_tone3": "9.0",
"pregnant_woman_tone4": "9.0",
"expecting_woman_tone4": "9.0",
"pregnant_woman_tone5": "9.0",
"expecting_woman_tone5": "9.0",
"man_with_gua_pi_mao": "6.0",
"man_with_gua_pi_mao_tone1": "8.0",
"man_with_gua_pi_mao_tone2": "8.0",
"man_with_gua_pi_mao_tone3": "8.0",
"man_with_gua_pi_mao_tone4": "8.0",
"man_with_gua_pi_mao_tone5": "8.0",
"person_frowning": "6.0",
"person_frowning_tone1": "8.0",
"person_frowning_tone2": "8.0",
"person_frowning_tone3": "8.0",
"person_frowning_tone4": "8.0",
"person_frowning_tone5": "8.0",
"person_with_pouting_face": "6.0",
"person_with_pouting_face_tone1": "8.0",
"person_with_pouting_face_tone2": "8.0",
"person_with_pouting_face_tone3": "8.0",
"person_with_pouting_face_tone4": "8.0",
"person_with_pouting_face_tone5": "8.0",
"no_good": "6.0",
"no_good_tone1": "8.0",
"no_good_tone2": "8.0",
"no_good_tone3": "8.0",
"no_good_tone4": "8.0",
"no_good_tone5": "8.0",
"ok_woman": "6.0",
"ok_woman_tone1": "8.0",
"ok_woman_tone2": "8.0",
"ok_woman_tone3": "8.0",
"ok_woman_tone4": "8.0",
"ok_woman_tone5": "8.0",
"information_desk_person": "6.0",
"information_desk_person_tone1": "8.0",
"information_desk_person_tone2": "8.0",
"information_desk_person_tone3": "8.0",
"information_desk_person_tone4": "8.0",
"information_desk_person_tone5": "8.0",
"raising_hand": "6.0",
"raising_hand_tone1": "8.0",
"raising_hand_tone2": "8.0",
"raising_hand_tone3": "8.0",
"raising_hand_tone4": "8.0",
"raising_hand_tone5": "8.0",
"bow": "6.0",
"bow_tone1": "8.0",
"bow_tone2": "8.0",
"bow_tone3": "8.0",
"bow_tone4": "8.0",
"bow_tone5": "8.0",
"face_palm": "9.0",
"facepalm": "9.0",
"face_palm_tone1": "9.0",
"facepalm_tone1": "9.0",
"face_palm_tone2": "9.0",
"facepalm_tone2": "9.0",
"face_palm_tone3": "9.0",
"facepalm_tone3": "9.0",
"face_palm_tone4": "9.0",
"facepalm_tone4": "9.0",
"face_palm_tone5": "9.0",
"facepalm_tone5": "9.0",
"shrug": "9.0",
"shrug_tone1": "9.0",
"shrug_tone2": "9.0",
"shrug_tone3": "9.0",
"shrug_tone4": "9.0",
"shrug_tone5": "9.0",
"massage": "6.0",
"massage_tone1": "8.0",
"massage_tone2": "8.0",
"massage_tone3": "8.0",
"massage_tone4": "8.0",
"massage_tone5": "8.0",
"haircut": "6.0",
"haircut_tone1": "8.0",
"haircut_tone2": "8.0",
"haircut_tone3": "8.0",
"haircut_tone4": "8.0",
"haircut_tone5": "8.0",
"walking": "6.0",
"walking_tone1": "8.0",
"walking_tone2": "8.0",
"walking_tone3": "8.0",
"walking_tone4": "8.0",
"walking_tone5": "8.0",
"runner": "6.0",
"runner_tone1": "8.0",
"runner_tone2": "8.0",
"runner_tone3": "8.0",
"runner_tone4": "8.0",
"runner_tone5": "8.0",
"dancer": "6.0",
"dancer_tone1": "8.0",
"dancer_tone2": "8.0",
"dancer_tone3": "8.0",
"dancer_tone4": "8.0",
"dancer_tone5": "8.0",
"man_dancing": "9.0",
"male_dancer": "9.0",
"man_dancing_tone1": "9.0",
"male_dancer_tone1": "9.0",
"man_dancing_tone2": "9.0",
"male_dancer_tone2": "9.0",
"man_dancing_tone3": "9.0",
"male_dancer_tone3": "9.0",
"man_dancing_tone4": "9.0",
"male_dancer_tone4": "9.0",
"man_dancing_tone5": "9.0",
"male_dancer_tone5": "9.0",
"dancers": "6.0",
"levitate": "7.0",
"man_in_business_suit_levitating": "7.0",
"speaking_head": "7.0",
"speaking_head_in_silhouette": "7.0",
"bust_in_silhouette": "6.0",
"busts_in_silhouette": "6.0",
"fencer": "9.0",
"fencing": "9.0",
"horse_racing": "6.0",
"horse_racing_tone1": "8.0",
"horse_racing_tone2": "8.0",
"horse_racing_tone3": "8.0",
"horse_racing_tone4": "8.0",
"horse_racing_tone5": "8.0",
"skier": "5.2",
"snowboarder": "6.0",
"golfer": "7.0",
"surfer": "6.0",
"surfer_tone1": "8.0",
"surfer_tone2": "8.0",
"surfer_tone3": "8.0",
"surfer_tone4": "8.0",
"surfer_tone5": "8.0",
"rowboat": "6.0",
"rowboat_tone1": "8.0",
"rowboat_tone2": "8.0",
"rowboat_tone3": "8.0",
"rowboat_tone4": "8.0",
"rowboat_tone5": "8.0",
"swimmer": "6.0",
"swimmer_tone1": "8.0",
"swimmer_tone2": "8.0",
"swimmer_tone3": "8.0",
"swimmer_tone4": "8.0",
"swimmer_tone5": "8.0",
"basketball_player": "5.2",
"person_with_ball": "5.2",
"basketball_player_tone1": "8.0",
"person_with_ball_tone1": "8.0",
"basketball_player_tone2": "8.0",
"person_with_ball_tone2": "8.0",
"basketball_player_tone3": "8.0",
"person_with_ball_tone3": "8.0",
"basketball_player_tone4": "8.0",
"person_with_ball_tone4": "8.0",
"basketball_player_tone5": "8.0",
"person_with_ball_tone5": "8.0",
"lifter": "7.0",
"weight_lifter": "7.0",
"lifter_tone1": "8.0",
"weight_lifter_tone1": "8.0",
"lifter_tone2": "8.0",
"weight_lifter_tone2": "8.0",
"lifter_tone3": "8.0",
"weight_lifter_tone3": "8.0",
"lifter_tone4": "8.0",
"weight_lifter_tone4": "8.0",
"lifter_tone5": "8.0",
"weight_lifter_tone5": "8.0",
"bicyclist": "6.0",
"bicyclist_tone1": "8.0",
"bicyclist_tone2": "8.0",
"bicyclist_tone3": "8.0",
"bicyclist_tone4": "8.0",
"bicyclist_tone5": "8.0",
"mountain_bicyclist": "6.0",
"mountain_bicyclist_tone1": "8.0",
"mountain_bicyclist_tone2": "8.0",
"mountain_bicyclist_tone3": "8.0",
"mountain_bicyclist_tone4": "8.0",
"mountain_bicyclist_tone5": "8.0",
"race_car": "7.0",
"racing_car": "7.0",
"motorcycle": "7.0",
"racing_motorcycle": "7.0",
"cartwheel": "9.0",
"person_doing_cartwheel": "9.0",
"cartwheel_tone1": "9.0",
"person_doing_cartwheel_tone1": "9.0",
"cartwheel_tone2": "9.0",
"person_doing_cartwheel_tone2": "9.0",
"cartwheel_tone3": "9.0",
"person_doing_cartwheel_tone3": "9.0",
"cartwheel_tone4": "9.0",
"person_doing_cartwheel_tone4": "9.0",
"cartwheel_tone5": "9.0",
"person_doing_cartwheel_tone5": "9.0",
"wrestlers": "9.0",
"wrestling": "9.0",
"wrestlers_tone1": "9.0",
"wrestling_tone1": "9.0",
"wrestlers_tone2": "9.0",
"wrestling_tone2": "9.0",
"wrestlers_tone3": "9.0",
"wrestling_tone3": "9.0",
"wrestlers_tone4": "9.0",
"wrestling_tone4": "9.0",
"wrestlers_tone5": "9.0",
"wrestling_tone5": "9.0",
"water_polo": "9.0",
"water_polo_tone1": "9.0",
"water_polo_tone2": "9.0",
"water_polo_tone3": "9.0",
"water_polo_tone4": "9.0",
"water_polo_tone5": "9.0",
"handball": "9.0",
"handball_tone1": "9.0",
"handball_tone2": "9.0",
"handball_tone3": "9.0",
"handball_tone4": "9.0",
"handball_tone5": "9.0",
"juggling": "9.0",
"juggler": "9.0",
"juggling_tone1": "9.0",
"juggler_tone1": "9.0",
"juggling_tone2": "9.0",
"juggler_tone2": "9.0",
"juggling_tone3": "9.0",
"juggler_tone3": "9.0",
"juggling_tone4": "9.0",
"juggler_tone4": "9.0",
"juggling_tone5": "9.0",
"juggler_tone5": "9.0",
"couple": "6.0",
"two_men_holding_hands": "6.0",
"two_women_holding_hands": "6.0",
"couplekiss": "6.0",
"kiss_mm": "6.0",
"couplekiss_mm": "6.0",
"kiss_ww": "6.0",
"couplekiss_ww": "6.0",
"couple_with_heart": "6.0",
"couple_mm": "6.0",
"couple_with_heart_mm": "6.0",
"couple_ww": "6.0",
"couple_with_heart_ww": "6.0",
"family": "6.0",
"family_mwg": "6.0",
"family_mwgb": "6.0",
"family_mwbb": "6.0",
"family_mwgg": "6.0",
"family_mmb": "6.0",
"family_mmg": "6.0",
"family_mmgb": "6.0",
"family_mmbb": "6.0",
"family_mmgg": "6.0",
"family_wwb": "6.0",
"family_wwg": "6.0",
"family_wwgb": "6.0",
"family_wwbb": "6.0",
"family_wwgg": "6.0",
"tone1": "8.0",
"tone2": "8.0",
"tone3": "8.0",
"tone4": "8.0",
"tone5": "8.0",
"muscle": "6.0",
"muscle_tone1": "8.0",
"muscle_tone2": "8.0",
"muscle_tone3": "8.0",
"muscle_tone4": "8.0",
"muscle_tone5": "8.0",
"selfie": "9.0",
"selfie_tone1": "9.0",
"selfie_tone2": "9.0",
"selfie_tone3": "9.0",
"selfie_tone4": "9.0",
"selfie_tone5": "9.0",
"point_left": "6.0",
"point_left_tone1": "8.0",
"point_left_tone2": "8.0",
"point_left_tone3": "8.0",
"point_left_tone4": "8.0",
"point_left_tone5": "8.0",
"point_right": "6.0",
"point_right_tone1": "8.0",
"point_right_tone2": "8.0",
"point_right_tone3": "8.0",
"point_right_tone4": "8.0",
"point_right_tone5": "8.0",
"point_up": "1.1",
"point_up_tone1": "8.0",
"point_up_tone2": "8.0",
"point_up_tone3": "8.0",
"point_up_tone4": "8.0",
"point_up_tone5": "8.0",
"point_up_2": "6.0",
"point_up_2_tone1": "8.0",
"point_up_2_tone2": "8.0",
"point_up_2_tone3": "8.0",
"point_up_2_tone4": "8.0",
"point_up_2_tone5": "8.0",
"middle_finger": "7.0",
"reversed_hand_with_middle_finger_extended": "7.0",
"middle_finger_tone1": "8.0",
"reversed_hand_with_middle_finger_extended_tone1": "8.0",
"middle_finger_tone2": "8.0",
"reversed_hand_with_middle_finger_extended_tone2": "8.0",
"middle_finger_tone3": "8.0",
"reversed_hand_with_middle_finger_extended_tone3": "8.0",
"middle_finger_tone4": "8.0",
"reversed_hand_with_middle_finger_extended_tone4": "8.0",
"middle_finger_tone5": "8.0",
"reversed_hand_with_middle_finger_extended_tone5": "8.0",
"point_down": "6.0",
"point_down_tone1": "8.0",
"point_down_tone2": "8.0",
"point_down_tone3": "8.0",
"point_down_tone4": "8.0",
"point_down_tone5": "8.0",
"v": "1.1",
"v_tone1": "8.0",
"v_tone2": "8.0",
"v_tone3": "8.0",
"v_tone4": "8.0",
"v_tone5": "8.0",
"fingers_crossed": "9.0",
"hand_with_index_and_middle_finger_crossed": "9.0",
"fingers_crossed_tone1": "9.0",
"hand_with_index_and_middle_fingers_crossed_tone1": "9.0",
"fingers_crossed_tone2": "9.0",
"hand_with_index_and_middle_fingers_crossed_tone2": "9.0",
"fingers_crossed_tone3": "9.0",
"hand_with_index_and_middle_fingers_crossed_tone3": "9.0",
"fingers_crossed_tone4": "9.0",
"hand_with_index_and_middle_fingers_crossed_tone4": "9.0",
"fingers_crossed_tone5": "9.0",
"hand_with_index_and_middle_fingers_crossed_tone5": "9.0",
"vulcan": "7.0",
"raised_hand_with_part_between_middle_and_ring_fingers": "7.0",
"vulcan_tone1": "8.0",
"raised_hand_with_part_between_middle_and_ring_fingers_tone1": "8.0",
"vulcan_tone2": "8.0",
"raised_hand_with_part_between_middle_and_ring_fingers_tone2": "8.0",
"vulcan_tone3": "8.0",
"raised_hand_with_part_between_middle_and_ring_fingers_tone3": "8.0",
"vulcan_tone4": "8.0",
"raised_hand_with_part_between_middle_and_ring_fingers_tone4": "8.0",
"vulcan_tone5": "8.0",
"raised_hand_with_part_between_middle_and_ring_fingers_tone5": "8.0",
"metal": "8.0",
"sign_of_the_horns": "8.0",
"metal_tone1": "8.0",
"sign_of_the_horns_tone1": "8.0",
"metal_tone2": "8.0",
"sign_of_the_horns_tone2": "8.0",
"metal_tone3": "8.0",
"sign_of_the_horns_tone3": "8.0",
"metal_tone4": "8.0",
"sign_of_the_horns_tone4": "8.0",
"metal_tone5": "8.0",
"sign_of_the_horns_tone5": "8.0",
"call_me": "9.0",
"call_me_hand": "9.0",
"call_me_tone1": "9.0",
"call_me_hand_tone1": "9.0",
"call_me_tone2": "9.0",
"call_me_hand_tone2": "9.0",
"call_me_tone3": "9.0",
"call_me_hand_tone3": "9.0",
"call_me_tone4": "9.0",
"call_me_hand_tone4": "9.0",
"call_me_tone5": "9.0",
"call_me_hand_tone5": "9.0",
"hand_splayed": "7.0",
"raised_hand_with_fingers_splayed": "7.0",
"hand_splayed_tone1": "8.0",
"raised_hand_with_fingers_splayed_tone1": "8.0",
"hand_splayed_tone2": "8.0",
"raised_hand_with_fingers_splayed_tone2": "8.0",
"hand_splayed_tone3": "8.0",
"raised_hand_with_fingers_splayed_tone3": "8.0",
"hand_splayed_tone4": "8.0",
"raised_hand_with_fingers_splayed_tone4": "8.0",
"hand_splayed_tone5": "8.0",
"raised_hand_with_fingers_splayed_tone5": "8.0",
"raised_hand": "6.0",
"raised_hand_tone1": "8.0",
"raised_hand_tone2": "8.0",
"raised_hand_tone3": "8.0",
"raised_hand_tone4": "8.0",
"raised_hand_tone5": "8.0",
"ok_hand": "6.0",
"ok_hand_tone1": "8.0",
"ok_hand_tone2": "8.0",
"ok_hand_tone3": "8.0",
"ok_hand_tone4": "8.0",
"ok_hand_tone5": "8.0",
"thumbsup": "6.0",
"+1": "6.0",
"thumbup": "6.0",
"thumbsup_tone1": "8.0",
"+1_tone1": "8.0",
"thumbup_tone1": "8.0",
"thumbsup_tone2": "8.0",
"+1_tone2": "8.0",
"thumbup_tone2": "8.0",
"thumbsup_tone3": "8.0",
"+1_tone3": "8.0",
"thumbup_tone3": "8.0",
"thumbsup_tone4": "8.0",
"+1_tone4": "8.0",
"thumbup_tone4": "8.0",
"thumbsup_tone5": "8.0",
"+1_tone5": "8.0",
"thumbup_tone5": "8.0",
"thumbsdown": "6.0",
"-1": "6.0",
"thumbdown": "6.0",
"thumbsdown_tone1": "8.0",
"-1_tone1": "8.0",
"thumbdown_tone1": "8.0",
"thumbsdown_tone2": "8.0",
"-1_tone2": "8.0",
"thumbdown_tone2": "8.0",
"thumbsdown_tone3": "8.0",
"-1_tone3": "8.0",
"thumbdown_tone3": "8.0",
"thumbsdown_tone4": "8.0",
"-1_tone4": "8.0",
"thumbdown_tone4": "8.0",
"thumbsdown_tone5": "8.0",
"-1_tone5": "8.0",
"thumbdown_tone5": "8.0",
"fist": "6.0",
"fist_tone1": "8.0",
"fist_tone2": "8.0",
"fist_tone3": "8.0",
"fist_tone4": "8.0",
"fist_tone5": "8.0",
"punch": "6.0",
"punch_tone1": "8.0",
"punch_tone2": "8.0",
"punch_tone3": "8.0",
"punch_tone4": "8.0",
"punch_tone5": "8.0",
"left_facing_fist": "9.0",
"left_fist": "9.0",
"left_facing_fist_tone1": "9.0",
"left_fist_tone1": "9.0",
"left_facing_fist_tone2": "9.0",
"left_fist_tone2": "9.0",
"left_facing_fist_tone3": "9.0",
"left_fist_tone3": "9.0",
"left_facing_fist_tone4": "9.0",
"left_fist_tone4": "9.0",
"left_facing_fist_tone5": "9.0",
"left_fist_tone5": "9.0",
"right_facing_fist": "9.0",
"right_fist": "9.0",
"right_facing_fist_tone1": "9.0",
"right_fist_tone1": "9.0",
"right_facing_fist_tone2": "9.0",
"right_fist_tone2": "9.0",
"right_facing_fist_tone3": "9.0",
"right_fist_tone3": "9.0",
"right_facing_fist_tone4": "9.0",
"right_fist_tone4": "9.0",
"right_facing_fist_tone5": "9.0",
"right_fist_tone5": "9.0",
"raised_back_of_hand": "9.0",
"back_of_hand": "9.0",
"raised_back_of_hand_tone1": "9.0",
"back_of_hand_tone1": "9.0",
"raised_back_of_hand_tone2": "9.0",
"back_of_hand_tone2": "9.0",
"raised_back_of_hand_tone3": "9.0",
"back_of_hand_tone3": "9.0",
"raised_back_of_hand_tone4": "9.0",
"back_of_hand_tone4": "9.0",
"raised_back_of_hand_tone5": "9.0",
"back_of_hand_tone5": "9.0",
"wave": "6.0",
"wave_tone1": "8.0",
"wave_tone2": "8.0",
"wave_tone3": "8.0",
"wave_tone4": "8.0",
"wave_tone5": "8.0",
"clap": "6.0",
"clap_tone1": "8.0",
"clap_tone2": "8.0",
"clap_tone3": "8.0",
"clap_tone4": "8.0",
"clap_tone5": "8.0",
"writing_hand": "1.1",
"writing_hand_tone1": "8.0",
"writing_hand_tone2": "8.0",
"writing_hand_tone3": "8.0",
"writing_hand_tone4": "8.0",
"writing_hand_tone5": "8.0",
"open_hands": "6.0",
"open_hands_tone1": "8.0",
"open_hands_tone2": "8.0",
"open_hands_tone3": "8.0",
"open_hands_tone4": "8.0",
"open_hands_tone5": "8.0",
"raised_hands": "6.0",
"raised_hands_tone1": "8.0",
"raised_hands_tone2": "8.0",
"raised_hands_tone3": "8.0",
"raised_hands_tone4": "8.0",
"raised_hands_tone5": "8.0",
"pray": "6.0",
"pray_tone1": "8.0",
"pray_tone2": "8.0",
"pray_tone3": "8.0",
"pray_tone4": "8.0",
"pray_tone5": "8.0",
"handshake": "9.0",
"shaking_hands": "9.0",
"handshake_tone1": "9.0",
"shaking_hands_tone1": "9.0",
"handshake_tone2": "9.0",
"shaking_hands_tone2": "9.0",
"handshake_tone3": "9.0",
"shaking_hands_tone3": "9.0",
"handshake_tone4": "9.0",
"shaking_hands_tone4": "9.0",
"handshake_tone5": "9.0",
"shaking_hands_tone5": "9.0",
"nail_care": "6.0",
"nail_care_tone1": "8.0",
"nail_care_tone2": "8.0",
"nail_care_tone3": "8.0",
"nail_care_tone4": "8.0",
"nail_care_tone5": "8.0",
"ear": "6.0",
"ear_tone1": "8.0",
"ear_tone2": "8.0",
"ear_tone3": "8.0",
"ear_tone4": "8.0",
"ear_tone5": "8.0",
"nose": "6.0",
"nose_tone1": "8.0",
"nose_tone2": "8.0",
"nose_tone3": "8.0",
"nose_tone4": "8.0",
"nose_tone5": "8.0",
"footprints": "6.0",
"eyes": "6.0",
"eye": "7.0",
"eye_in_speech_bubble": "7.0",
"tongue": "6.0",
"lips": "6.0",
"kiss": "6.0",
"cupid": "6.0",
"heart": "1.1",
"heartbeat": "6.0",
"broken_heart": "6.0",
"two_hearts": "6.0",
"sparkling_heart": "6.0",
"heartpulse": "6.0",
"blue_heart": "6.0",
"green_heart": "6.0",
"yellow_heart": "6.0",
"purple_heart": "6.0",
"black_heart": "9.0",
"gift_heart": "6.0",
"revolving_hearts": "6.0",
"heart_decoration": "6.0",
"heart_exclamation": "1.1",
"heavy_heart_exclamation_mark_ornament": "1.1",
"love_letter": "6.0",
"zzz": "6.0",
"anger": "6.0",
"bomb": "6.0",
"boom": "6.0",
"sweat_drops": "6.0",
"dash": "6.0",
"dizzy": "6.0",
"speech_balloon": "6.0",
"speech_left": "7.0",
"left_speech_bubble": "7.0",
"anger_right": "7.0",
"right_anger_bubble": "7.0",
"thought_balloon": "6.0",
"hole": "7.0",
"eyeglasses": "6.0",
"dark_sunglasses": "7.0",
"necktie": "6.0",
"shirt": "6.0",
"jeans": "6.0",
"dress": "6.0",
"kimono": "6.0",
"bikini": "6.0",
"womans_clothes": "6.0",
"purse": "6.0",
"handbag": "6.0",
"pouch": "6.0",
"shopping_bags": "7.0",
"school_satchel": "6.0",
"mans_shoe": "6.0",
"athletic_shoe": "6.0",
"high_heel": "6.0",
"sandal": "6.0",
"boot": "6.0",
"crown": "6.0",
"womans_hat": "6.0",
"tophat": "6.0",
"mortar_board": "6.0",
"helmet_with_cross": "5.2",
"helmet_with_white_cross": "5.2",
"prayer_beads": "8.0",
"lipstick": "6.0",
"ring": "6.0",
"gem": "6.0",
"monkey_face": "6.0",
"monkey": "6.0",
"gorilla": "9.0",
"dog": "6.0",
"dog2": "6.0",
"poodle": "6.0",
"wolf": "6.0",
"fox": "9.0",
"fox_face": "9.0",
"cat": "6.0",
"cat2": "6.0",
"lion_face": "8.0",
"lion": "8.0",
"tiger": "6.0",
"tiger2": "6.0",
"leopard": "6.0",
"horse": "6.0",
"racehorse": "6.0",
"deer": "9.0",
"unicorn": "8.0",
"unicorn_face": "8.0",
"cow": "6.0",
"ox": "6.0",
"water_buffalo": "6.0",
"cow2": "6.0",
"pig": "6.0",
"pig2": "6.0",
"boar": "6.0",
"pig_nose": "6.0",
"ram": "6.0",
"sheep": "6.0",
"goat": "6.0",
"dromedary_camel": "6.0",
"camel": "6.0",
"elephant": "6.0",
"rhino": "9.0",
"rhinoceros": "9.0",
"mouse": "6.0",
"mouse2": "6.0",
"rat": "6.0",
"hamster": "6.0",
"rabbit": "6.0",
"rabbit2": "6.0",
"chipmunk": "7.0",
"bat": "9.0",
"bear": "6.0",
"koala": "6.0",
"panda_face": "6.0",
"feet": "6.0",
"paw_prints": "6.0",
"turkey": "8.0",
"chicken": "6.0",
"rooster": "6.0",
"hatching_chick": "6.0",
"baby_chick": "6.0",
"hatched_chick": "6.0",
"bird": "6.0",
"penguin": "6.0",
"dove": "7.0",
"dove_of_peace": "7.0",
"eagle": "9.0",
"duck": "9.0",
"owl": "9.0",
"frog": "6.0",
"crocodile": "6.0",
"turtle": "6.0",
"lizard": "9.0",
"snake": "6.0",
"dragon_face": "6.0",
"dragon": "6.0",
"whale": "6.0",
"whale2": "6.0",
"dolphin": "6.0",
"fish": "6.0",
"tropical_fish": "6.0",
"blowfish": "6.0",
"shark": "9.0",
"octopus": "6.0",
"shell": "6.0",
"crab": "8.0",
"shrimp": "9.0",
"squid": "9.0",
"butterfly": "9.0",
"snail": "6.0",
"bug": "6.0",
"ant": "6.0",
"bee": "6.0",
"beetle": "6.0",
"spider": "7.0",
"spider_web": "7.0",
"scorpion": "8.0",
"bouquet": "6.0",
"cherry_blossom": "6.0",
"white_flower": "6.0",
"rosette": "7.0",
"rose": "6.0",
"wilted_rose": "9.0",
"wilted_flower": "9.0",
"hibiscus": "6.0",
"sunflower": "6.0",
"blossom": "6.0",
"tulip": "6.0",
"seedling": "6.0",
"evergreen_tree": "6.0",
"deciduous_tree": "6.0",
"palm_tree": "6.0",
"cactus": "6.0",
"ear_of_rice": "6.0",
"herb": "6.0",
"shamrock": "4.1",
"four_leaf_clover": "6.0",
"maple_leaf": "6.0",
"fallen_leaf": "6.0",
"leaves": "6.0",
"grapes": "6.0",
"melon": "6.0",
"watermelon": "6.0",
"tangerine": "6.0",
"lemon": "6.0",
"banana": "6.0",
"pineapple": "6.0",
"apple": "6.0",
"green_apple": "6.0",
"pear": "6.0",
"peach": "6.0",
"cherries": "6.0",
"strawberry": "6.0",
"kiwi": "9.0",
"kiwifruit": "9.0",
"tomato": "6.0",
"avocado": "9.0",
"eggplant": "6.0",
"potato": "9.0",
"carrot": "9.0",
"corn": "6.0",
"hot_pepper": "7.0",
"cucumber": "9.0",
"mushroom": "6.0",
"peanuts": "9.0",
"shelled_peanut": "9.0",
"chestnut": "6.0",
"bread": "6.0",
"croissant": "9.0",
"french_bread": "9.0",
"baguette_bread": "9.0",
"pancakes": "9.0",
"cheese": "8.0",
"cheese_wedge": "8.0",
"meat_on_bone": "6.0",
"poultry_leg": "6.0",
"bacon": "9.0",
"hamburger": "6.0",
"fries": "6.0",
"pizza": "6.0",
"hotdog": "8.0",
"hot_dog": "8.0",
"taco": "8.0",
"burrito": "8.0",
"stuffed_flatbread": "9.0",
"stuffed_pita": "9.0",
"egg": "9.0",
"cooking": "6.0",
"shallow_pan_of_food": "9.0",
"paella": "9.0",
"stew": "6.0",
"salad": "9.0",
"green_salad": "9.0",
"popcorn": "8.0",
"bento": "6.0",
"rice_cracker": "6.0",
"rice_ball": "6.0",
"rice": "6.0",
"curry": "6.0",
"ramen": "6.0",
"spaghetti": "6.0",
"sweet_potato": "6.0",
"oden": "6.0",
"sushi": "6.0",
"fried_shrimp": "6.0",
"fish_cake": "6.0",
"dango": "6.0",
"icecream": "6.0",
"shaved_ice": "6.0",
"ice_cream": "6.0",
"doughnut": "6.0",
"cookie": "6.0",
"birthday": "6.0",
"cake": "6.0",
"chocolate_bar": "6.0",
"candy": "6.0",
"lollipop": "6.0",
"custard": "6.0",
"pudding": "6.0",
"flan": "6.0",
"honey_pot": "6.0",
"baby_bottle": "6.0",
"milk": "9.0",
"glass_of_milk": "9.0",
"coffee": "4.0",
"tea": "6.0",
"sake": "6.0",
"champagne": "8.0",
"bottle_with_popping_cork": "8.0",
"wine_glass": "6.0",
"cocktail": "6.0",
"tropical_drink": "6.0",
"beer": "6.0",
"beers": "6.0",
"champagne_glass": "9.0",
"clinking_glass": "9.0",
"tumbler_glass": "9.0",
"whisky": "9.0",
"fork_knife_plate": "7.0",
"fork_and_knife_with_plate": "7.0",
"fork_and_knife": "6.0",
"spoon": "9.0",
"knife": "6.0",
"amphora": "8.0",
"earth_africa": "6.0",
"earth_americas": "6.0",
"earth_asia": "6.0",
"globe_with_meridians": "6.0",
"map": "7.0",
"world_map": "7.0",
"japan": "6.0",
"mountain_snow": "7.0",
"snow_capped_mountain": "7.0",
"mountain": "5.2",
"volcano": "6.0",
"mount_fuji": "6.0",
"camping": "7.0",
"beach": "7.0",
"beach_with_umbrella": "7.0",
"desert": "7.0",
"island": "7.0",
"desert_island": "7.0",
"park": "7.0",
"national_park": "7.0",
"stadium": "7.0",
"classical_building": "7.0",
"construction_site": "7.0",
"building_construction": "7.0",
"homes": "7.0",
"house_buildings": "7.0",
"cityscape": "7.0",
"house_abandoned": "7.0",
"derelict_house_building": "7.0",
"house": "6.0",
"house_with_garden": "6.0",
"office": "6.0",
"post_office": "6.0",
"european_post_office": "6.0",
"hospital": "6.0",
"bank": "6.0",
"hotel": "6.0",
"love_hotel": "6.0",
"convenience_store": "6.0",
"school": "6.0",
"department_store": "6.0",
"factory": "6.0",
"japanese_castle": "6.0",
"european_castle": "6.0",
"wedding": "6.0",
"tokyo_tower": "6.0",
"statue_of_liberty": "6.0",
"church": "5.2",
"mosque": "8.0",
"synagogue": "8.0",
"shinto_shrine": "5.2",
"kaaba": "8.0",
"fountain": "5.2",
"tent": "5.2",
"foggy": "6.0",
"night_with_stars": "6.0",
"sunrise_over_mountains": "6.0",
"sunrise": "6.0",
"city_dusk": "6.0",
"city_sunset": "6.0",
"city_sunrise": "6.0",
"bridge_at_night": "6.0",
"hotsprings": "1.1",
"milky_way": "6.0",
"carousel_horse": "6.0",
"ferris_wheel": "6.0",
"roller_coaster": "6.0",
"barber": "6.0",
"circus_tent": "6.0",
"performing_arts": "6.0",
"frame_photo": "7.0",
"frame_with_picture": "7.0",
"art": "6.0",
"slot_machine": "6.0",
"steam_locomotive": "6.0",
"railway_car": "6.0",
"bullettrain_side": "6.0",
"bullettrain_front": "6.0",
"train2": "6.0",
"metro": "6.0",
"light_rail": "6.0",
"station": "6.0",
"tram": "6.0",
"monorail": "6.0",
"mountain_railway": "6.0",
"train": "6.0",
"bus": "6.0",
"oncoming_bus": "6.0",
"trolleybus": "6.0",
"minibus": "6.0",
"ambulance": "6.0",
"fire_engine": "6.0",
"police_car": "6.0",
"oncoming_police_car": "6.0",
"taxi": "6.0",
"oncoming_taxi": "6.0",
"red_car": "6.0",
"oncoming_automobile": "6.0",
"blue_car": "6.0",
"truck": "6.0",
"articulated_lorry": "6.0",
"tractor": "6.0",
"bike": "6.0",
"scooter": "9.0",
"motor_scooter": "9.0",
"motorbike": "9.0",
"busstop": "6.0",
"motorway": "7.0",
"railway_track": "7.0",
"railroad_track": "7.0",
"fuelpump": "5.2",
"rotating_light": "6.0",
"traffic_light": "6.0",
"vertical_traffic_light": "6.0",
"construction": "6.0",
"octagonal_sign": "9.0",
"stop_sign": "9.0",
"anchor": "4.1",
"sailboat": "5.2",
"canoe": "9.0",
"kayak": "9.0",
"speedboat": "6.0",
"cruise_ship": "7.0",
"passenger_ship": "7.0",
"ferry": "5.2",
"motorboat": "7.0",
"ship": "6.0",
"airplane": "1.1",
"airplane_small": "7.0",
"small_airplane": "7.0",
"airplane_departure": "7.0",
"airplane_arriving": "7.0",
"seat": "6.0",
"helicopter": "6.0",
"suspension_railway": "6.0",
"mountain_cableway": "6.0",
"aerial_tramway": "6.0",
"rocket": "6.0",
"satellite_orbital": "7.0",
"bellhop": "7.0",
"bellhop_bell": "7.0",
"door": "6.0",
"sleeping_accommodation": "7.0",
"bed": "7.0",
"couch": "7.0",
"couch_and_lamp": "7.0",
"toilet": "6.0",
"shower": "6.0",
"bath": "6.0",
"bath_tone1": "8.0",
"bath_tone2": "8.0",
"bath_tone3": "8.0",
"bath_tone4": "8.0",
"bath_tone5": "8.0",
"bathtub": "6.0",
"hourglass": "1.1",
"hourglass_flowing_sand": "6.0",
"watch": "1.1",
"alarm_clock": "6.0",
"stopwatch": "6.0",
"timer": "6.0",
"timer_clock": "6.0",
"clock": "7.0",
"mantlepiece_clock": "7.0",
"clock12": "6.0",
"clock1230": "6.0",
"clock1": "6.0",
"clock130": "6.0",
"clock2": "6.0",
"clock230": "6.0",
"clock3": "6.0",
"clock330": "6.0",
"clock4": "6.0",
"clock430": "6.0",
"clock5": "6.0",
"clock530": "6.0",
"clock6": "6.0",
"clock630": "6.0",
"clock7": "6.0",
"clock730": "6.0",
"clock8": "6.0",
"clock830": "6.0",
"clock9": "6.0",
"clock930": "6.0",
"clock10": "6.0",
"clock1030": "6.0",
"clock11": "6.0",
"clock1130": "6.0",
"new_moon": "6.0",
"waxing_crescent_moon": "6.0",
"first_quarter_moon": "6.0",
"waxing_gibbous_moon": "6.0",
"full_moon": "6.0",
"waning_gibbous_moon": "6.0",
"last_quarter_moon": "6.0",
"waning_crescent_moon": "6.0",
"crescent_moon": "6.0",
"new_moon_with_face": "6.0",
"first_quarter_moon_with_face": "6.0",
"last_quarter_moon_with_face": "6.0",
"thermometer": "7.0",
"sunny": "1.1",
"full_moon_with_face": "6.0",
"sun_with_face": "6.0",
"star": "5.1",
"star2": "6.0",
"stars": "6.0",
"cloud": "1.1",
"partly_sunny": "5.2",
"thunder_cloud_rain": "5.2",
"thunder_cloud_and_rain": "5.2",
"white_sun_small_cloud": "7.0",
"white_sun_with_small_cloud": "7.0",
"white_sun_cloud": "7.0",
"white_sun_behind_cloud": "7.0",
"white_sun_rain_cloud": "7.0",
"white_sun_behind_cloud_with_rain": "7.0",
"cloud_rain": "7.0",
"cloud_with_rain": "7.0",
"cloud_snow": "7.0",
"cloud_with_snow": "7.0",
"cloud_lightning": "7.0",
"cloud_with_lightning": "7.0",
"cloud_tornado": "7.0",
"cloud_with_tornado": "7.0",
"fog": "7.0",
"wind_blowing_face": "7.0",
"cyclone": "6.0",
"rainbow": "6.0",
"closed_umbrella": "6.0",
"umbrella2": "1.1",
"umbrella": "4.0",
"beach_umbrella": "5.2",
"umbrella_on_ground": "5.2",
"zap": "4.0",
"snowflake": "1.1",
"snowman2": "1.1",
"snowman": "5.2",
"comet": "1.1",
"fire": "6.0",
"flame": "6.0",
"droplet": "6.0",
"ocean": "6.0",
"jack_o_lantern": "6.0",
"christmas_tree": "6.0",
"fireworks": "6.0",
"sparkler": "6.0",
"sparkles": "6.0",
"balloon": "6.0",
"tada": "6.0",
"confetti_ball": "6.0",
"tanabata_tree": "6.0",
"bamboo": "6.0",
"dolls": "6.0",
"flags": "6.0",
"wind_chime": "6.0",
"rice_scene": "6.0",
"ribbon": "6.0",
"gift": "6.0",
"reminder_ribbon": "7.0",
"tickets": "7.0",
"admission_tickets": "7.0",
"ticket": "6.0",
"military_medal": "7.0",
"trophy": "6.0",
"medal": "7.0",
"sports_medal": "7.0",
"first_place": "9.0",
"first_place_medal": "9.0",
"second_place": "9.0",
"second_place_medal": "9.0",
"third_place": "9.0",
"third_place_medal": "9.0",
"soccer": "5.2",
"baseball": "5.2",
"basketball": "6.0",
"volleyball": "8.0",
"football": "6.0",
"rugby_football": "6.0",
"tennis": "6.0",
"8ball": "6.0",
"bowling": "6.0",
"cricket": "8.0",
"cricket_bat_ball": "8.0",
"field_hockey": "8.0",
"hockey": "8.0",
"ping_pong": "8.0",
"table_tennis": "8.0",
"badminton": "8.0",
"boxing_glove": "9.0",
"boxing_gloves": "9.0",
"martial_arts_uniform": "9.0",
"karate_uniform": "9.0",
"goal": "9.0",
"goal_net": "9.0",
"dart": "6.0",
"golf": "5.2",
"ice_skate": "5.2",
"fishing_pole_and_fish": "6.0",
"running_shirt_with_sash": "6.0",
"ski": "6.0",
"video_game": "6.0",
"joystick": "7.0",
"game_die": "6.0",
"spades": "1.1",
"hearts": "1.1",
"diamonds": "1.1",
"clubs": "1.1",
"black_joker": "6.0",
"mahjong": "5.1",
"flower_playing_cards": "6.0",
"mute": "6.0",
"speaker": "6.0",
"sound": "6.0",
"loud_sound": "6.0",
"loudspeaker": "6.0",
"mega": "6.0",
"postal_horn": "6.0",
"bell": "6.0",
"no_bell": "6.0",
"musical_score": "6.0",
"musical_note": "6.0",
"notes": "6.0",
"microphone2": "7.0",
"studio_microphone": "7.0",
"level_slider": "7.0",
"control_knobs": "7.0",
"microphone": "6.0",
"headphones": "6.0",
"radio": "6.0",
"saxophone": "6.0",
"guitar": "6.0",
"musical_keyboard": "6.0",
"trumpet": "6.0",
"violin": "6.0",
"drum": "9.0",
"drum_with_drumsticks": "9.0",
"iphone": "6.0",
"calling": "6.0",
"telephone": "1.1",
"telephone_receiver": "6.0",
"pager": "6.0",
"fax": "6.0",
"battery": "6.0",
"electric_plug": "6.0",
"computer": "6.0",
"desktop": "7.0",
"desktop_computer": "7.0",
"printer": "7.0",
"keyboard": "1.1",
"mouse_three_button": "7.0",
"three_button_mouse": "7.0",
"trackball": "7.0",
"minidisc": "6.0",
"floppy_disk": "6.0",
"cd": "6.0",
"dvd": "6.0",
"movie_camera": "6.0",
"film_frames": "7.0",
"projector": "7.0",
"film_projector": "7.0",
"clapper": "6.0",
"tv": "6.0",
"camera": "6.0",
"camera_with_flash": "7.0",
"video_camera": "6.0",
"vhs": "6.0",
"mag": "6.0",
"mag_right": "6.0",
"microscope": "6.0",
"telescope": "6.0",
"satellite": "6.0",
"candle": "7.0",
"bulb": "6.0",
"flashlight": "6.0",
"izakaya_lantern": "6.0",
"notebook_with_decorative_cover": "6.0",
"closed_book": "6.0",
"book": "6.0",
"green_book": "6.0",
"blue_book": "6.0",
"orange_book": "6.0",
"books": "6.0",
"notebook": "6.0",
"ledger": "6.0",
"page_with_curl": "6.0",
"scroll": "6.0",
"page_facing_up": "6.0",
"newspaper": "6.0",
"newspaper2": "7.0",
"rolled_up_newspaper": "7.0",
"bookmark_tabs": "6.0",
"bookmark": "6.0",
"label": "7.0",
"moneybag": "6.0",
"yen": "6.0",
"dollar": "6.0",
"euro": "6.0",
"pound": "6.0",
"money_with_wings": "6.0",
"credit_card": "6.0",
"chart": "6.0",
"currency_exchange": "6.0",
"heavy_dollar_sign": "6.0",
"envelope": "1.1",
"e-mail": "6.0",
"email": "6.0",
"incoming_envelope": "6.0",
"envelope_with_arrow": "6.0",
"outbox_tray": "6.0",
"inbox_tray": "6.0",
"package": "6.0",
"mailbox": "6.0",
"mailbox_closed": "6.0",
"mailbox_with_mail": "6.0",
"mailbox_with_no_mail": "6.0",
"postbox": "6.0",
"ballot_box": "7.0",
"ballot_box_with_ballot": "7.0",
"pencil2": "1.1",
"black_nib": "1.1",
"pen_fountain": "7.0",
"lower_left_fountain_pen": "7.0",
"pen_ballpoint": "7.0",
"lower_left_ballpoint_pen": "7.0",
"paintbrush": "7.0",
"lower_left_paintbrush": "7.0",
"crayon": "7.0",
"lower_left_crayon": "7.0",
"pencil": "6.0",
"briefcase": "6.0",
"file_folder": "6.0",
"open_file_folder": "6.0",
"dividers": "7.0",
"card_index_dividers": "7.0",
"date": "6.0",
"calendar": "6.0",
"notepad_spiral": "7.0",
"spiral_note_pad": "7.0",
"calendar_spiral": "7.0",
"spiral_calendar_pad": "7.0",
"card_index": "6.0",
"chart_with_upwards_trend": "6.0",
"chart_with_downwards_trend": "6.0",
"bar_chart": "6.0",
"clipboard": "6.0",
"pushpin": "6.0",
"round_pushpin": "6.0",
"paperclip": "6.0",
"paperclips": "7.0",
"linked_paperclips": "7.0",
"straight_ruler": "6.0",
"triangular_ruler": "6.0",
"scissors": "1.1",
"card_box": "7.0",
"card_file_box": "7.0",
"file_cabinet": "7.0",
"wastebasket": "7.0",
"lock": "6.0",
"unlock": "6.0",
"lock_with_ink_pen": "6.0",
"closed_lock_with_key": "6.0",
"key": "6.0",
"key2": "7.0",
"old_key": "7.0",
"hammer": "6.0",
"pick": "5.2",
"hammer_pick": "4.1",
"hammer_and_pick": "4.1",
"tools": "7.0",
"hammer_and_wrench": "7.0",
"dagger": "7.0",
"dagger_knife": "7.0",
"crossed_swords": "4.1",
"gun": "6.0",
"bow_and_arrow": "8.0",
"archery": "8.0",
"shield": "7.0",
"wrench": "6.0",
"nut_and_bolt": "6.0",
"gear": "4.1",
"compression": "7.0",
"alembic": "4.1",
"scales": "4.1",
"link": "6.0",
"chains": "5.2",
"syringe": "6.0",
"pill": "6.0",
"smoking": "6.0",
"coffin": "4.1",
"urn": "4.1",
"funeral_urn": "4.1",
"moyai": "6.0",
"oil": "7.0",
"oil_drum": "7.0",
"crystal_ball": "6.0",
"shopping_cart": "9.0",
"shopping_trolley": "9.0",
"atm": "6.0",
"put_litter_in_its_place": "6.0",
"potable_water": "6.0",
"wheelchair": "4.1",
"mens": "6.0",
"womens": "6.0",
"restroom": "6.0",
"baby_symbol": "6.0",
"wc": "6.0",
"passport_control": "6.0",
"customs": "6.0",
"baggage_claim": "6.0",
"left_luggage": "6.0",
"warning": "4.0",
"children_crossing": "6.0",
"no_entry": "5.2",
"no_entry_sign": "6.0",
"no_bicycles": "6.0",
"no_smoking": "6.0",
"do_not_litter": "6.0",
"non-potable_water": "6.0",
"no_pedestrians": "6.0",
"no_mobile_phones": "6.0",
"underage": "6.0",
"radioactive": "1.1",
"radioactive_sign": "1.1",
"biohazard": "1.1",
"biohazard_sign": "1.1",
"arrow_up": "4.0",
"arrow_upper_right": "1.1",
"arrow_right": "1.1",
"arrow_lower_right": "1.1",
"arrow_down": "4.0",
"arrow_lower_left": "1.1",
"arrow_left": "4.0",
"arrow_upper_left": "1.1",
"arrow_up_down": "1.1",
"left_right_arrow": "1.1",
"leftwards_arrow_with_hook": "1.1",
"arrow_right_hook": "1.1",
"arrow_heading_up": "3.2",
"arrow_heading_down": "3.2",
"arrows_clockwise": "6.0",
"arrows_counterclockwise": "6.0",
"back": "6.0",
"end": "6.0",
"on": "6.0",
"soon": "6.0",
"top": "6.0",
"place_of_worship": "8.0",
"worship_symbol": "8.0",
"atom": "4.1",
"atom_symbol": "4.1",
"om_symbol": "7.0",
"star_of_david": "1.1",
"wheel_of_dharma": "1.1",
"yin_yang": "1.1",
"cross": "1.1",
"latin_cross": "1.1",
"orthodox_cross": "1.1",
"star_and_crescent": "1.1",
"peace": "1.1",
"peace_symbol": "1.1",
"menorah": "8.0",
"six_pointed_star": "6.0",
"aries": "1.1",
"taurus": "1.1",
"gemini": "1.1",
"cancer": "1.1",
"leo": "1.1",
"virgo": "1.1",
"libra": "1.1",
"scorpius": "1.1",
"sagittarius": "1.1",
"capricorn": "1.1",
"aquarius": "1.1",
"pisces": "1.1",
"ophiuchus": "6.0",
"twisted_rightwards_arrows": "6.0",
"repeat": "6.0",
"repeat_one": "6.0",
"arrow_forward": "1.1",
"fast_forward": "6.0",
"track_next": "6.0",
"next_track": "6.0",
"play_pause": "6.0",
"arrow_backward": "1.1",
"rewind": "6.0",
"track_previous": "6.0",
"previous_track": "6.0",
"arrow_up_small": "6.0",
"arrow_double_up": "6.0",
"arrow_down_small": "6.0",
"arrow_double_down": "6.0",
"pause_button": "7.0",
"double_vertical_bar": "7.0",
"stop_button": "7.0",
"record_button": "7.0",
"eject": "4.0",
"eject_symbol": "4.0",
"cinema": "6.0",
"low_brightness": "6.0",
"high_brightness": "6.0",
"signal_strength": "6.0",
"vibration_mode": "6.0",
"mobile_phone_off": "6.0",
"recycle": "3.2",
"name_badge": "6.0",
"fleur-de-lis": "4.1",
"beginner": "6.0",
"trident": "6.0",
"o": "5.2",
"white_check_mark": "6.0",
"ballot_box_with_check": "1.1",
"heavy_check_mark": "1.1",
"heavy_multiplication_x": "1.1",
"x": "6.0",
"negative_squared_cross_mark": "6.0",
"heavy_plus_sign": "6.0",
"heavy_minus_sign": "6.0",
"heavy_division_sign": "6.0",
"curly_loop": "6.0",
"loop": "6.0",
"part_alternation_mark": "3.2",
"eight_spoked_asterisk": "1.1",
"eight_pointed_black_star": "1.1",
"sparkle": "1.1",
"bangbang": "1.1",
"interrobang": "3.0",
"question": "6.0",
"grey_question": "6.0",
"grey_exclamation": "6.0",
"exclamation": "5.2",
"wavy_dash": "1.1",
"copyright": "1.1",
"registered": "1.1",
"tm": "1.1",
"hash": "3.0",
"asterisk": "3.0",
"keycap_asterisk": "3.0",
"zero": "3.0",
"one": "3.0",
"two": "3.0",
"three": "3.0",
"four": "3.0",
"five": "3.0",
"six": "3.0",
"seven": "3.0",
"eight": "3.0",
"nine": "3.0",
"keycap_ten": "6.0",
"capital_abcd": "6.0",
"abcd": "6.0",
"symbols": "6.0",
"abc": "6.0",
"a": "6.0",
"ab": "6.0",
"b": "6.0",
"cl": "6.0",
"cool": "6.0",
"free": "6.0",
"information_source": "3.0",
"id": "6.0",
"m": "1.1",
"new": "6.0",
"ng": "6.0",
"o2": "6.0",
"ok": "6.0",
"parking": "5.2",
"sos": "6.0",
"up": "6.0",
"vs": "6.0",
"koko": "6.0",
"sa": "6.0",
"u6708": "6.0",
"u6709": "6.0",
"u6307": "5.2",
"ideograph_advantage": "6.0",
"u5272": "6.0",
"u7121": "5.2",
"u7981": "6.0",
"accept": "6.0",
"u7533": "6.0",
"u5408": "6.0",
"u7a7a": "6.0",
"congratulations": "1.1",
"secret": "1.1",
"u55b6": "6.0",
"u6e80": "6.0",
"black_small_square": "1.1",
"white_small_square": "1.1",
"white_medium_square": "3.2",
"black_medium_square": "3.2",
"white_medium_small_square": "3.2",
"black_medium_small_square": "3.2",
"black_large_square": "5.1",
"white_large_square": "5.1",
"large_orange_diamond": "6.0",
"large_blue_diamond": "6.0",
"small_orange_diamond": "6.0",
"small_blue_diamond": "6.0",
"small_red_triangle": "6.0",
"small_red_triangle_down": "6.0",
"diamond_shape_with_a_dot_inside": "6.0",
"radio_button": "6.0",
"black_square_button": "6.0",
"white_square_button": "6.0",
"white_circle": "4.1",
"black_circle": "4.1",
"red_circle": "6.0",
"blue_circle": "6.0",
"checkered_flag": "6.0",
"triangular_flag_on_post": "6.0",
"crossed_flags": "6.0",
"flag_black": "6.0",
"waving_black_flag": "6.0",
"flag_white": "6.0",
"waving_white_flag": "6.0",
"rainbow_flag": "6.0",
"gay_pride_flag": "6.0",
"flag_ac": "6.0",
"ac": "6.0",
"flag_ad": "6.0",
"ad": "6.0",
"flag_ae": "6.0",
"ae": "6.0",
"flag_af": "6.0",
"af": "6.0",
"flag_ag": "6.0",
"ag": "6.0",
"flag_ai": "6.0",
"ai": "6.0",
"flag_al": "6.0",
"al": "6.0",
"flag_am": "6.0",
"am": "6.0",
"flag_ao": "6.0",
"ao": "6.0",
"flag_aq": "6.0",
"aq": "6.0",
"flag_ar": "6.0",
"ar": "6.0",
"flag_as": "6.0",
"as": "6.0",
"flag_at": "6.0",
"at": "6.0",
"flag_au": "6.0",
"au": "6.0",
"flag_aw": "6.0",
"aw": "6.0",
"flag_ax": "6.0",
"ax": "6.0",
"flag_az": "6.0",
"az": "6.0",
"flag_ba": "6.0",
"ba": "6.0",
"flag_bb": "6.0",
"bb": "6.0",
"flag_bd": "6.0",
"bd": "6.0",
"flag_be": "6.0",
"be": "6.0",
"flag_bf": "6.0",
"bf": "6.0",
"flag_bg": "6.0",
"bg": "6.0",
"flag_bh": "6.0",
"bh": "6.0",
"flag_bi": "6.0",
"bi": "6.0",
"flag_bj": "6.0",
"bj": "6.0",
"flag_bl": "6.0",
"bl": "6.0",
"flag_bm": "6.0",
"bm": "6.0",
"flag_bn": "6.0",
"bn": "6.0",
"flag_bo": "6.0",
"bo": "6.0",
"flag_bq": "6.0",
"bq": "6.0",
"flag_br": "6.0",
"br": "6.0",
"flag_bs": "6.0",
"bs": "6.0",
"flag_bt": "6.0",
"bt": "6.0",
"flag_bv": "6.0",
"bv": "6.0",
"flag_bw": "6.0",
"bw": "6.0",
"flag_by": "6.0",
"by": "6.0",
"flag_bz": "6.0",
"bz": "6.0",
"flag_ca": "6.0",
"ca": "6.0",
"flag_cc": "6.0",
"cc": "6.0",
"flag_cd": "6.0",
"congo": "6.0",
"flag_cf": "6.0",
"cf": "6.0",
"flag_cg": "6.0",
"cg": "6.0",
"flag_ch": "6.0",
"ch": "6.0",
"flag_ci": "6.0",
"ci": "6.0",
"flag_ck": "6.0",
"ck": "6.0",
"flag_cl": "6.0",
"chile": "6.0",
"flag_cm": "6.0",
"cm": "6.0",
"flag_cn": "6.0",
"cn": "6.0",
"flag_co": "6.0",
"co": "6.0",
"flag_cp": "6.0",
"cp": "6.0",
"flag_cr": "6.0",
"cr": "6.0",
"flag_cu": "6.0",
"cu": "6.0",
"flag_cv": "6.0",
"cv": "6.0",
"flag_cw": "6.0",
"cw": "6.0",
"flag_cx": "6.0",
"cx": "6.0",
"flag_cy": "6.0",
"cy": "6.0",
"flag_cz": "6.0",
"cz": "6.0",
"flag_de": "6.0",
"de": "6.0",
"flag_dg": "6.0",
"dg": "6.0",
"flag_dj": "6.0",
"dj": "6.0",
"flag_dk": "6.0",
"dk": "6.0",
"flag_dm": "6.0",
"dm": "6.0",
"flag_do": "6.0",
"do": "6.0",
"flag_dz": "6.0",
"dz": "6.0",
"flag_ea": "6.0",
"ea": "6.0",
"flag_ec": "6.0",
"ec": "6.0",
"flag_ee": "6.0",
"ee": "6.0",
"flag_eg": "6.0",
"eg": "6.0",
"flag_eh": "6.0",
"eh": "6.0",
"flag_er": "6.0",
"er": "6.0",
"flag_es": "6.0",
"es": "6.0",
"flag_et": "6.0",
"et": "6.0",
"flag_eu": "6.0",
"eu": "6.0",
"flag_fi": "6.0",
"fi": "6.0",
"flag_fj": "6.0",
"fj": "6.0",
"flag_fk": "6.0",
"fk": "6.0",
"flag_fm": "6.0",
"fm": "6.0",
"flag_fo": "6.0",
"fo": "6.0",
"flag_fr": "6.0",
"fr": "6.0",
"flag_ga": "6.0",
"ga": "6.0",
"flag_gb": "6.0",
"gb": "6.0",
"flag_gd": "6.0",
"gd": "6.0",
"flag_ge": "6.0",
"ge": "6.0",
"flag_gf": "6.0",
"gf": "6.0",
"flag_gg": "6.0",
"gg": "6.0",
"flag_gh": "6.0",
"gh": "6.0",
"flag_gi": "6.0",
"gi": "6.0",
"flag_gl": "6.0",
"gl": "6.0",
"flag_gm": "6.0",
"gm": "6.0",
"flag_gn": "6.0",
"gn": "6.0",
"flag_gp": "6.0",
"gp": "6.0",
"flag_gq": "6.0",
"gq": "6.0",
"flag_gr": "6.0",
"gr": "6.0",
"flag_gs": "6.0",
"gs": "6.0",
"flag_gt": "6.0",
"gt": "6.0",
"flag_gu": "6.0",
"gu": "6.0",
"flag_gw": "6.0",
"gw": "6.0",
"flag_gy": "6.0",
"gy": "6.0",
"flag_hk": "6.0",
"hk": "6.0",
"flag_hm": "6.0",
"hm": "6.0",
"flag_hn": "6.0",
"hn": "6.0",
"flag_hr": "6.0",
"hr": "6.0",
"flag_ht": "6.0",
"ht": "6.0",
"flag_hu": "6.0",
"hu": "6.0",
"flag_ic": "6.0",
"ic": "6.0",
"flag_id": "6.0",
"indonesia": "6.0",
"flag_ie": "6.0",
"ie": "6.0",
"flag_il": "6.0",
"il": "6.0",
"flag_im": "6.0",
"im": "6.0",
"flag_in": "6.0",
"in": "6.0",
"flag_io": "6.0",
"io": "6.0",
"flag_iq": "6.0",
"iq": "6.0",
"flag_ir": "6.0",
"ir": "6.0",
"flag_is": "6.0",
"is": "6.0",
"flag_it": "6.0",
"it": "6.0",
"flag_je": "6.0",
"je": "6.0",
"flag_jm": "6.0",
"jm": "6.0",
"flag_jo": "6.0",
"jo": "6.0",
"flag_jp": "6.0",
"jp": "6.0",
"flag_ke": "6.0",
"ke": "6.0",
"flag_kg": "6.0",
"kg": "6.0",
"flag_kh": "6.0",
"kh": "6.0",
"flag_ki": "6.0",
"ki": "6.0",
"flag_km": "6.0",
"km": "6.0",
"flag_kn": "6.0",
"kn": "6.0",
"flag_kp": "6.0",
"kp": "6.0",
"flag_kr": "6.0",
"kr": "6.0",
"flag_kw": "6.0",
"kw": "6.0",
"flag_ky": "6.0",
"ky": "6.0",
"flag_kz": "6.0",
"kz": "6.0",
"flag_la": "6.0",
"la": "6.0",
"flag_lb": "6.0",
"lb": "6.0",
"flag_lc": "6.0",
"lc": "6.0",
"flag_li": "6.0",
"li": "6.0",
"flag_lk": "6.0",
"lk": "6.0",
"flag_lr": "6.0",
"lr": "6.0",
"flag_ls": "6.0",
"ls": "6.0",
"flag_lt": "6.0",
"lt": "6.0",
"flag_lu": "6.0",
"lu": "6.0",
"flag_lv": "6.0",
"lv": "6.0",
"flag_ly": "6.0",
"ly": "6.0",
"flag_ma": "6.0",
"ma": "6.0",
"flag_mc": "6.0",
"mc": "6.0",
"flag_md": "6.0",
"md": "6.0",
"flag_me": "6.0",
"me": "6.0",
"flag_mf": "6.0",
"mf": "6.0",
"flag_mg": "6.0",
"mg": "6.0",
"flag_mh": "6.0",
"mh": "6.0",
"flag_mk": "6.0",
"mk": "6.0",
"flag_ml": "6.0",
"ml": "6.0",
"flag_mm": "6.0",
"mm": "6.0",
"flag_mn": "6.0",
"mn": "6.0",
"flag_mo": "6.0",
"mo": "6.0",
"flag_mp": "6.0",
"mp": "6.0",
"flag_mq": "6.0",
"mq": "6.0",
"flag_mr": "6.0",
"mr": "6.0",
"flag_ms": "6.0",
"ms": "6.0",
"flag_mt": "6.0",
"mt": "6.0",
"flag_mu": "6.0",
"mu": "6.0",
"flag_mv": "6.0",
"mv": "6.0",
"flag_mw": "6.0",
"mw": "6.0",
"flag_mx": "6.0",
"mx": "6.0",
"flag_my": "6.0",
"my": "6.0",
"flag_mz": "6.0",
"mz": "6.0",
"flag_na": "6.0",
"na": "6.0",
"flag_nc": "6.0",
"nc": "6.0",
"flag_ne": "6.0",
"ne": "6.0",
"flag_nf": "6.0",
"nf": "6.0",
"flag_ng": "6.0",
"nigeria": "6.0",
"flag_ni": "6.0",
"ni": "6.0",
"flag_nl": "6.0",
"nl": "6.0",
"flag_no": "6.0",
"no": "6.0",
"flag_np": "6.0",
"np": "6.0",
"flag_nr": "6.0",
"nr": "6.0",
"flag_nu": "6.0",
"nu": "6.0",
"flag_nz": "6.0",
"nz": "6.0",
"flag_om": "6.0",
"om": "6.0",
"flag_pa": "6.0",
"pa": "6.0",
"flag_pe": "6.0",
"pe": "6.0",
"flag_pf": "6.0",
"pf": "6.0",
"flag_pg": "6.0",
"pg": "6.0",
"flag_ph": "6.0",
"ph": "6.0",
"flag_pk": "6.0",
"pk": "6.0",
"flag_pl": "6.0",
"pl": "6.0",
"flag_pm": "6.0",
"pm": "6.0",
"flag_pn": "6.0",
"pn": "6.0",
"flag_pr": "6.0",
"pr": "6.0",
"flag_ps": "6.0",
"ps": "6.0",
"flag_pt": "6.0",
"pt": "6.0",
"flag_pw": "6.0",
"pw": "6.0",
"flag_py": "6.0",
"py": "6.0",
"flag_qa": "6.0",
"qa": "6.0",
"flag_re": "6.0",
"re": "6.0",
"flag_ro": "6.0",
"ro": "6.0",
"flag_rs": "6.0",
"rs": "6.0",
"flag_ru": "6.0",
"ru": "6.0",
"flag_rw": "6.0",
"rw": "6.0",
"flag_sa": "6.0",
"saudiarabia": "6.0",
"saudi": "6.0",
"flag_sb": "6.0",
"sb": "6.0",
"flag_sc": "6.0",
"sc": "6.0",
"flag_sd": "6.0",
"sd": "6.0",
"flag_se": "6.0",
"se": "6.0",
"flag_sg": "6.0",
"sg": "6.0",
"flag_sh": "6.0",
"sh": "6.0",
"flag_si": "6.0",
"si": "6.0",
"flag_sj": "6.0",
"sj": "6.0",
"flag_sk": "6.0",
"sk": "6.0",
"flag_sl": "6.0",
"sl": "6.0",
"flag_sm": "6.0",
"sm": "6.0",
"flag_sn": "6.0",
"sn": "6.0",
"flag_so": "6.0",
"so": "6.0",
"flag_sr": "6.0",
"sr": "6.0",
"flag_ss": "6.0",
"ss": "6.0",
"flag_st": "6.0",
"st": "6.0",
"flag_sv": "6.0",
"sv": "6.0",
"flag_sx": "6.0",
"sx": "6.0",
"flag_sy": "6.0",
"sy": "6.0",
"flag_sz": "6.0",
"sz": "6.0",
"flag_ta": "6.0",
"ta": "6.0",
"flag_tc": "6.0",
"tc": "6.0",
"flag_td": "6.0",
"td": "6.0",
"flag_tf": "6.0",
"tf": "6.0",
"flag_tg": "6.0",
"tg": "6.0",
"flag_th": "6.0",
"th": "6.0",
"flag_tj": "6.0",
"tj": "6.0",
"flag_tk": "6.0",
"tk": "6.0",
"flag_tl": "6.0",
"tl": "6.0",
"flag_tm": "6.0",
"turkmenistan": "6.0",
"flag_tn": "6.0",
"tn": "6.0",
"flag_to": "6.0",
"to": "6.0",
"flag_tr": "6.0",
"tr": "6.0",
"flag_tt": "6.0",
"tt": "6.0",
"flag_tv": "6.0",
"tuvalu": "6.0",
"flag_tw": "6.0",
"tw": "6.0",
"flag_tz": "6.0",
"tz": "6.0",
"flag_ua": "6.0",
"ua": "6.0",
"flag_ug": "6.0",
"ug": "6.0",
"flag_um": "6.0",
"um": "6.0",
"flag_us": "6.0",
"us": "6.0",
"flag_uy": "6.0",
"uy": "6.0",
"flag_uz": "6.0",
"uz": "6.0",
"flag_va": "6.0",
"va": "6.0",
"flag_vc": "6.0",
"vc": "6.0",
"flag_ve": "6.0",
"ve": "6.0",
"flag_vg": "6.0",
"vg": "6.0",
"flag_vi": "6.0",
"vi": "6.0",
"flag_vn": "6.0",
"vn": "6.0",
"flag_vu": "6.0",
"vu": "6.0",
"flag_wf": "6.0",
"wf": "6.0",
"flag_ws": "6.0",
"ws": "6.0",
"flag_xk": "6.0",
"xk": "6.0",
"flag_ye": "6.0",
"ye": "6.0",
"flag_yt": "6.0",
"yt": "6.0",
"flag_za": "6.0",
"za": "6.0",
"flag_zm": "6.0",
"zm": "6.0",
"flag_zw": "6.0",
"zw": "6.0",
"regional_indicator_z": "6.0",
"regional_indicator_y": "6.0",
"regional_indicator_x": "6.0",
"regional_indicator_w": "6.0",
"regional_indicator_v": "6.0",
"regional_indicator_u": "6.0",
"regional_indicator_t": "6.0",
"regional_indicator_s": "6.0",
"regional_indicator_r": "6.0",
"regional_indicator_q": "6.0",
"regional_indicator_p": "6.0",
"regional_indicator_o": "6.0",
"regional_indicator_n": "6.0",
"regional_indicator_m": "6.0",
"regional_indicator_l": "6.0",
"regional_indicator_k": "6.0",
"regional_indicator_j": "6.0",
"regional_indicator_i": "6.0",
"regional_indicator_h": "6.0",
"regional_indicator_g": "6.0",
"regional_indicator_f": "6.0",
"regional_indicator_e": "6.0",
"regional_indicator_d": "6.0",
"regional_indicator_c": "6.0",
"regional_indicator_b": "6.0",
"regional_indicator_a": "6.0",
"large_blue_circle": "6.0",
"ten": "6.0"
}
\ No newline at end of file
......@@ -8,7 +8,6 @@ module Banzai
# Based on HTML::Pipeline::EmojiFilter
class EmojiFilter < HTML::Pipeline::Filter
IGNORED_ANCESTOR_TAGS = %w(pre code tt).to_set
IGNORE_UNICODE_EMOJIS = %w(™ © ®).freeze
def call
doc.xpath('descendant-or-self::text()').each do |node|
......@@ -35,7 +34,8 @@ module Banzai
def emoji_name_element_unicode_filter(text)
text.gsub(emoji_pattern) do |match|
name = Regexp.last_match(1)
Gitlab::Emoji.gl_emoji_tag(name)
emoji = TanukiEmoji.find_by_alpha_code(name)
Gitlab::Emoji.gl_emoji_tag(emoji)
end
end
......@@ -46,26 +46,19 @@ module Banzai
# Returns a String with unicode emoji replaced with gl-emoji unicode.
def emoji_unicode_element_unicode_filter(text)
text.gsub(emoji_unicode_pattern) do |moji|
emoji_info = Gitlab::Emoji.emojis_by_moji[moji]
Gitlab::Emoji.gl_emoji_tag(emoji_info['name'])
emoji = TanukiEmoji.find_by_codepoints(moji)
Gitlab::Emoji.gl_emoji_tag(emoji)
end
end
# Build a regexp that matches all valid :emoji: names.
def self.emoji_pattern
@emoji_pattern ||=
%r{(?<=[^[:alnum:]:]|\n|^)
:(#{Gitlab::Emoji.emojis_names.map { |name| Regexp.escape(name) }.join('|')}):
(?=[^[:alnum:]:]|$)}x
@emoji_pattern ||= TanukiEmoji.index.alpha_code_pattern
end
# Build a regexp that matches all valid unicode emojis names.
def self.emoji_unicode_pattern
@emoji_unicode_pattern ||=
begin
filtered_emojis = Gitlab::Emoji.emojis_unicodes - IGNORE_UNICODE_EMOJIS
/(#{filtered_emojis.map { |moji| Regexp.escape(moji) }.join('|')})/
end
@emoji_unicode_pattern ||= TanukiEmoji.index.codepoints_pattern
end
private
......
......@@ -4,40 +4,15 @@ module Gitlab
module Emoji
extend self
def emojis
Gemojione.index.instance_variable_get(:@emoji_by_name)
end
def emojis_by_moji
Gemojione.index.instance_variable_get(:@emoji_by_moji)
end
def emojis_unicodes
emojis_by_moji.keys
end
def emojis_names
emojis.keys
end
def emojis_aliases
@emoji_aliases ||= Gitlab::Json.parse(File.read(Rails.root.join('fixtures', 'emojis', 'aliases.json')))
end
def emoji_filename(name)
emojis[name]["unicode"]
end
def emoji_unicode_filename(moji)
emojis_by_moji[moji]["unicode"]
end
def emoji_unicode_version(name)
emoji_unicode_versions_by_name[name]
end
# When updating emoji assets increase the version below
# and update the version number in `app/assets/javascripts/emoji/index.js`
EMOJI_VERSION = 1
def normalize_emoji_name(name)
emojis_aliases[name] || name
# Return a Pathname to emoji's current versioned folder
#
# @return [Pathname] Absolute Path to versioned emojis folder in `public`
def emoji_public_absolute_path
Rails.root.join("public/-/emojis/#{EMOJI_VERSION}")
end
def emoji_image_tag(name, src)
......@@ -54,23 +29,19 @@ module Gitlab
ActionController::Base.helpers.tag(:img, image_options)
end
def emoji_exists?(name)
emojis.has_key?(name)
end
# CSS sprite fallback takes precedence over image fallback
def gl_emoji_tag(name, options = {})
emoji_name = emojis_aliases[name] || name
emoji_info = emojis[emoji_name]
return unless emoji_info
# @param [TanukiEmoji::Character] emoji
# @param [Hash] options
def gl_emoji_tag(emoji, options = {})
return unless emoji
data = {
name: emoji_name,
unicode_version: emoji_unicode_version(emoji_name)
name: emoji.name,
unicode_version: emoji.unicode_version
}
options = { title: emoji_info['description'], data: data }.merge(options)
options = { title: emoji.description, data: data }.merge(options)
ActionController::Base.helpers.content_tag('gl-emoji', emoji_info['moji'], options)
ActionController::Base.helpers.content_tag('gl-emoji', emoji.codepoints, options)
end
def custom_emoji_tag(name, image_source)
......@@ -82,12 +53,5 @@ module Gitlab
emoji_image_tag(name, image_source).html_safe
end
end
private
def emoji_unicode_versions_by_name
@emoji_unicode_versions_by_name ||=
Gitlab::Json.parse(File.read(Rails.root.join('fixtures', 'emojis', 'emoji-unicode-version-map.json')))
end
end
end
# frozen_string_literal: true
namespace :gemojione do
desc 'Generates Emoji SHA256 digests'
task aliases: ['yarn:check', 'environment'] do
require 'json'
namespace :tanuki_emoji do
desc 'Generates Emoji aliases fixtures'
task aliases: :environment do
aliases = {}
index_file = File.join(Rails.root, 'fixtures', 'emojis', 'index.json')
index = Gitlab::Json.parse(File.read(index_file))
index.each_pair do |key, data|
data['aliases'].each do |a|
a.tr!(':', '')
aliases[a] = key
TanukiEmoji.index.all.each do |emoji|
emoji.aliases.each do |emoji_alias|
aliases[TanukiEmoji::Character.format_name(emoji_alias)] = emoji.name
end
end
out = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json')
File.open(out, 'w') do |handle|
aliases_json_file = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json')
File.open(aliases_json_file, 'w') do |handle|
handle.write(Gitlab::Json.pretty_generate(aliases, indent: ' ', space: '', space_before: ''))
end
end
task digests: ['yarn:check', 'environment'] do
desc 'Generates Emoji SHA256 digests'
task digests: :environment do
require 'digest/sha2'
require 'json'
# We don't have `node_modules` available in built versions of GitLab
FileUtils.cp_r(Rails.root.join('node_modules', 'emoji-unicode-version', 'emoji-unicode-version-map.json'), File.join(Rails.root, 'fixtures', 'emojis'))
digest_emoji_map = {}
emojis_map = {}
dir = Gemojione.images_path
resultant_emoji_map = {}
resultant_emoji_map_new = {}
TanukiEmoji.index.all.each do |emoji|
emoji_path = Gitlab::Emoji.emoji_public_absolute_path.join("#{emoji.name}.png")
Gitlab::Emoji.emojis.each do |name, emoji_hash|
# Ignore aliases
unless Gitlab::Emoji.emojis_aliases.key?(name)
fpath = File.join(dir, "#{emoji_hash['unicode']}.png")
hash_digest = Digest::SHA256.file(fpath).hexdigest
digest_entry = {
category: emoji.category,
moji: emoji.codepoints,
description: emoji.description,
unicodeVersion: emoji.unicode_version,
digest: Digest::SHA256.file(emoji_path).hexdigest
}
category = emoji_hash['category']
if name == 'gay_pride_flag'
category = 'flags'
end
entry = {
category: category,
moji: emoji_hash['moji'],
description: emoji_hash['description'],
unicodeVersion: Gitlab::Emoji.emoji_unicode_version(name),
digest: hash_digest
}
digest_emoji_map[emoji.name] = digest_entry
resultant_emoji_map[name] = entry
# Our new map is only characters to make the json substantially smaller
emoji_entry = {
c: emoji.category,
e: emoji.codepoints,
d: emoji.description,
u: emoji.unicode_version
}
# Our new map is only characters to make the json substantially smaller
new_entry = {
c: category,
e: emoji_hash['moji'],
d: emoji_hash['description'],
u: Gitlab::Emoji.emoji_unicode_version(name)
}
emojis_map[emoji.name] = emoji_entry
end
resultant_emoji_map_new[name] = new_entry
end
digests_json = File.join(Rails.root, 'fixtures', 'emojis', 'digests.json')
File.open(digests_json, 'w') do |handle|
handle.write(Gitlab::Json.pretty_generate(digest_emoji_map))
end
out = File.join(Rails.root, 'fixtures', 'emojis', 'digests.json')
File.open(out, 'w') do |handle|
handle.write(Gitlab::Json.pretty_generate(resultant_emoji_map))
emojis_json = Gitlab::Emoji.emoji_public_absolute_path.join('emojis.json')
File.open(emojis_json, 'w') do |handle|
handle.write(Gitlab::Json.pretty_generate(emojis_map))
end
end
desc 'Import emoji assets from TanukiEmoji to versioned folder'
task import: :environment do
require 'mini_magick'
# Setting to the same size as previous gemojione images
EMOJI_SIZE = 64
emoji_dir = Gitlab::Emoji.emoji_public_absolute_path
puts "Importing emojis into: #{emoji_dir} ..."
out_new = File.join(Rails.root, 'public', '-', 'emojis', '1', 'emojis.json')
File.open(out_new, 'w') do |handle|
handle.write(Gitlab::Json.pretty_generate(resultant_emoji_map_new))
# Re-create the assets folder and copy emojis renaming them to use name instead of unicode hex
FileUtils.rm_rf(emoji_dir) if Dir.exist?(emoji_dir)
FileUtils.mkdir_p(emoji_dir, mode: 0700)
TanukiEmoji.index.all.each do |emoji|
source = File.join(TanukiEmoji.images_path, emoji.image_name)
destination = File.join(emoji_dir, "#{emoji.name}.png")
FileUtils.cp(source, destination)
resize!(destination, EMOJI_SIZE)
print emoji.codepoints
end
puts
puts 'Done!'
end
# This task will generate a standard and Retina sprite of all of the current
# Gemojione Emojis, with the accompanying SCSS map.
# TanukiEmoji Emojis, with the accompanying SCSS map.
#
# It will not appear in `rake -T` output, and the dependent gems are not
# included in the Gemfile by default, because this task will only be needed
# occasionally, such as when new Emojis are added to Gemojione.
# occasionally, such as when new Emojis are added to TanukiEmoji.
task sprite: :environment do
begin
require 'sprite_factory'
# Sprite-Factory still requires rmagick, but maybe could be migrated to support minimagick
# Upstream issue: https://github.com/jakesgordon/sprite-factory/issues/47#issuecomment-929302890
require 'rmagick'
rescue LoadError
# noop
......@@ -104,24 +113,9 @@ namespace :gemojione do
SPRITESHEET_WIDTH = 860
SPRITESHEET_HEIGHT = 840
# Set up a map to rename image files
emoji_unicode_string_to_name_map = {}
Gitlab::Emoji.emojis.each do |name, emoji_hash|
# Ignore aliases
unless Gitlab::Emoji.emojis_aliases.key?(name)
emoji_unicode_string_to_name_map[emoji_hash['unicode']] = name
end
end
emoji_dir = Gitlab::Emoji.emoji_public_absolute_path
# Copy the Gemojione assets to the temporary folder for renaming
emoji_dir = "app/assets/images/emoji"
FileUtils.rm_rf(emoji_dir)
FileUtils.mkdir_p(emoji_dir, mode: 0700)
FileUtils.cp_r(File.join(Gemojione.images_path, '.'), emoji_dir)
Dir[File.join(emoji_dir, "**/*.png")].each do |png|
image_path = png
rename_to_named_emoji_image!(emoji_unicode_string_to_name_map, image_path)
end
puts "Preparing sprites for regular size: #{SIZE}px..."
Dir.mktmpdir do |tmpdir|
FileUtils.cp_r(File.join(emoji_dir, '.'), tmpdir)
......@@ -130,10 +124,16 @@ namespace :gemojione do
Dir["**/*.png"].each do |png|
tmp_image_path = File.join(tmpdir, png)
resize!(tmp_image_path, SIZE)
print '.'
end
end
puts ' Done!'
style_path = Rails.root.join(*%w(app assets stylesheets framework emoji_sprites.scss))
puts "\n"
style_path = Rails.root.join(*%w(app assets stylesheets emoji_sprites.scss))
print 'Compiling sprites regular sprites... '
# Combine the resized assets into a packed sprite and re-generate the SCSS
SpriteFactory.cssurl = "image-url('$IMAGE')"
......@@ -165,31 +165,44 @@ namespace :gemojione do
height: #{SIZE}px;
width: #{SIZE}px;
/* stylelint-disable media-feature-name-no-vendor-prefix */
@media only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and (min--moz-device-pixel-ratio: 2),
only screen and (-o-min-device-pixel-ratio: 2/1),
only screen and (min-device-pixel-ratio: 2),
only screen and (min-resolution: 192dpi),
only screen and (min-resolution: 2dppx) {
only screen and (min--moz-device-pixel-ratio: 2),
only screen and (-o-min-device-pixel-ratio: 2/1),
only screen and (min-device-pixel-ratio: 2),
only screen and (min-resolution: 192dpi),
only screen and (min-resolution: 2dppx) {
background-image: image-url('emoji@2x.png');
background-size: #{SPRITESHEET_WIDTH}px #{SPRITESHEET_HEIGHT}px;
}
/* stylelint-enable media-feature-name-no-vendor-prefix */
}
CSS
end
end
puts 'Done!'
puts "\n"
puts "Preparing sprites for HiDPI size: #{RETINA}px..."
# Now do it again but for Retina
Dir.mktmpdir do |tmpdir|
# Copy the Gemojione assets to the temporary folder for resizing
# Copy the TanukiEmoji assets to the temporary folder for resizing
FileUtils.cp_r(File.join(emoji_dir, '.'), tmpdir)
Dir.chdir(tmpdir) do
Dir["**/*.png"].each do |png|
tmp_image_path = File.join(tmpdir, png)
resize!(tmp_image_path, RETINA)
print '.'
end
end
puts ' Done!'
puts "\n"
print 'Compiling HiDPI sprites...'
# Combine the resized assets into a packed sprite and re-generate the SCSS
SpriteFactory.run!(tmpdir, {
......@@ -200,20 +213,38 @@ namespace :gemojione do
layout: :packed
})
end
puts ' Done!'
end
def check_requirements!
return if defined?(SpriteFactory) && defined?(Magick)
puts <<-MSG.strip_heredoc
This task is disabled by default and should only be run when the Gemojione
unless defined?(Magick)
puts <<~MSG
This task is disabled by default and should only be run when the TanukiEmoji
gem is updated with new Emojis.
To enable this task, *temporarily* add the following lines to Gemfile and
re-bundle:
gem 'sprite-factory'
gem 'rmagick'
gem 'rmagick', '~> 3.2'
It depends on ImageMagick 6, which can be installed via HomeBrew with:
brew unlink imagemagick
brew install imagemagick@6 && brew link imagemagick@6 --force
MSG
exit 1
end
return if Dir.exist? Gitlab::Emoji.emoji_public_absolute_path
puts <<~MSG
You first need to import the assets for Emoji version: #{Gitlab::Emoji::EMOJI_VERSION}
Run the following task:
rake tanuki_emoji:import
MSG
exit 1
......@@ -221,25 +252,9 @@ namespace :gemojione do
def resize!(image_path, size)
# Resize the image in-place, save it, and free the object
image = Magick::Image.read(image_path).first
image.resize!(size, size)
image.write(image_path) { self.quality = 100 }
image.destroy!
end
EMOJI_IMAGE_PATH_RE = /(.*?)(([0-9a-f]-?)+)\.png$/i.freeze
def rename_to_named_emoji_image!(emoji_unicode_string_to_name_map, image_path)
# Rename file from unicode to emoji name
matches = EMOJI_IMAGE_PATH_RE.match(image_path)
preceding_path = matches[1]
unicode_string = matches[2]
name = emoji_unicode_string_to_name_map[unicode_string]
if name
new_png_path = File.join(preceding_path, "#{name}.png")
FileUtils.mv(image_path, new_png_path)
new_png_path
else
puts "Warning: emoji_unicode_string_to_name_map missing entry for #{unicode_string}. Full path: #{image_path}"
end
image = MiniMagick::Image.open(image_path)
image.quality(100)
image.resize("#{size}x#{size}")
image.write(image_path)
end
end
......@@ -56,13 +56,13 @@ describe('gl_emoji', () => {
'bomb emoji just with name attribute',
'<gl-emoji data-name="bomb"></gl-emoji>',
'<gl-emoji data-name="bomb" data-unicode-version="6.0" title="bomb">💣</gl-emoji>',
'<gl-emoji data-name="bomb" data-unicode-version="6.0" title="bomb"><img class="emoji" title=":bomb:" alt=":bomb:" src="/-/emojis/1/bomb.png" width="20" height="20" align="absmiddle"></gl-emoji>',
`<gl-emoji data-name="bomb" data-unicode-version="6.0" title="bomb"><img class="emoji" title=":bomb:" alt=":bomb:" src="/-/emojis/${EMOJI_VERSION}/bomb.png" width="20" height="20" align="absmiddle"></gl-emoji>`,
],
[
'bomb emoji with name attribute and unicode version',
'<gl-emoji data-name="bomb" data-unicode-version="6.0">💣</gl-emoji>',
'<gl-emoji data-name="bomb" data-unicode-version="6.0">💣</gl-emoji>',
'<gl-emoji data-name="bomb" data-unicode-version="6.0"><img class="emoji" title=":bomb:" alt=":bomb:" src="/-/emojis/1/bomb.png" width="20" height="20" align="absmiddle"></gl-emoji>',
`<gl-emoji data-name="bomb" data-unicode-version="6.0"><img class="emoji" title=":bomb:" alt=":bomb:" src="/-/emojis/${EMOJI_VERSION}/bomb.png" width="20" height="20" align="absmiddle"></gl-emoji>`,
],
[
'bomb emoji with sprite fallback',
......@@ -80,7 +80,7 @@ describe('gl_emoji', () => {
'invalid emoji',
'<gl-emoji data-name="invalid_emoji"></gl-emoji>',
'<gl-emoji data-name="grey_question" data-unicode-version="6.0" title="white question mark ornament">❔</gl-emoji>',
'<gl-emoji data-name="grey_question" data-unicode-version="6.0" title="white question mark ornament"><img class="emoji" title=":grey_question:" alt=":grey_question:" src="/-/emojis/1/grey_question.png" width="20" height="20" align="absmiddle"></gl-emoji>',
`<gl-emoji data-name="grey_question" data-unicode-version="6.0" title="white question mark ornament"><img class="emoji" title=":grey_question:" alt=":grey_question:" src="/-/emojis/${EMOJI_VERSION}/grey_question.png" width="20" height="20" align="absmiddle"></gl-emoji>`,
],
])('%s', (name, markup, withEmojiSupport, withoutEmojiSupport) => {
it(`renders correctly with emoji support`, async () => {
......
......@@ -6,6 +6,7 @@ RSpec.describe EmojiHelper do
describe '#emoji_icon' do
let(:options) { {} }
let(:emoji_text) { 'rocket' }
let(:unicode_version) { '6.0' }
let(:aria_hidden_option) { "aria-hidden=\"true\"" }
subject { helper.emoji_icon(emoji_text, options) }
......@@ -14,7 +15,7 @@ RSpec.describe EmojiHelper do
is_expected.to include('<gl-emoji',
"title=\"#{emoji_text}\"",
"data-name=\"#{emoji_text}\"",
"data-unicode-version=\"#{::Gitlab::Emoji.emoji_unicode_version(emoji_text)}\"")
"data-unicode-version=\"#{unicode_version}\"")
is_expected.not_to include(aria_hidden_option)
end
......@@ -25,7 +26,7 @@ RSpec.describe EmojiHelper do
is_expected.to include('<gl-emoji',
"title=\"#{emoji_text}\"",
"data-name=\"#{emoji_text}\"",
"data-unicode-version=\"#{::Gitlab::Emoji.emoji_unicode_version(emoji_text)}\"",
"data-unicode-version=\"#{unicode_version}\"",
aria_hidden_option)
end
end
......
......@@ -28,9 +28,9 @@ RSpec.describe Banzai::Filter::EmojiFilter do
it 'replaces name versions of trademark, copyright, and registered trademark' do
doc = filter('<p>:tm: :copyright: :registered:</p>')
expect(doc.css('gl-emoji')[0].text).to eq '™'
expect(doc.css('gl-emoji')[1].text).to eq '©'
expect(doc.css('gl-emoji')[2].text).to eq '®'
expect(doc.css('gl-emoji')[0].text).to eq '™'
expect(doc.css('gl-emoji')[1].text).to eq '
expect(doc.css('gl-emoji')[2].text).to eq '
end
it 'correctly encodes the URL' do
......
......@@ -3,18 +3,20 @@
require 'spec_helper'
RSpec.describe Banzai::Pipeline::EmojiPipeline do
let(:emoji) { TanukiEmoji.find_by_alpha_code('100') }
def parse(text)
described_class.to_html(text, {})
end
it 'replaces emoji' do
expected_result = "Hello world #{Gitlab::Emoji.gl_emoji_tag('100')}"
expected_result = "Hello world #{Gitlab::Emoji.gl_emoji_tag(emoji)}"
expect(parse('Hello world :100:')).to eq(expected_result)
end
it 'filters out HTML tags' do
expected_result = "Hello &lt;b&gt;world&lt;/b&gt; #{Gitlab::Emoji.gl_emoji_tag('100')}"
expected_result = "Hello &lt;b&gt;world&lt;/b&gt; #{Gitlab::Emoji.gl_emoji_tag(emoji)}"
expect(parse('Hello <b>world</b> :100:')).to eq(expected_result)
end
......
......@@ -3,90 +3,6 @@
require 'spec_helper'
RSpec.describe Gitlab::Emoji do
let_it_be(:emojis) { Gemojione.index.instance_variable_get(:@emoji_by_name) }
let_it_be(:emojis_by_moji) { Gemojione.index.instance_variable_get(:@emoji_by_moji) }
let_it_be(:emoji_unicode_versions_by_name) { Gitlab::Json.parse(File.read(Rails.root.join('fixtures', 'emojis', 'emoji-unicode-version-map.json'))) }
let_it_be(:emojis_aliases) { Gitlab::Json.parse(File.read(Rails.root.join('fixtures', 'emojis', 'aliases.json'))) }
describe '.emojis' do
it 'returns emojis' do
current_emojis = described_class.emojis
expect(current_emojis).to eq(emojis)
end
end
describe '.emojis_by_moji' do
it 'return emojis by moji' do
current_emojis_by_moji = described_class.emojis_by_moji
expect(current_emojis_by_moji).to eq(emojis_by_moji)
end
end
describe '.emojis_unicodes' do
it 'returns emoji unicodes' do
emoji_keys = described_class.emojis_unicodes
expect(emoji_keys).to eq(emojis_by_moji.keys)
end
end
describe '.emojis_names' do
it 'returns emoji names' do
emoji_names = described_class.emojis_names
expect(emoji_names).to eq(emojis.keys)
end
end
describe '.emojis_aliases' do
it 'returns emoji aliases' do
emoji_aliases = described_class.emojis_aliases
expect(emoji_aliases).to eq(emojis_aliases)
end
end
describe '.emoji_filename' do
it 'returns emoji filename' do
# "100" => {"unicode"=>"1F4AF"...}
emoji_filename = described_class.emoji_filename('100')
expect(emoji_filename).to eq(emojis['100']['unicode'])
end
end
describe '.emoji_unicode_filename' do
it 'returns emoji unicode filename' do
emoji_unicode_filename = described_class.emoji_unicode_filename('💯')
expect(emoji_unicode_filename).to eq(emojis_by_moji['💯']['unicode'])
end
end
describe '.emoji_unicode_version' do
it 'returns emoji unicode version by name' do
emoji_unicode_version = described_class.emoji_unicode_version('100')
expect(emoji_unicode_version).to eq(emoji_unicode_versions_by_name['100'])
end
end
describe '.normalize_emoji_name' do
it 'returns same name if not found in aliases' do
emoji_name = described_class.normalize_emoji_name('random')
expect(emoji_name).to eq('random')
end
it 'returns name if name found in aliases' do
emoji_name = described_class.normalize_emoji_name('small_airplane')
expect(emoji_name).to eq(emojis_aliases['small_airplane'])
end
end
describe '.emoji_image_tag' do
it 'returns emoji image tag' do
emoji_image = described_class.emoji_image_tag('emoji_one', 'src_url')
......@@ -104,29 +20,17 @@ RSpec.describe Gitlab::Emoji do
end
end
describe '.emoji_exists?' do
it 'returns true if the name exists' do
emoji_exists = described_class.emoji_exists?('100')
expect(emoji_exists).to be_truthy
end
it 'returns false if the name does not exist' do
emoji_exists = described_class.emoji_exists?('random')
expect(emoji_exists).to be_falsey
end
end
describe '.gl_emoji_tag' do
it 'returns gl emoji tag if emoji is found' do
gl_tag = described_class.gl_emoji_tag('small_airplane')
emoji = TanukiEmoji.find_by_alpha_code('small_airplane')
gl_tag = described_class.gl_emoji_tag(emoji)
expect(gl_tag).to eq('<gl-emoji title="small airplane" data-name="airplane_small" data-unicode-version="7.0">🛩</gl-emoji>')
end
it 'returns nil if emoji name is not found' do
gl_tag = described_class.gl_emoji_tag('random')
it 'returns nil if emoji is not found' do
emoji = TanukiEmoji.find_by_alpha_code('random')
gl_tag = described_class.gl_emoji_tag(emoji)
expect(gl_tag).to be_nil
end
......
......@@ -14,7 +14,7 @@ RSpec.describe CustomEmoji do
end
describe 'exclusion of duplicated emoji' do
let(:emoji_name) { Gitlab::Emoji.emojis_names.sample }
let(:emoji_name) { TanukiEmoji.index.all.sample.name }
let(:group) { create(:group, :private) }
it 'disallows emoji names of built-in emoji' do
......
......@@ -6,21 +6,22 @@ RSpec.describe AwardEmojiPresenter do
let(:emoji_name) { 'thumbsup' }
let(:award_emoji) { build(:award_emoji, name: emoji_name) }
let(:presenter) { described_class.new(award_emoji) }
let(:emoji) { TanukiEmoji.find_by_alpha_code(emoji_name) }
describe '#description' do
it { expect(presenter.description).to eq Gitlab::Emoji.emojis[emoji_name]['description'] }
it { expect(presenter.description).to eq emoji.description }
end
describe '#unicode' do
it { expect(presenter.unicode).to eq Gitlab::Emoji.emojis[emoji_name]['unicode'] }
it { expect(presenter.unicode).to eq emoji.hex }
end
describe '#unicode_version' do
it { expect(presenter.unicode_version).to eq Gitlab::Emoji.emoji_unicode_version(emoji_name) }
it { expect(presenter.unicode_version).to eq('6.0') }
end
describe '#emoji' do
it { expect(presenter.emoji).to eq Gitlab::Emoji.emojis[emoji_name]['moji'] }
it { expect(presenter.emoji).to eq emoji.codepoints }
end
describe 'when presenting an award emoji with an invalid name' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe AwardEmojis::BaseService do
let(:awardable) { build(:note) }
let(:current_user) { build(:user) }
describe '.initialize' do
subject { described_class }
it 'uses same emoji name if not an alias' do
emoji_name = 'horse'
expect(subject.new(awardable, emoji_name, current_user).name).to eq(emoji_name)
end
it 'uses emoji original name if its an alias' do
emoji_alias = 'small_airplane'
emoji_name = 'airplane_small'
expect(subject.new(awardable, emoji_alias, current_user).name).to eq(emoji_name)
end
end
end
......@@ -53,7 +53,7 @@ RSpec.describe Users::UpdateService do
result = update_user(user, status: { emoji: "Moo!" })
expect(result[:status]).to eq(:error)
expect(result[:message]).to eq("Emoji is not included in the list")
expect(result[:message]).to eq("Emoji is not a valid emoji name")
end
it 'updates user detail with provided attributes' do
......
......@@ -4810,11 +4810,6 @@ emoji-regex@^8.0.0:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
emoji-unicode-version@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/emoji-unicode-version/-/emoji-unicode-version-0.2.1.tgz#0ebf3666b5414097971d34994e299fce75cdbafc"
integrity sha1-Dr82ZrVBQJeXHTSZTimfznXNuvw=
emojis-list@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment