pwu / rpms / ibus

Forked from rpms/ibus 5 years ago
Clone
Blob Blame History Raw
From 0432aa66b8728bc266da3c2cca84587bc44b3557 Mon Sep 17 00:00:00 2001
From: Matthias Clasen <mclasen@redhat.com>
Date: Tue, 8 Mar 2016 11:16:24 +0900
Subject: [PATCH] Don't warn if DISPLAY is not set

This is normal under Wayland, and not worth warning about.
The warnings disrupt unit tests in GNOME continuous, which
treat warnings as fatal.

BUG=https://github.com/ibus/ibus/pull/1844
R=shawn.p.huang@gmail.com

Review URL: https://codereview.appspot.com/289430043

Patch from Matthias Clasen <mclasen@redhat.com>.
---
 src/ibusshare.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/ibusshare.c b/src/ibusshare.c
index 63800a6..b793a96 100644
--- a/src/ibusshare.c
+++ b/src/ibusshare.c
@@ -113,10 +113,7 @@ ibus_get_socket_path (void)
             display = g_strdup (_display);
         }
 
-        if (display == NULL) {
-            g_warning ("DISPLAY is empty! We use default DISPLAY (:0.0)");
-        }
-        else {
+        if (display) {
             p = display;
             hostname = display;
             for (; *p != ':' && *p != '\0'; p++);
-- 
2.7.4

From 84c18f1d382548c52138822a11473d2dac79e485 Mon Sep 17 00:00:00 2001
From: Rui Matos <tiagomatos@gmail.com>
Date: Wed, 25 May 2016 11:21:09 +0900
Subject: [PATCH] Install a DBus service file

With the transition to user scoped DBus sessions (vs. login sessions)
there's a need to start ibus-daemon via DBus activation so that the
process gets properly tracked and disposed of when the login session
ends. Otherwise the ibus-daemon process lingers on and keeps the whole
login session up.

We already connect and own a well known name on DBus. The remaining
missing piece is the DBus service file which we introduce here.

BUG=https://github.com/ibus/ibus/pull/1853
R=Shawn.P.Huang@gmail.com

Review URL: https://codereview.appspot.com/295340043

Patch from Rui Matos <tiagomatos@gmail.com>.
---
 bus/Makefile.am                     | 11 +++++++++++
 bus/org.freedesktop.IBus.service.in |  3 +++
 2 files changed, 14 insertions(+)
 create mode 100644 bus/org.freedesktop.IBus.service.in

diff --git a/bus/Makefile.am b/bus/Makefile.am
index 26cb2f8..4dabacf 100644
--- a/bus/Makefile.am
+++ b/bus/Makefile.am
@@ -174,4 +174,15 @@ man_onedir = $(mandir)/man1
 %.1.gz: %.1
 	$(AM_V_GEN) gzip -c $< > $@.tmp && mv $@.tmp $@
 
+
+dbusservice_in_files = org.freedesktop.IBus.service.in
+dbusservice_DATA = $(dbusservice_in_files:.service.in=.service)
+dbusservicedir=${datadir}/dbus-1/services
+
+org.freedesktop.IBus.service: org.freedesktop.IBus.service.in
+	$(AM_V_GEN) sed -e "s|\@bindir\@|$(bindir)|" $< > $@.tmp && mv $@.tmp $@
+
+EXTRA_DIST += $(dbusservice_in_files)
+CLEANFILES += $(dbusservice_DATA)
+
 -include $(top_srcdir)/git.mk
diff --git a/bus/org.freedesktop.IBus.service.in b/bus/org.freedesktop.IBus.service.in
new file mode 100644
index 0000000..cc88834
--- /dev/null
+++ b/bus/org.freedesktop.IBus.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.freedesktop.IBus
+Exec=@bindir@/ibus-daemon --replace --xim --panel disable
-- 
2.7.4

From 3ef21fef0135f7b4fe9611d201f15611734f6c51 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
Date: Fri, 3 Jun 2016 11:52:29 +0900
Subject: [PATCH] client/gtk2: Fix SEGV with Wayland display

Delete gdk_display_get_name() in GTK clients because ibus-daemon
does not use gdk_display_get_name().
GdkX11Dislay and GdkX11Window does not work with Wayland.

BUG=https://github.com/ibus/ibus/issues/1859
R=Shawn.P.Huang@gmail.com

Review URL: https://codereview.appspot.com/301760043
---
 client/gtk2/ibusimcontext.c | 5 -----
 setup/main.py               | 7 +++++--
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
index 9d927e6..0df0062 100644
--- a/client/gtk2/ibusimcontext.c
+++ b/client/gtk2/ibusimcontext.c
@@ -583,11 +583,6 @@ ibus_im_context_class_init (IBusIMContextClass *class)
 
     /* init bus object */
     if (_bus == NULL) {
-        const gchar *dname = gdk_display_get_name (gdk_display_get_default ());
-        /* ibus-daemon uses DISPLAY variable. */
-        if (g_strcmp0 (dname, "Wayland") == 0)
-            dname = g_getenv ("DISPLAY");
-        ibus_set_display (dname);
         _bus = ibus_bus_new_async ();
 
         /* init the global fake context */
diff --git a/setup/main.py b/setup/main.py
index 26c2b0f..e1f7a9d 100644
--- a/setup/main.py
+++ b/setup/main.py
@@ -275,8 +275,11 @@ class Setup(object):
         self.__init_general()
 
     def __gdk_window_set_cb(self, object, pspec):
-        str = '%u' % GdkX11.X11Window.get_xid(object.get_window())
-        GLib.setenv('IBUS_SETUP_XID', str, True)
+        window = object.get_window()
+        if type(window) != GdkX11.X11Window:
+            return
+        s = '%u' % GdkX11.X11Window.get_xid(window)
+        GLib.setenv('IBUS_SETUP_XID', s, True)
 
     def __combobox_notify_active_engine_cb(self, combobox, property):
         engine = self.__combobox.get_active_engine()
-- 
2.7.4

From a598ae29223d1ca25e76bf7d7de9703f63ea337e Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
Date: Fri, 3 Jun 2016 19:44:11 +0900
Subject: [PATCH] ui/gtk3: Fix panel CSS format for GTK 3.20

CSS node names have been changed since GTK 3.20 and the font size and
widget color no longer work with the previous node names.

BUG=https://github.com/ibus/ibus/issues/1856

Review URL: https://codereview.appspot.com/297380043
---
 ui/gtk3/candidatearea.vala | 16 +++++++++++++---
 ui/gtk3/handle.vala        | 10 ++++++++--
 ui/gtk3/panel.vala         |  9 +++++++--
 3 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/ui/gtk3/candidatearea.vala b/ui/gtk3/candidatearea.vala
index c969312..3848f0d 100644
--- a/ui/gtk3/candidatearea.vala
+++ b/ui/gtk3/candidatearea.vala
@@ -3,7 +3,7 @@
  * ibus - The Input Bus
  *
  * Copyright(c) 2011-2015 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright(c) 2015 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright(c) 2015-2016 Takao Fujiwara <takao.fujiwara1@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -31,6 +31,10 @@ class CandidateArea : Gtk.Box {
     private uint m_focus_candidate;
     private bool m_show_cursor;
 
+    private bool m_use_latest_css_format =
+            ((Gtk.MAJOR_VERSION > 3) ||
+             (Gtk.MAJOR_VERSION == 3) && (Gtk.MINOR_VERSION >= 20));
+
     private const string LABELS[] = {
         "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.",
         "9.", "0.", "a.", "b.", "c.", "d.", "e.", "f."
@@ -103,7 +107,8 @@ class CandidateArea : Gtk.Box {
                 Pango.AttrList attrs = get_pango_attr_list_from_ibus_text(candidates[i]);
                 if (i == focus_candidate && show_cursor) {
                     Gtk.StyleContext context = m_candidates[i].get_style_context();
-                    Gdk.RGBA color = context.get_color(Gtk.StateFlags.SELECTED);
+                    Gdk.RGBA *color = null;
+                    context.get(Gtk.StateFlags.SELECTED, "color", out color);
                     Pango.Attribute pango_attr = Pango.attr_foreground_new(
                             (uint16)(color.red * uint16.MAX),
                             (uint16)(color.green * uint16.MAX),
@@ -112,7 +117,12 @@ class CandidateArea : Gtk.Box {
                     pango_attr.end_index = candidates[i].get_text().length;
                     attrs.insert((owned)pango_attr);
 
-                    color = context.get_background_color(Gtk.StateFlags.SELECTED);
+                    color = null;
+                    string bg_prop =
+                            m_use_latest_css_format
+                            ? "-gtk-secondary-caret-color"
+                            : "background-color";
+                    context.get(Gtk.StateFlags.SELECTED, bg_prop, out color);
                     pango_attr = Pango.attr_background_new(
                             (uint16)(color.red * uint16.MAX),
                             (uint16)(color.green * uint16.MAX),
diff --git a/ui/gtk3/handle.vala b/ui/gtk3/handle.vala
index 1edb537..bef5e8b 100644
--- a/ui/gtk3/handle.vala
+++ b/ui/gtk3/handle.vala
@@ -2,7 +2,8 @@
  *
  * ibus - The Input Bus
  *
- * Copyright(c) 2011-2015 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright(c) 2011-2016 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright(c) 2016 Takao Fujiwara <takao.fujiwara1@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -29,6 +30,11 @@ class Handle : Gtk.EventBox {
     public signal void move_end();
 
     public Handle() {
+        // Call base class constructor
+        GLib.Object(
+            name : "IBusHandle"
+        );
+
         set_size_request(6, -1);
         Gdk.EventMask mask = Gdk.EventMask.EXPOSURE_MASK |
                              Gdk.EventMask.BUTTON_PRESS_MASK |
@@ -42,7 +48,7 @@ class Handle : Gtk.EventBox {
         Gtk.CssProvider css_provider = new Gtk.CssProvider();
         try {
             css_provider.load_from_data(
-                    "GtkEventBox { background-color: gray }", -1);
+                    "#IBusHandle { background-color: gray }", -1);
         } catch (GLib.Error error) {
             warning("Parse error in Handle: %s", error.message);
         }
diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala
index 2ca3a5e..cc19350 100644
--- a/ui/gtk3/panel.vala
+++ b/ui/gtk3/panel.vala
@@ -3,7 +3,7 @@
  * ibus - The Input Bus
  *
  * Copyright(c) 2011-2014 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright(c) 2015 Takao Fujwiara <takao.fujiwara1@gmail.com>
+ * Copyright(c) 2015-2016 Takao Fujwiara <takao.fujiwara1@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -543,7 +543,12 @@ class Panel : IBus.PanelService {
             return;
         }
 
-        string data_format = "GtkLabel { font: %s; }";
+        string data_format = "label { font: %s; }";
+        if (Gtk.MAJOR_VERSION < 3 ||
+            (Gtk.MAJOR_VERSION == 3 && Gtk.MINOR_VERSION < 20)) {
+            data_format = "GtkLabel { font: %s; }";
+        }
+
         string data = data_format.printf(font_name);
         m_css_provider = new Gtk.CssProvider();
 
-- 
2.7.4

From 160d3c975af91eea6b8271b757be769b8ceef98d Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
Date: Tue, 21 Jun 2016 18:10:21 +0900
Subject: [PATCH 1/4] engine: Implement Emoji typing with XKB engines

Now Ctrl+Shift+e can convert an Emoji annotation to the Emoji characters
likes Ctrl+Shift+u.
The annotations are described as "Keywords" in the Unicode Emoji Data:
http://www.unicode.org/emoji/charts/emoji-list.html
'emoji-parser' compiles 'emoji-list.html' and generates 'emoji.dict'

Review URL: https://codereview.appspot.com/295610043
---
 configure.ac           |  16 ++
 src/Makefile.am        |  31 ++++
 src/emoji-parser.c     | 217 ++++++++++++++++++++++++
 src/ibusenginesimple.c | 443 ++++++++++++++++++++++++++++++++++++++++++++-----
 src/ibusutil.c         | 193 ++++++++++++++++++++-
 src/ibusutil.h         |  31 +++-
 6 files changed, 890 insertions(+), 41 deletions(-)
 create mode 100644 src/emoji-parser.c

diff --git a/configure.ac b/configure.ac
index 1e1f5dd..3128ef9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -599,6 +599,21 @@ if test x"$enable_libnotify" = x"yes"; then
     enable_libnotify="yes (enabled, use --disable-libnotify to disable)"
 fi
 
+# --disable-emoji-dict option.
+AC_ARG_ENABLE(emoji-dict,
+    AS_HELP_STRING([--disable-emoji-dict],
+                   [Do not build Emoji dict files]),
+    [enable_emoji_dict=$enableval],
+    [enable_emoji_dict=yes]
+)
+AM_CONDITIONAL([ENABLE_EMOJI_DICT], [test x"$enable_emoji_dict" = x"yes"])
+if test x"$enable_emoji_dict" = x"yes"; then
+    PKG_CHECK_MODULES(LIBXML2, [
+        libxml-2.0
+    ])
+    enable_emoji_dict="yes (enabled, use --disable-emoji-dict to disable)"
+fi
+
 # Check iso-codes.
 PKG_CHECK_MODULES(ISOCODES, [
     iso-codes
@@ -682,6 +697,7 @@ Build options:
   Panel icon                    "$IBUS_ICON_KEYBOARD"
   Enable surrounding-text       $enable_surrounding_text
   Enable libnotify              $enable_libnotify
+  Enable Emoji dict             $enable_emoji_dict
   Run test cases                $enable_tests
 ])
 
diff --git a/src/Makefile.am b/src/Makefile.am
index adaebe9..a33b67d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -231,7 +231,38 @@ ibusmarshalers.c: ibusmarshalers.h ibusmarshalers.list
 	$(GLIB_GENMARSHAL) --prefix=_ibus_marshal $(srcdir)/ibusmarshalers.list --body --internal) > $@.tmp && \
 	mv $@.tmp $@
 
+if ENABLE_EMOJI_DICT
+AM_CPPFLAGS += -DENABLE_EMOJI_DICT
+
+dictdir = $(pkgdatadir)/dicts
+dict_DATA = emoji.dict
+
+noinst_PROGRAMS = emoji-parser
+
+emoji.dict: emoji-parser emoji-list.html
+	$(builddir)/emoji-parser emoji-list.html $@
+
+emoji_parser_SOURCES =          \
+    emoji-parser.c              \
+    $(NULL)
+emoji_parser_CFLAGS =           \
+    $(GLIB2_CFLAGS)             \
+    $(LIBXML2_CFLAGS)           \
+    $(NULL)
+emoji_parser_LDADD =            \
+    $(GLIB2_LIBS)               \
+    $(LIBXML2_LIBS)             \
+    $(libibus)                  \
+    $(NULL)
+
+CLEANFILES +=                   \
+    $(dict_DATA)                \
+    $(NULL)
+endif
+
 EXTRA_DIST =                    \
+    emoji-list.html             \
+    emoji-parser.c              \
     ibusversion.h.in            \
     ibusmarshalers.list         \
     ibusenumtypes.h.template    \
diff --git a/src/emoji-parser.c b/src/emoji-parser.c
new file mode 100644
index 0000000..cf92fee
--- /dev/null
+++ b/src/emoji-parser.c
@@ -0,0 +1,217 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* vim:set et sts=4: */
+/* ibus - The Input Bus
+ * Copyright (C) 2016 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+/* Convert http://www.unicode.org/emoji/charts/emoji-list.html
+ * to the dictionary file which look up the Emoji from the annotation.
+ */
+
+#include <glib.h>
+#include <libxml/HTMLparser.h>
+#include <libgen.h>
+
+#include "ibusutil.h"
+
+typedef struct _EmojiData EmojiData;
+struct _EmojiData {
+    gchar      *class;
+    gchar      *emoji;
+    GSList     *annotates;
+    GSList     *prev_annotates;
+    GHashTable *dict;
+};
+
+const gchar *progname;
+
+static gboolean         parse_node             (xmlNode     *node,
+                                                gboolean     is_child,
+                                                const gchar *prop_name,
+                                                EmojiData   *data);
+
+static void
+usage (void)
+{
+    g_print ("%s emoji-list.html emoji.dict\n", progname);
+}
+
+static void
+reset_emoji_element (EmojiData *data)
+{
+    g_clear_pointer (&data->class, g_free);
+    g_clear_pointer (&data->emoji, g_free);
+    if (data->annotates) {
+        g_slist_free_full (data->prev_annotates, g_free);
+        data->prev_annotates = data->annotates;
+        data->annotates = NULL;
+    }
+}
+
+static void
+free_dict_words (gpointer list)
+{
+    g_slist_free_full (list, g_free);
+}
+
+static gboolean
+parse_attr (xmlAttr   *attr,
+            EmojiData *data)
+{
+    if (g_strcmp0 ((const gchar *) attr->name, "class") == 0 && attr->children)
+        parse_node (attr->children, TRUE, (const gchar *) attr->name, data);
+    if (g_strcmp0 ((const gchar *) attr->name, "target") == 0 && attr->children)
+        parse_node (attr->children, TRUE, (const gchar *) attr->name, data);
+    if (attr->next)
+        parse_attr (attr->next, data);
+    return TRUE;
+}
+
+static gboolean
+parse_node (xmlNode     *node,
+            gboolean     is_child,
+            const gchar *prop_name,
+            EmojiData   *data)
+{
+    if (g_strcmp0 ((const gchar *) node->name, "tr") == 0) {
+        GSList *annotates = data->annotates;
+        while (annotates) {
+            GSList *emojis = g_hash_table_lookup (data->dict, annotates->data);
+            if (emojis) {
+                emojis = g_slist_copy_deep (emojis, (GCopyFunc) g_strdup, NULL);
+            }
+            emojis = g_slist_append (emojis, g_strdup (data->emoji));
+            g_hash_table_replace (data->dict,
+                                  g_strdup (annotates->data),
+                                  emojis);
+            annotates = annotates->next;
+        }
+        reset_emoji_element (data);
+    }
+    /* if node->name is "text" and is_child is FALSE,
+     * it's '\n' or Space between <td> and <td>.
+     */
+    if (g_strcmp0 ((const gchar *) node->name, "text") == 0 && is_child) {
+        /* Get "chars" in <td class="chars"> */
+        if (g_strcmp0 (prop_name, "class") == 0) {
+            if (g_strcmp0 (data->class, (const gchar *) node->content) != 0) {
+                g_clear_pointer (&data->class, g_free);
+                data->class = g_strdup ((const gchar *) node->content);
+            }
+        }
+        /* Get "annotate" in <td class="name"><a target="annotate"> */
+        if (g_strcmp0 (prop_name, "target") == 0 &&
+            g_strcmp0 (data->class, "name") == 0) {
+            g_clear_pointer (&data->class, g_free);
+            data->class = g_strdup ((const gchar *) node->content);
+        }
+        /* Get "emoji" in <td class="chars">emoji</td> */
+        if (g_strcmp0 (prop_name, "td") == 0 &&
+            g_strcmp0 (data->class, "chars") == 0) {
+            data->emoji = g_strdup ((const gchar *) node->content);
+        }
+        /* We ignore "NAME" for <td class="name">NAME</td> but
+         * takes "ANNOTATE" for
+         * <td class="name"><a target="annotate">ANNOTATE</a></td>
+         */
+        if (g_strcmp0 (prop_name, "td") == 0 &&
+            g_strcmp0 (data->class, "name") == 0) {
+            g_slist_free_full (data->annotates, g_free);
+            data->annotates = NULL;
+        }
+        /* Get "ANNOTATE" in
+         * <td class="name"><a target="annotate">ANNOTATE</a></td>
+         */
+        if (g_strcmp0 (prop_name, "a") == 0 &&
+            g_strcmp0 (data->class, "annotate") == 0) {
+            data->annotates =
+                    g_slist_append (data->annotates,
+                                    g_strdup ((const gchar *) node->content));
+        }
+    }
+    /* Get "foo" in <td class="foo"> */
+    if (g_strcmp0 ((const gchar *) node->name, "td") == 0 &&
+        node->properties != NULL) {
+        parse_attr (node->properties, data);
+    }
+    /* Get "foo" in <a target="foo"> */
+    if (g_strcmp0 ((const gchar *) node->name, "a") == 0 &&
+        node->properties != NULL) {
+        parse_attr (node->properties, data);
+    }
+    if (node->children) {
+        parse_node (node->children, TRUE, (const gchar *) node->name, data);
+    } else {
+        /* If annotate is NULL likes <td class="name"></td>,
+         * the previous emoji cell has the same annotate.
+         */
+        if (g_strcmp0 ((const gchar *) node->name, "td") == 0 &&
+            g_strcmp0 (data->class, "name") == 0) {
+            data->annotates = g_slist_copy_deep (data->prev_annotates,
+                                                 (GCopyFunc) g_strdup,
+                                                 NULL);
+        }
+    }
+    if (node->next)
+        parse_node (node->next, FALSE, (const gchar *) node->name, data);
+
+    return TRUE;
+}
+
+static GHashTable *
+parse_html (const gchar *filename)
+{
+    xmlDoc *doc = htmlParseFile (filename, "utf-8");
+    EmojiData data = { 0, };
+
+    if (doc == NULL || doc->children == NULL) {
+        g_warning ("Parse Error in document type: %x",
+                   doc ? doc->type : 0);
+        return FALSE;
+    }
+
+    data.dict = g_hash_table_new_full (g_str_hash,
+                                       g_str_equal,
+                                       g_free,
+                                       free_dict_words);
+    parse_node (doc->children, TRUE, (const gchar *) doc->name, &data);
+
+    reset_emoji_element (&data);
+    g_slist_free_full (data.prev_annotates, g_free);
+
+    return data.dict;
+}
+
+int
+main (int argc, char *argv[])
+{
+    GHashTable *dict;
+    progname = basename (argv[0]);
+
+    if (argc < 3) {
+        usage ();
+        return -1;
+    }
+
+    dict = parse_html (argv[1]);
+    ibus_emoji_dict_save (argv[2], dict);
+    g_hash_table_destroy (dict);
+
+    return 0;
+}
diff --git a/src/ibusenginesimple.c b/src/ibusenginesimple.c
index 1b688b0..8efe5a9 100644
--- a/src/ibusenginesimple.c
+++ b/src/ibusenginesimple.c
@@ -3,7 +3,7 @@
 /* ibus - The Input Bus
  * Copyright (C) 2014 Peng Huang <shawn.p.huang@gmail.com>
  * Copyright (C) 2015-2016 Takao Fujiwara <takao.fujiwara1@gmail.com>
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014-2016 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -31,6 +31,7 @@
 
 #include "ibuskeys.h"
 #include "ibuskeysyms.h"
+#include "ibusutil.h"
 
 /* This file contains the table of the compose sequences,
  * static const guint16 gtk_compose_seqs_compact[] = {}
@@ -42,16 +43,27 @@
 #include <stdlib.h>
 
 #define X11_DATADIR X11_DATA_PREFIX "/share/X11/locale"
+#define EMOJI_SOURCE_LEN 100
 #define IBUS_ENGINE_SIMPLE_GET_PRIVATE(o)  \
    (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_ENGINE_SIMPLE, IBusEngineSimplePrivate))
 
-struct _IBusEngineSimplePrivate {
-    guint16     compose_buffer[IBUS_MAX_COMPOSE_LEN + 1];
-    gunichar    tentative_match;
-    gint        tentative_match_len;
+typedef struct {
+    GHashTable *dict;
+    int         max_seq_len;
+} IBusEngineDict;
 
-    guint       in_hex_sequence : 1;
-    guint       modifiers_dropped : 1;
+struct _IBusEngineSimplePrivate {
+    guint16             compose_buffer[EMOJI_SOURCE_LEN];
+    gunichar            tentative_match;
+    gchar              *tentative_emoji;
+    gint                tentative_match_len;
+
+    guint               in_hex_sequence : 1;
+    guint               in_emoji_sequence : 1;
+    guint               modifiers_dropped : 1;
+    IBusEngineDict     *emoji_dict;
+    IBusLookupTable    *lookup_table;
+    gboolean            lookup_table_visible;
 };
 
 /* From the values below, the value 30 means the number of different first keysyms
@@ -97,6 +109,8 @@ static gboolean ibus_engine_simple_process_key_event
                                                  guint               modifiers);
 static void     ibus_engine_simple_commit_char (IBusEngineSimple    *simple,
                                                 gunichar             ch);
+static void     ibus_engine_simple_commit_str  (IBusEngineSimple    *simple,
+                                                const gchar         *str);
 static void     ibus_engine_simple_update_preedit_text
                                                (IBusEngineSimple    *simple);
 
@@ -128,6 +142,18 @@ ibus_engine_simple_init (IBusEngineSimple *simple)
 static void
 ibus_engine_simple_destroy (IBusEngineSimple *simple)
 {
+    IBusEngineSimplePrivate *priv = simple->priv;
+
+    if (priv->emoji_dict) {
+        if (priv->emoji_dict->dict)
+            g_clear_pointer (&priv->emoji_dict->dict, g_hash_table_destroy);
+        g_slice_free (IBusEngineDict, priv->emoji_dict);
+        priv->emoji_dict = NULL;
+    }
+
+    g_clear_pointer (&priv->lookup_table, g_object_unref);
+    g_clear_pointer (&priv->tentative_emoji, g_free);
+
     IBUS_OBJECT_CLASS(ibus_engine_simple_parent_class)->destroy (
         IBUS_OBJECT (simple));
 }
@@ -146,6 +172,11 @@ ibus_engine_simple_reset (IBusEngine *engine)
         priv->tentative_match_len = 0;
         ibus_engine_hide_preedit_text ((IBusEngine *)simple);
     }
+    if (priv->tentative_emoji || priv->in_emoji_sequence) {
+        priv->in_emoji_sequence = FALSE;
+        g_clear_pointer (&priv->tentative_emoji, g_free);
+        ibus_engine_hide_preedit_text ((IBusEngine *)simple);
+    }
 }
 
 static void
@@ -162,23 +193,60 @@ ibus_engine_simple_commit_char (IBusEngineSimple *simple,
         priv->tentative_match_len = 0;
         ibus_engine_simple_update_preedit_text (simple);
     }
+    if (priv->tentative_emoji || priv->in_emoji_sequence) {
+        priv->in_emoji_sequence = FALSE;
+        g_clear_pointer (&priv->tentative_emoji, g_free);
+        ibus_engine_simple_update_preedit_text (simple);
+    }
 
     ibus_engine_commit_text ((IBusEngine *)simple,
             ibus_text_new_from_unichar (ch));
 }
 
 static void
+ibus_engine_simple_commit_str (IBusEngineSimple *simple,
+                               const gchar      *str)
+{
+    IBusEngineSimplePrivate *priv = simple->priv;
+    gchar *backup_str;
+
+    g_return_if_fail (str && *str);
+
+    backup_str = g_strdup (str);
+
+    if (priv->tentative_match || priv->in_hex_sequence) {
+        priv->in_hex_sequence = FALSE;
+        priv->tentative_match = 0;
+        priv->tentative_match_len = 0;
+        ibus_engine_simple_update_preedit_text (simple);
+    }
+    if (priv->tentative_emoji || priv->in_emoji_sequence) {
+        priv->in_emoji_sequence = FALSE;
+        g_clear_pointer (&priv->tentative_emoji, g_free);
+        ibus_engine_simple_update_preedit_text (simple);
+    }
+
+    ibus_engine_commit_text ((IBusEngine *)simple,
+            ibus_text_new_from_string (backup_str));
+    g_free (backup_str);
+}
+
+static void
 ibus_engine_simple_update_preedit_text (IBusEngineSimple *simple)
 {
     IBusEngineSimplePrivate *priv = simple->priv;
 
-    gunichar outbuf[IBUS_MAX_COMPOSE_LEN + 2];
+    gunichar outbuf[EMOJI_SOURCE_LEN + 1];
     int len = 0;
 
-    if (priv->in_hex_sequence) {
+    if (priv->in_hex_sequence || priv->in_emoji_sequence) {
         int hexchars = 0;
 
-        outbuf[0] = L'u';
+        if (priv->in_hex_sequence)
+            outbuf[0] = L'u';
+        else
+            outbuf[0] = L'@';
+
         len = 1;
 
         while (priv->compose_buffer[hexchars] != 0) {
@@ -187,10 +255,22 @@ ibus_engine_simple_update_preedit_text (IBusEngineSimple *simple)
             ++len;
             ++hexchars;
         }
-        g_assert (len <= IBUS_MAX_COMPOSE_LEN + 1);
+
+        if (priv->in_hex_sequence)
+            g_assert (len <= IBUS_MAX_COMPOSE_LEN + 1);
+        else
+            g_assert (len <= EMOJI_SOURCE_LEN + 1);
     }
-    else if (priv->tentative_match)
+    else if (priv->tentative_match) {
         outbuf[len++] = priv->tentative_match;
+    } else if (priv->tentative_emoji && *priv->tentative_emoji) {
+        IBusText *text = ibus_text_new_from_string (priv->tentative_emoji);
+        len = strlen (priv->tentative_emoji);
+        ibus_text_append_attribute (text,
+                IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, len);
+        ibus_engine_update_preedit_text ((IBusEngine *)simple, text, len, TRUE);
+        return;
+    }
 
     outbuf[len] = L'\0';
     if (len == 0) {
@@ -277,6 +357,104 @@ check_hex (IBusEngineSimple *simple,
     return TRUE;
 }
 
+static IBusEngineDict *
+load_emoji_dict ()
+{
+    IBusEngineDict *emoji_dict;
+    GList *keys;
+    int max_length = 0;
+
+    emoji_dict = g_slice_new0 (IBusEngineDict);
+    emoji_dict->dict = ibus_emoji_dict_load (IBUS_DATA_DIR "/dicts/emoji.dict");
+    if (!emoji_dict->dict)
+        return emoji_dict;
+
+    keys = g_hash_table_get_keys (emoji_dict->dict);
+    for (; keys; keys = keys->next) {
+        int length = strlen (keys->data);
+        if (max_length < length)
+            max_length = length;
+    }
+    emoji_dict->max_seq_len = max_length;
+
+    return emoji_dict;
+}
+
+static gboolean
+check_emoji_table (IBusEngineSimple       *simple,
+                   gint                    n_compose,
+                   gint                    index)
+{
+    IBusEngineSimplePrivate *priv = simple->priv;
+    IBusEngineDict *emoji_dict = priv->emoji_dict;
+    GString *str = NULL;
+    gint i;
+    gchar buf[7];
+    GSList *words = NULL;
+
+    g_assert (IBUS_IS_ENGINE_SIMPLE (simple));
+
+    if (priv->lookup_table == NULL) {
+        priv->lookup_table = ibus_lookup_table_new (10, 0, TRUE, TRUE);
+        g_object_ref_sink (priv->lookup_table);
+    }
+    if (emoji_dict == NULL)
+        emoji_dict = priv->emoji_dict = load_emoji_dict (simple);
+
+    if (emoji_dict == NULL || emoji_dict->dict == NULL)
+        return FALSE;
+
+    if (n_compose > emoji_dict->max_seq_len)
+        return FALSE;
+
+    str = g_string_new (NULL);
+    priv->lookup_table_visible = FALSE;
+
+    i = 0;
+    while (i < n_compose) {
+        gunichar ch;
+
+        ch = ibus_keyval_to_unicode (priv->compose_buffer[i]);
+
+        if (ch == 0)
+            return FALSE;
+
+        if (!g_unichar_isprint (ch))
+            return FALSE;
+
+        buf[g_unichar_to_utf8 (ch, buf)] = '\0';
+
+        g_string_append (str, buf);
+
+        ++i;
+    }
+
+    if (str->str) {
+        words = g_hash_table_lookup (emoji_dict->dict, str->str);
+    }
+    g_string_free (str, TRUE);
+
+    if (words != NULL) {
+        int i = 0;
+        ibus_lookup_table_clear (priv->lookup_table);
+        priv->lookup_table_visible = TRUE;
+
+        while (words) {
+            if (i == index) {
+                g_clear_pointer (&priv->tentative_emoji, g_free);
+                priv->tentative_emoji = g_strdup (words->data);
+            }
+            IBusText *text = ibus_text_new_from_string (words->data);
+            ibus_lookup_table_append_candidate (priv->lookup_table, text);
+            words = words->next;
+            i++;
+        }
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
 static int
 compare_seq_index (const void *key, const void *value)
 {
@@ -626,10 +804,10 @@ ibus_check_algorithmically (const guint16 *compose_buffer,
 
 static gboolean
 no_sequence_matches (IBusEngineSimple *simple,
-                     gint                 n_compose,
-                     guint                keyval,
-                     guint                keycode,
-                     guint                modifiers)
+                     gint              n_compose,
+                     guint             keyval,
+                     guint             keycode,
+                     guint             modifiers)
 {
     IBusEngineSimplePrivate *priv = simple->priv;
 
@@ -642,8 +820,7 @@ no_sequence_matches (IBusEngineSimple *simple,
         gint len = priv->tentative_match_len;
         int i;
 
-        ibus_engine_simple_commit_char (simple,
-                                            priv->tentative_match);
+        ibus_engine_simple_commit_char (simple, priv->tentative_match);
         priv->compose_buffer[0] = 0;
 
         for (i=0; i < n_compose - len - 1; i++) {
@@ -655,8 +832,11 @@ no_sequence_matches (IBusEngineSimple *simple,
 
         return ibus_engine_simple_process_key_event (
                 (IBusEngine *)simple, keyval, keycode, modifiers);
-    }
-    else {
+    } else if (priv->tentative_emoji && *priv->tentative_emoji) {
+        ibus_engine_simple_commit_str (simple, priv->tentative_emoji);
+        g_clear_pointer (&priv->tentative_emoji, g_free);
+        priv->compose_buffer[0] = 0;
+    } else {
         priv->compose_buffer[0] = 0;
         if (n_compose > 1) {
             /* Invalid sequence */
@@ -676,6 +856,7 @@ no_sequence_matches (IBusEngineSimple *simple,
         else
             return FALSE;
     }
+    return FALSE;
 }
 
 static gboolean
@@ -687,6 +868,39 @@ is_hex_keyval (guint keyval)
 }
 
 static gboolean
+is_graph_keyval (guint keyval)
+{
+  gunichar ch = ibus_keyval_to_unicode (keyval);
+
+  return g_unichar_isgraph (ch);
+}
+
+static void
+ibus_engine_simple_update_lookup_and_aux_table (IBusEngineSimple *simple)
+{
+    IBusEngineSimplePrivate *priv;
+    guint index, candidates;
+    gchar *aux_label = NULL;
+    IBusText *text = NULL;
+
+    g_return_if_fail (IBUS_IS_ENGINE_SIMPLE (simple));
+
+    priv = simple->priv;
+    index = ibus_lookup_table_get_cursor_pos (priv->lookup_table) + 1;
+    candidates = ibus_lookup_table_get_number_of_candidates(priv->lookup_table);
+    aux_label = g_strdup_printf ("(%u / %u)", index, candidates);
+    text = ibus_text_new_from_string (aux_label);
+    g_free (aux_label);
+
+    ibus_engine_update_auxiliary_text (IBUS_ENGINE (simple),
+                                       text,
+                                       priv->lookup_table_visible);
+    ibus_engine_update_lookup_table (IBUS_ENGINE (simple),
+                                     priv->lookup_table,
+                                     priv->lookup_table_visible);
+}
+
+static gboolean
 ibus_engine_simple_process_key_event (IBusEngine *engine,
                                       guint       keyval,
                                       guint       keycode,
@@ -697,10 +911,13 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
     gint n_compose = 0;
     gboolean have_hex_mods;
     gboolean is_hex_start;
+    gboolean is_emoji_start = FALSE;
     gboolean is_hex_end;
+    gboolean is_space;
     gboolean is_backspace;
     gboolean is_escape;
     guint hex_keyval;
+    guint printable_keyval;
     gint i;
     gboolean compose_finish;
     gunichar output_char;
@@ -714,17 +931,16 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
              keyval == IBUS_KEY_Shift_L || keyval == IBUS_KEY_Shift_R)) {
             if (priv->tentative_match &&
                 g_unichar_validate (priv->tentative_match)) {
-                ibus_engine_simple_commit_char (simple,
-                                                    priv->tentative_match);
-            }
-            else if (n_compose == 0) {
+                ibus_engine_simple_commit_char (simple, priv->tentative_match);
+            } else if (n_compose == 0) {
                 priv->modifiers_dropped = TRUE;
-            }
-            else {
+            } else {
                 /* invalid hex sequence */
                 /* FIXME beep_window (event->window); */
                 priv->tentative_match = 0;
+                g_clear_pointer (&priv->tentative_emoji, g_free);
                 priv->in_hex_sequence = FALSE;
+                priv->in_emoji_sequence = FALSE;
                 priv->compose_buffer[0] = 0;
 
                 ibus_engine_simple_update_preedit_text (simple);
@@ -732,6 +948,26 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
 
             return TRUE;
         }
+        /* Handle Shift + Space */
+        else if (priv->in_emoji_sequence &&
+            (keyval == IBUS_KEY_Control_L || keyval == IBUS_KEY_Control_R)) {
+            if (priv->tentative_emoji && *priv->tentative_emoji) {
+                ibus_engine_simple_commit_str (simple, priv->tentative_emoji);
+                g_clear_pointer (&priv->tentative_emoji, g_free);
+            } else if (n_compose == 0) {
+                priv->modifiers_dropped = TRUE;
+            } else {
+                /* invalid hex sequence */
+                /* FIXME beep_window (event->window); */
+                priv->tentative_match = 0;
+                g_clear_pointer (&priv->tentative_emoji, g_free);
+                priv->in_hex_sequence = FALSE;
+                priv->in_emoji_sequence = FALSE;
+                priv->compose_buffer[0] = 0;
+
+                ibus_engine_simple_update_preedit_text (simple);
+            }
+        }
         else
             return FALSE;
     }
@@ -741,25 +977,33 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
         if (keyval == ibus_compose_ignore[i])
             return FALSE;
 
-    if (priv->in_hex_sequence && priv->modifiers_dropped)
+    if ((priv->in_hex_sequence || priv->in_emoji_sequence)
+        && priv->modifiers_dropped) {
         have_hex_mods = TRUE;
-    else
+    } else {
         have_hex_mods = (modifiers & (HEX_MOD_MASK)) == HEX_MOD_MASK;
+    }
 
     is_hex_start = keyval == IBUS_KEY_U;
+#ifdef ENABLE_EMOJI_DICT
+    is_emoji_start = keyval == IBUS_KEY_E;
+#endif
     is_hex_end = (keyval == IBUS_KEY_space ||
                   keyval == IBUS_KEY_KP_Space ||
                   keyval == IBUS_KEY_Return ||
                   keyval == IBUS_KEY_ISO_Enter ||
                   keyval == IBUS_KEY_KP_Enter);
+    is_space = (keyval == IBUS_KEY_space || keyval == IBUS_KEY_KP_Space);
     is_backspace = keyval == IBUS_KEY_BackSpace;
     is_escape = keyval == IBUS_KEY_Escape;
     hex_keyval = is_hex_keyval (keyval) ? keyval : 0;
+    printable_keyval = is_graph_keyval (keyval) ? keyval : 0;
 
     /* gtkimcontextsimple causes a buffer overflow in priv->compose_buffer.
      * Add the check code here.
      */
-    if (n_compose >= IBUS_MAX_COMPOSE_LEN) {
+    if ((n_compose >= IBUS_MAX_COMPOSE_LEN && priv->in_hex_sequence) ||
+        (n_compose >= EMOJI_SOURCE_LEN && priv->in_emoji_sequence)) {
         if (is_backspace) {
             priv->compose_buffer[--n_compose] = 0;
         }
@@ -767,7 +1011,9 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
             /* invalid hex sequence */
             // beep_window (event->window);
             priv->tentative_match = 0;
+            g_clear_pointer (&priv->tentative_emoji, g_free);
             priv->in_hex_sequence = FALSE;
+            priv->in_emoji_sequence = FALSE;
             priv->compose_buffer[0] = 0;
         }
         else if (is_escape) {
@@ -789,12 +1035,16 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
      * ISO_Level3_Switch.
      */
     if (!have_hex_mods ||
-        (n_compose > 0 && !priv->in_hex_sequence) ||
-        (n_compose == 0 && !priv->in_hex_sequence && !is_hex_start) ||
+        (n_compose > 0 && !priv->in_hex_sequence && !priv->in_emoji_sequence) ||
+        (n_compose == 0 && !priv->in_hex_sequence && !is_hex_start &&
+         !priv->in_emoji_sequence && !is_emoji_start) ||
         (priv->in_hex_sequence && !hex_keyval &&
-         !is_hex_start && !is_hex_end && !is_escape && !is_backspace)) {
+         !is_hex_start && !is_hex_end && !is_escape && !is_backspace) ||
+        (priv->in_emoji_sequence && !printable_keyval &&
+         !is_emoji_start && !is_hex_end && !is_escape && !is_backspace)) {
         if (modifiers & (IBUS_MOD1_MASK | IBUS_CONTROL_MASK) ||
-            (priv->in_hex_sequence && priv->modifiers_dropped &&
+            ((priv->in_hex_sequence || priv->in_emoji_sequence) &&
+             priv->modifiers_dropped &&
              (keyval == IBUS_KEY_Return ||
               keyval == IBUS_KEY_ISO_Enter ||
               keyval == IBUS_KEY_KP_Enter))) {
@@ -816,6 +1066,20 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
 
         return TRUE;
     }
+    if (priv->in_emoji_sequence && have_hex_mods && is_backspace) {
+        if (n_compose > 0) {
+            n_compose--;
+            priv->compose_buffer[n_compose] = 0;
+            check_emoji_table (simple, n_compose, -1);
+            ibus_engine_simple_update_lookup_and_aux_table (simple);
+        } else {
+            priv->in_emoji_sequence = FALSE;
+        }
+
+        ibus_engine_simple_update_preedit_text (simple);
+
+        return TRUE;
+    }
 
     /* Check for hex sequence restart */
     if (priv->in_hex_sequence && have_hex_mods && is_hex_start) {
@@ -833,13 +1097,41 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
             }
         }
     }
+    if (priv->in_emoji_sequence && have_hex_mods && is_emoji_start) {
+        if (priv->tentative_emoji && *priv->tentative_emoji) {
+            ibus_engine_simple_commit_str (simple, priv->tentative_emoji);
+            g_clear_pointer (&priv->tentative_emoji, g_free);
+        }
+        else {
+            if (n_compose > 0) {
+                g_clear_pointer (&priv->tentative_emoji, g_free);
+                priv->in_emoji_sequence = FALSE;
+                priv->compose_buffer[0] = 0;
+            }
+        }
+    }
 
     /* Check for hex sequence start */
     if (!priv->in_hex_sequence && have_hex_mods && is_hex_start) {
         priv->compose_buffer[0] = 0;
         priv->in_hex_sequence = TRUE;
+        priv->in_emoji_sequence = FALSE;
         priv->modifiers_dropped = FALSE;
         priv->tentative_match = 0;
+        g_clear_pointer (&priv->tentative_emoji, g_free);
+
+        // g_debug ("Start HEX MODE");
+
+        ibus_engine_simple_update_preedit_text (simple);
+
+        return TRUE;
+    } else if (!priv->in_emoji_sequence && have_hex_mods && is_emoji_start) {
+        priv->compose_buffer[0] = 0;
+        priv->in_hex_sequence = FALSE;
+        priv->in_emoji_sequence = TRUE;
+        priv->modifiers_dropped = FALSE;
+        priv->tentative_match = 0;
+        g_clear_pointer (&priv->tentative_emoji, g_free);
 
         // g_debug ("Start HEX MODE");
 
@@ -864,9 +1156,20 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
             // beep_window (event->window);
             return TRUE;
         }
-    }
-    else
+    } else if (priv->in_emoji_sequence) {
+        if (printable_keyval) {
+            priv->compose_buffer[n_compose++] = printable_keyval;
+        }
+        else if (is_space && (modifiers & IBUS_SHIFT_MASK)) {
+            priv->compose_buffer[n_compose++] = IBUS_KEY_space;
+        }
+        else if (is_escape) {
+            ibus_engine_simple_reset (engine);
+            return TRUE;
+        }
+    } else {
         priv->compose_buffer[n_compose++] = keyval;
+    }
 
     priv->compose_buffer[n_compose] = 0;
 
@@ -880,8 +1183,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
                     ibus_engine_simple_commit_char (simple,
                             priv->tentative_match);
                     priv->compose_buffer[0] = 0;
-                }
-                else {
+                } else {
                     // FIXME
                     /* invalid hex sequence */
                     // beep_window (event->window);
@@ -899,6 +1201,73 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
             return TRUE;
         }
     }
+    else if (priv->in_emoji_sequence) {
+        if (have_hex_mods && n_compose > 0) {
+            gboolean update_lookup_table = FALSE;
+
+            if (priv->lookup_table_visible) {
+                switch (keyval) {
+                case IBUS_KEY_space:
+                case IBUS_KEY_KP_Space:
+                    if ((modifiers & IBUS_SHIFT_MASK) == 0) {
+                        ibus_lookup_table_cursor_down (priv->lookup_table);
+                        update_lookup_table = TRUE;
+                    }
+                    break;
+                case IBUS_KEY_Down:
+                    ibus_lookup_table_cursor_down (priv->lookup_table);
+                    update_lookup_table = TRUE;
+                    break;
+                case IBUS_KEY_Up:
+                    ibus_lookup_table_cursor_up (priv->lookup_table);
+                    update_lookup_table = TRUE;
+                    break;
+                case IBUS_KEY_Page_Down:
+                    ibus_lookup_table_page_down (priv->lookup_table);
+                    update_lookup_table = TRUE;
+                    break;
+                case IBUS_KEY_Page_Up:
+                    ibus_lookup_table_page_up (priv->lookup_table);
+                    update_lookup_table = TRUE;
+                    break;
+                default:;
+                }
+            }
+
+            if (!update_lookup_table) {
+                if (is_hex_end && !is_space) {
+                    if (priv->lookup_table) {
+                        int index = (int) ibus_lookup_table_get_cursor_pos (
+                                priv->lookup_table);
+                        check_emoji_table (simple, n_compose, index);
+                        priv->lookup_table_visible = FALSE;
+                        update_lookup_table = TRUE;
+                    }
+                }
+                else if (check_emoji_table (simple, n_compose, -1)) {
+                    update_lookup_table = TRUE;
+                }
+            }
+
+            if (update_lookup_table)
+                ibus_engine_simple_update_lookup_and_aux_table (simple);
+            if (is_hex_end && !is_space) {
+                if (priv->tentative_emoji && *priv->tentative_emoji) {
+                    ibus_engine_simple_commit_str (simple,
+                            priv->tentative_emoji);
+                    priv->compose_buffer[0] = 0;
+                } else {
+                    g_clear_pointer (&priv->tentative_emoji, g_free);
+                    priv->in_emoji_sequence = FALSE;
+                    priv->compose_buffer[0] = 0;
+                }
+            }
+
+            ibus_engine_simple_update_preedit_text (simple);
+
+            return TRUE;
+        }
+    }
     else {
         GSList *list = global_tables;
         while (list) {
diff --git a/src/ibusutil.c b/src/ibusutil.c
index b9f3fdd..bfaa4f4 100644
--- a/src/ibusutil.c
+++ b/src/ibusutil.c
@@ -2,8 +2,8 @@
 /* vim:set et sts=4: */
 /* bus - The Input Bus
  * Copyright (C) 2008-2015 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright (C) 2010-2015 Takao Fujiwara <takao.fujiwara1@gmail.com>
- * Copyright (C) 2008-2015 Red Hat, Inc.
+ * Copyright (C) 2010-2016 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2016 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -34,6 +34,9 @@
 #include <libintl.h>
 #endif
 
+#define IBUS_DICT_MAGIC "IBusDict"
+#define IBUS_DICT_VERSION (1)
+
 /* gettext macro */
 #define N_(t) t
 
@@ -125,6 +128,74 @@ _load_lang()
     ibus_xml_free (node);
 }
 
+static void
+free_dict_words (gpointer list)
+{
+    g_slist_free_full (list, g_free);
+}
+
+static void
+variant_foreach_add_emoji (gchar           *annotation,
+                           GSList          *emojis,
+                           GVariantBuilder *builder)
+{
+    int i;
+    int length = (int) g_slist_length (emojis);
+    gchar **buff = g_new0 (gchar *, length);
+    GSList *l = emojis;
+
+    for (i = 0; i < length; i++, l = l->next)
+        buff[i] = (gchar *) l->data;
+
+    g_variant_builder_add (builder,
+                           "{sv}",
+                           annotation,
+                           g_variant_new_strv ((const gchar * const  *) buff,
+                                               length));
+    g_free (buff);
+}
+
+static GVariant *
+ibus_emoji_dict_serialize (GHashTable *dict)
+{
+    GVariantBuilder builder;
+
+    g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+    g_hash_table_foreach (dict,  (GHFunc) variant_foreach_add_emoji, &builder);
+    return g_variant_builder_end (&builder);
+}
+
+static GHashTable *
+ibus_emoji_dict_deserialize (GVariant *variant)
+{
+    GHashTable *dict = NULL;
+    GVariantIter iter;
+    gchar *annotate = NULL;
+    GVariant *emojis_variant = NULL;
+
+    dict = g_hash_table_new_full (g_str_hash,
+                                  g_str_equal,
+                                  g_free,
+                                  free_dict_words);
+
+    g_variant_iter_init (&iter, variant);
+    while (g_variant_iter_loop (&iter, "{sv}", &annotate, &emojis_variant)) {
+        gsize i;
+        gsize length = 0;
+        const gchar **array = g_variant_get_strv (emojis_variant, &length);
+        GSList *emojis = NULL;
+
+        for (i = 0; i < length; i++) {
+            emojis = g_slist_append (emojis, g_strdup (array[i]));
+        }
+        g_hash_table_insert (dict, annotate, emojis);
+        annotate = NULL;
+        g_clear_pointer (&emojis_variant, g_variant_unref);
+    }
+
+    return dict;
+}
+
 const gchar *
 ibus_get_untranslated_language_name (const gchar *_locale)
 {
@@ -171,3 +242,121 @@ ibus_g_variant_get_child_string (GVariant *variant, gsize index, char **str)
     g_free (*str);
     g_variant_get_child (variant, index, "s", str);
 }
+
+void
+ibus_emoji_dict_save (const gchar *path, GHashTable *dict)
+{
+    GVariant *variant;
+    const gchar *header = IBUS_DICT_MAGIC;
+    const guint16 version = IBUS_DICT_VERSION;
+    const gchar *contents;
+    gsize length;
+    GError *error = NULL;
+
+    variant = g_variant_new ("(sqv)",
+                             header,
+                             version,
+                             ibus_emoji_dict_serialize (dict));
+
+    contents =  g_variant_get_data (variant);
+    length =  g_variant_get_size (variant);
+
+    if (!g_file_set_contents (path, contents, length, &error)) {
+        g_warning ("Failed to save emoji dict %s: %s", path, error->message);
+        g_error_free (error);
+    }
+
+    g_variant_unref (variant);
+}
+
+GHashTable *
+ibus_emoji_dict_load (const gchar *path)
+{
+    gchar *contents = NULL;
+    gsize length = 0;
+    GError *error = NULL;
+    GVariant *variant_table = NULL;
+    GVariant *variant = NULL;
+    const gchar *header = NULL;
+    guint16 version = 0;
+    GHashTable *retval = NULL;
+
+    if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
+        g_warning ("Emoji dict does not exist: %s", path);
+        goto out_load_cache;
+    }
+
+    if (!g_file_get_contents (path, &contents, &length, &error)) {
+        g_warning ("Failed to get dict content %s: %s", path, error->message);
+        g_error_free (error);
+        goto out_load_cache;
+    }
+
+    variant_table = g_variant_new_from_data (G_VARIANT_TYPE ("(sq)"),
+                                             contents,
+                                             length,
+                                             FALSE,
+                                             NULL,
+                                             NULL);
+
+    if (variant_table == NULL) {
+        g_warning ("cache table is broken.");
+        goto out_load_cache;
+    }
+
+    g_variant_get (variant_table, "(&sq)", &header, &version);
+
+    if (g_strcmp0 (header, IBUS_DICT_MAGIC) != 0) {
+        g_warning ("cache is not IBusDict.");
+        goto out_load_cache;
+    }
+
+    if (version != IBUS_DICT_VERSION) {
+        g_warning ("cache version is different: %u != %u",
+                   version, IBUS_DICT_VERSION);
+        goto out_load_cache;
+    }
+
+    version = 0;
+    header = NULL;
+    g_variant_unref (variant_table);
+
+    variant_table = g_variant_new_from_data (G_VARIANT_TYPE ("(sqv)"),
+                                             contents,
+                                             length,
+                                             FALSE,
+                                             NULL,
+                                             NULL);
+
+    if (variant_table == NULL) {
+        g_warning ("cache table is broken.");
+        goto out_load_cache;
+    }
+
+    g_variant_get (variant_table, "(&sqv)",
+                   NULL,
+                   NULL,
+                   &variant);
+
+    if (variant == NULL) {
+        g_warning ("cache dict is broken.");
+        goto out_load_cache;
+    }
+
+    retval = ibus_emoji_dict_deserialize (variant);
+
+out_load_cache:
+    if (variant)
+        g_variant_unref (variant);
+    if (variant_table)
+        g_variant_unref (variant_table);
+
+    return retval;
+}
+
+GSList *
+ibus_emoji_dict_lookup (GHashTable  *dict,
+                        const gchar *annotation)
+{
+    return (GSList *) g_hash_table_lookup (dict, annotation);
+}
diff --git a/src/ibusutil.h b/src/ibusutil.h
index 2c1360c..e619b67 100644
--- a/src/ibusutil.h
+++ b/src/ibusutil.h
@@ -2,8 +2,8 @@
 /* vim:set et sts=4: */
 /* bus - The Input Bus
  * Copyright (C) 2008-2015 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright (C) 2010-2015 Takao Fujiwara <takao.fujiwara1@gmail.com>
- * Copyright (C) 2008-2015 Red Hat, Inc.
+ * Copyright (C) 2010-2016 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2016 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -53,4 +53,31 @@ const gchar *    ibus_get_untranslated_language_name
  */
 const gchar *    ibus_get_language_name         (const gchar    *_locale);
 
+/**
+ * ibus_emoji_dict_save:
+ * @path: A path of the saved dictionary file.
+ * @dict: (element-type utf8 gpointer) (transfer none): An Emoji dictionary
+ *
+ * Save the Emoji dictionary to the cache file.
+ */
+void             ibus_emoji_dict_save           (const gchar    *path,
+                                                 GHashTable     *dict);
+/**
+ * ibus_emoji_dict_load:
+ * @path: A path of the saved dictionary file.
+ *
+ * Returns: (element-type utf8 gpointer) (transfer none): An Emoji dictionary file loaded from the saved cache file.
+ */
+GHashTable *     ibus_emoji_dict_load           (const gchar    *path);
+
+/**
+ * ibus_emoji_dict_lookup:
+ * @dict: (element-type utf8 gpointer) (transfer none): An Emoji dictionary
+ * @annotation: Annotation for Emoji characters
+ *
+ * Returns: (element-type utf8) (transfer none): List of Emoji characters
+ * This API is for gobject-introspection.
+ */
+GSList *         ibus_emoji_dict_lookup         (GHashTable     *dict,
+                                                 const gchar    *annotation);
 #endif
-- 
2.7.4

From 0ed644cd2b6c1d15bdba0d1c6d45d162b9b34806 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
Date: Thu, 23 Jun 2016 11:52:48 +0900
Subject: [PATCH 2/4] engine: Add emoji-list.html

Now we copied http://unicode.org/emoji/charts/emoji-list.html to
http://ibus.github.io/files/ibus/emoji-list.html
and download the file in the build time.
We don't save emoji-list.html in the tarball because the file size is
more than 5MB.
We always don't get the latest emoji-list.html to avoid the build error.

BUG=https://github.com/ibus/ibus/pull/1864
R=shawn.p.huang@gmail.com

Review URL: https://codereview.appspot.com/298580043
---
 src/Makefile.am | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index a33b67d..22e031f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -29,6 +29,15 @@ endif
 
 SUBDIRS = . $(TESTS_DIR)
 
+IBUS_V_wget = $(ibus__v_wget_@AM_V@)
+ibus__v_wget_ = $(ibus__v_wget_@AM_DEFAULT_V@)
+ibus__v_wget_0 = -nv
+ibus__v_wget_1 =
+IBUS_V_diff = $(ibus__v_diff_@AM_V@)
+ibus__v_diff_ = $(ibus__v_diff_@AM_DEFAULT_V@)
+ibus__v_diff_0 = -q
+ibus__v_diff_1 =
+
 # libibus = libibus-@IBUS_API_VERSION@.la
 libibus = libibus-1.0.la
 
@@ -239,6 +248,18 @@ dict_DATA = emoji.dict
 
 noinst_PROGRAMS = emoji-parser
 
+emoji-list.html:
+	$(AM_V_at)wget $(IBUS_V_wget) \
+                http://ibus.github.io/files/ibus/emoji-list.html
+	$(AM_V_at)wget $(IBUS_V_wget) \
+                http://unicode.org/emoji/charts/emoji-list.html \
+	        -O latest-emoji-list.html
+	$(AM_V_at)diff $(IBUS_V_diff) emoji-list.html latest-emoji-list.html; \
+	if test $$? -ne 0; then \
+	    echo "#### WARNING: emoji-list.html is old." >&2; \
+	fi; \
+	rm latest-emoji-list.html;
+
 emoji.dict: emoji-parser emoji-list.html
 	$(builddir)/emoji-parser emoji-list.html $@
 
@@ -257,11 +278,11 @@ emoji_parser_LDADD =            \
 
 CLEANFILES +=                   \
     $(dict_DATA)                \
+    emoji-list.html             \
     $(NULL)
 endif
 
 EXTRA_DIST =                    \
-    emoji-list.html             \
     emoji-parser.c              \
     ibusversion.h.in            \
     ibusmarshalers.list         \
-- 
2.7.4

From 0ee1896a2b3e75494f8f9fd9d04c27436f0877b8 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
Date: Thu, 7 Jul 2016 12:47:34 +0900
Subject: [PATCH 3/4] engine: Use annotations/en.xml from unocode.org but not
 emoji-list.html

Downloading emoji-list would cause a different build by build site.
Now save annotations/en.xml from unicode.org and get emoji.json from
Emoji One.
en.xml is used for Unicode annotations and emoji.json is used for
aliases_ascii, e.g. ":)", and category, e.g. "people".

BUG=https://github.com/ibus/ibus/issues/1865
R=Shawn.P.Huang@gmail.com

Review URL: https://codereview.appspot.com/299530044
---
 COPYING.unicode              |   52 +++
 Makefile.am                  |    1 +
 configure.ac                 |   14 +-
 data/Makefile.am             |    5 +-
 data/annotations/Makefile.am |   27 ++
 data/annotations/en.xml      | 1042 ++++++++++++++++++++++++++++++++++++++++++
 ibus.spec.in                 |   14 +
 src/Makefile.am              |   31 +-
 src/emoji-parser.c           |  605 +++++++++++++++++++-----
 9 files changed, 1634 insertions(+), 157 deletions(-)
 create mode 100644 COPYING.unicode
 create mode 100644 data/annotations/Makefile.am
 create mode 100644 data/annotations/en.xml

diff --git a/COPYING.unicode b/COPYING.unicode
new file mode 100644
index 0000000..28d3060
--- /dev/null
+++ b/COPYING.unicode
@@ -0,0 +1,52 @@
+(Apply to data/annotations/en.xml)
+
+UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
+
+    Unicode Data Files include all data files under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/, and
+http://www.unicode.org/cldr/data/. Unicode Data Files do not include PDF
+online code charts under the directory http://www.unicode.org/Public/.
+Software includes any source code published in the Unicode Standard or under
+the directories http://www.unicode.org/Public/,
+http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/.
+
+    NOTICE TO USER: Carefully read the following legal agreement. BY
+DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES
+("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND
+AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF
+YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA
+FILES OR SOFTWARE.
+
+    COPYRIGHT AND PERMISSION NOTICE
+
+    Copyright ยฉ 1991-2016 Unicode, Inc. All rights reserved. Distributed under
+the Terms of Use in http://www.unicode.org/copyright.html.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+copy of the Unicode data files and any associated documentation (the "Data
+Files") or Unicode software and any associated documentation (the "Software")
+to deal in the Data Files or Software without restriction, including without
+limitation the rights to use, copy, modify, merge, publish, distribute, and/or
+sell copies of the Data Files or Software, and to permit persons to whom the
+Data Files or Software are furnished to do so, provided that (a) the above
+copyright notice(s) and this permission notice appear with all copies of the
+Data Files or Software, (b) both the above copyright notice(s) and this
+permission notice appear in associated documentation, and (c) there is clear
+notice in each modified Data File or in the Software as well as in the
+documentation associated with the Data File(s) or Software that the data or
+software has been modified.
+
+    THE DATA FILES AND SOFTWARE ARE 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 OF THIRD
+PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE
+DATA FILES OR SOFTWARE.
+
+    Except as contained in this notice, the name of a copyright holder shall
+not be used in advertising or otherwise to promote the sale, use or other
+dealings in these Data Files or Software without prior written authorization
+of the copyright holder.
diff --git a/Makefile.am b/Makefile.am
index 3c4702c..425d1ec 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -69,6 +69,7 @@ pkgconfig_DATA = ibus-@IBUS_API_VERSION@.pc
 
 ibus_pc_in = ibus-@IBUS_API_VERSION@.pc.in
 EXTRA_DIST = \
+	COPYING.unicode \
 	autogen.sh \
 	$(ibus_pc_in) \
 	ibus.spec.in \
diff --git a/configure.ac b/configure.ac
index 3128ef9..f789819 100644
--- a/configure.ac
+++ b/configure.ac
@@ -608,12 +608,20 @@ AC_ARG_ENABLE(emoji-dict,
 )
 AM_CONDITIONAL([ENABLE_EMOJI_DICT], [test x"$enable_emoji_dict" = x"yes"])
 if test x"$enable_emoji_dict" = x"yes"; then
-    PKG_CHECK_MODULES(LIBXML2, [
-        libxml-2.0
+    PKG_CHECK_MODULES(JSON_GLIB1, [
+        json-glib-1.0
     ])
     enable_emoji_dict="yes (enabled, use --disable-emoji-dict to disable)"
 fi
 
+AC_ARG_WITH(emoji-json-file,
+    AS_HELP_STRING([--with-emoji-json-file[=DIR/emoji.json]],
+        [Set emoji.json. (default: "/usr/lib/node_modules/emojione/emoji.json")]),
+    EMOJI_JSON_FILE=$with_emoji_json_file,
+    EMOJI_JSON_FILE="/usr/lib/node_modules/emojione/emoji.json"
+)
+AC_SUBST(EMOJI_JSON_FILE)
+
 # Check iso-codes.
 PKG_CHECK_MODULES(ISOCODES, [
     iso-codes
@@ -639,6 +647,7 @@ engine/Makefile
 util/Makefile
 util/IMdkit/Makefile
 data/Makefile
+data/annotations/Makefile.am
 data/icons/Makefile
 data/keymaps/Makefile
 data/dconf/Makefile
@@ -698,6 +707,7 @@ Build options:
   Enable surrounding-text       $enable_surrounding_text
   Enable libnotify              $enable_libnotify
   Enable Emoji dict             $enable_emoji_dict
+  emoji.json path               $EMOJI_JSON_FILE
   Run test cases                $enable_tests
 ])
 
diff --git a/data/Makefile.am b/data/Makefile.am
index e41c9a2..d9d613f 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -2,8 +2,8 @@
 #
 # ibus - The Input Bus
 #
-# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
-# Copyright (c) 2007-2010 Red Hat, Inc.
+# Copyright (c) 2007-2016 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2007-2016 Red Hat, Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -21,6 +21,7 @@
 # USA
 
 SUBDIRS = \
+	annotations \
 	icons \
 	keymaps \
 	$(NULL)
diff --git a/data/annotations/Makefile.am b/data/annotations/Makefile.am
new file mode 100644
index 0000000..d87b933
--- /dev/null
+++ b/data/annotations/Makefile.am
@@ -0,0 +1,27 @@
+# vim:set noet ts=4:
+#
+# ibus - The Input Bus
+#
+# Copyright (c) 2016 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2016 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+# USA
+
+EXTRA_DIST = \
+	en.xml \
+	$(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/data/annotations/en.xml b/data/annotations/en.xml
new file mode 100644
index 0000000..ff7aa89
--- /dev/null
+++ b/data/annotations/en.xml
@@ -0,0 +1,1042 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!DOCTYPE ldml SYSTEM '../../common/dtd/ldml.dtd'>
+<!--	ยฉ 1991-2015 Unicode, Inc.
+	Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+	For terms of use, see http://www.unicode.org/copyright.html
+	CLDR data files are interpreted according to the LDML specification (http://unicode.org/reports/tr35/)
+
+	DO NOT CHANGE MANUALLY! Generated by: GenerateOtherAnnotations
+ -->
+<ldml>
+	<identity>
+		<version number="$Revision: 12320 $"/>
+		<language type='en'/>
+	</identity>
+	<annotations>
+		<annotation cp='[๐Ÿ˜€]' tts='grinning face'>face; grin</annotation>
+		<annotation cp='[๐Ÿ˜]' tts='grinning face with smiling eyes'>eye; face; grin; smile</annotation>
+		<annotation cp='[๐Ÿ˜‚]' tts='face with tears of joy'>face; joy; laugh; tear</annotation>
+		<annotation cp='[๐Ÿ˜ƒ]' tts='smiling face with open mouth'>face; mouth; open; smile</annotation>
+		<annotation cp='[๐Ÿ˜„]' tts='smiling face with open mouth and smiling eyes'>eye; face; mouth; open; smile</annotation>
+		<annotation cp='[๐Ÿ˜…]' tts='smiling face with open mouth and cold sweat'>cold; face; open; smile; sweat</annotation>
+		<annotation cp='[๐Ÿ˜†]' tts='smiling face with open mouth and tightly-closed eyes'>face; laugh; mouth; open; satisfied; smile</annotation>
+		<annotation cp='[๐Ÿ˜‰]' tts='winking face'>face; wink</annotation>
+		<annotation cp='[๐Ÿ˜Š]' tts='smiling face with smiling eyes'>blush; eye; face; smile</annotation>
+		<annotation cp='[๐Ÿ˜‹]' tts='face savouring delicious food'>delicious; face; savouring; smile; um; yum</annotation>
+		<annotation cp='[๐Ÿ˜Ž]' tts='smiling face with sunglasses'>bright; cool; eye; eyewear; face; glasses; smile; sun; sunglasses; weather</annotation>
+		<annotation cp='[๐Ÿ˜]' tts='smiling face with heart-shaped eyes'>eye; face; heart; love; smile</annotation>
+		<annotation cp='[๐Ÿ˜˜]' tts='face throwing a kiss'>face; heart; kiss</annotation>
+		<annotation cp='[๐Ÿ˜—]' tts='kissing face'>face; kiss</annotation>
+		<annotation cp='[๐Ÿ˜™]' tts='kissing face with smiling eyes'>eye; face; kiss; smile</annotation>
+		<annotation cp='[๐Ÿ˜š]' tts='kissing face with closed eyes'>closed; eye; face; kiss</annotation>
+		<annotation cp='[โ˜บ]' tts='smiling face'>face; outlined; relaxed; smile</annotation>
+		<annotation cp='[๐Ÿ™‚]' tts='slightly smiling face'>face; smile</annotation>
+		<annotation cp='[๐Ÿค—]' tts='hugging face'>face; hug; hugging</annotation>
+		<annotation cp='[๐Ÿ˜‡]' tts='smiling face with halo'>angel; face; fairy tale; fantasy; halo; innocent; smile</annotation>
+		<annotation cp='[๐Ÿค”]' tts='thinking face'>face; thinking</annotation>
+		<annotation cp='[๐Ÿ˜]' tts='neutral face'>deadpan; face; neutral</annotation>
+		<annotation cp='[๐Ÿ˜‘]' tts='expressionless face'>expressionless; face; inexpressive; unexpressive</annotation>
+		<annotation cp='[๐Ÿ˜ถ]' tts='face without mouth'>face; mouth; quiet; silent</annotation>
+		<annotation cp='[๐Ÿ™„]' tts='face with rolling eyes'>eyes; face; rolling</annotation>
+		<annotation cp='[๐Ÿ˜]' tts='smirking face'>face; smirk</annotation>
+		<annotation cp='[๐Ÿ˜ฃ]' tts='persevering face'>face; persevere</annotation>
+		<annotation cp='[๐Ÿ˜ฅ]' tts='disappointed but relieved face'>disappointed; face; relieved; whew</annotation>
+		<annotation cp='[๐Ÿ˜ฎ]' tts='face with open mouth'>face; mouth; open; sympathy</annotation>
+		<annotation cp='[๐Ÿค]' tts='zipper-mouth face'>face; mouth; zipper</annotation>
+		<annotation cp='[๐Ÿ˜ฏ]' tts='hushed face'>face; hushed; stunned; surprised</annotation>
+		<annotation cp='[๐Ÿ˜ช]' tts='sleepy face'>face; sleep</annotation>
+		<annotation cp='[๐Ÿ˜ซ]' tts='tired face'>face; tired</annotation>
+		<annotation cp='[๐Ÿ˜ด]' tts='sleeping face'>face; sleep; zzz</annotation>
+		<annotation cp='[๐Ÿ˜Œ]' tts='relieved face'>face; relieved</annotation>
+		<annotation cp='[๐Ÿค“]' tts='nerd face'>face; geek; nerd</annotation>
+		<annotation cp='[๐Ÿ˜›]' tts='face with stuck-out tongue'>face; tongue</annotation>
+		<annotation cp='[๐Ÿ˜œ]' tts='face with stuck-out tongue and winking eye'>eye; face; joke; tongue; wink</annotation>
+		<annotation cp='[๐Ÿ˜]' tts='face with stuck-out tongue and tightly-closed eyes'>eye; face; horrible; taste; tongue</annotation>
+		<annotation cp='[โ˜น]' tts='frowning face'>face; frown</annotation>
+		<annotation cp='[๐Ÿ™]' tts='slightly frowning face'>face; frown</annotation>
+		<annotation cp='[๐Ÿ˜’]' tts='unamused face'>face; unamused; unhappy</annotation>
+		<annotation cp='[๐Ÿ˜“]' tts='face with cold sweat'>cold; face; sweat</annotation>
+		<annotation cp='[๐Ÿ˜”]' tts='pensive face'>dejected; face; pensive</annotation>
+		<annotation cp='[๐Ÿ˜•]' tts='confused face'>confused; face</annotation>
+		<annotation cp='[๐Ÿ˜–]' tts='confounded face'>confounded; face</annotation>
+		<annotation cp='[๐Ÿ™ƒ]' tts='upside-down face'>face; upside-down</annotation>
+		<annotation cp='[๐Ÿ˜ท]' tts='face with medical mask'>cold; doctor; face; mask; medicine; sick</annotation>
+		<annotation cp='[๐Ÿค’]' tts='face with thermometer'>face; ill; sick; thermometer</annotation>
+		<annotation cp='[๐Ÿค•]' tts='face with head-bandage'>bandage; face; hurt; injury</annotation>
+		<annotation cp='[๐Ÿค‘]' tts='money-mouth face'>face; money; mouth</annotation>
+		<annotation cp='[๐Ÿ˜ฒ]' tts='astonished face'>astonished; face; shocked; totally</annotation>
+		<annotation cp='[๐Ÿ˜ž]' tts='disappointed face'>disappointed; face</annotation>
+		<annotation cp='[๐Ÿ˜Ÿ]' tts='worried face'>face; worried</annotation>
+		<annotation cp='[๐Ÿ˜ค]' tts='face with steam from nose'>face; triumph; won</annotation>
+		<annotation cp='[๐Ÿ˜ข]' tts='crying face'>cry; face; sad; tear</annotation>
+		<annotation cp='[๐Ÿ˜ญ]' tts='loudly crying face'>cry; face; sad; sob; tear</annotation>
+		<annotation cp='[๐Ÿ˜ฆ]' tts='frowning face with open mouth'>face; frown; mouth; open</annotation>
+		<annotation cp='[๐Ÿ˜ง]' tts='anguished face'>anguished; face</annotation>
+		<annotation cp='[๐Ÿ˜จ]' tts='fearful face'>face; fear; fearful; scared</annotation>
+		<annotation cp='[๐Ÿ˜ฉ]' tts='weary face'>face; tired; weary</annotation>
+		<annotation cp='[๐Ÿ˜ฌ]' tts='grimacing face'>face; grimace</annotation>
+		<annotation cp='[๐Ÿ˜ฐ]' tts='face with open mouth and cold sweat'>blue; cold; face; mouth; open; rushed; sweat</annotation>
+		<annotation cp='[๐Ÿ˜ฑ]' tts='face screaming in fear'>face; fear; fearful; munch; scared; scream</annotation>
+		<annotation cp='[๐Ÿ˜ณ]' tts='flushed face'>dazed; face; flushed</annotation>
+		<annotation cp='[๐Ÿ˜ต]' tts='dizzy face'>dizzy; face</annotation>
+		<annotation cp='[๐Ÿ˜ก]' tts='pouting face'>angry; face; mad; pouting; rage; red</annotation>
+		<annotation cp='[๐Ÿ˜ ]' tts='angry face'>angry; face; mad</annotation>
+		<annotation cp='[๐Ÿ˜ˆ]' tts='smiling face with horns'>face; fairy tale; fantasy; horns; smile</annotation>
+		<annotation cp='[๐Ÿ‘ฟ]' tts='imp'>demon; devil; face; fairy tale; fantasy</annotation>
+		<annotation cp='[๐Ÿ‘น]' tts='ogre'>creature; face; fairy tale; fantasy; japanese; monster</annotation>
+		<annotation cp='[๐Ÿ‘บ]' tts='goblin'>creature; face; fairy tale; fantasy; japanese; monster</annotation>
+		<annotation cp='[๐Ÿ’€]' tts='skull'>body; death; face; fairy tale; monster</annotation>
+		<annotation cp='[โ˜ ]' tts='skull and crossbones'>body; crossbones; death; face; monster; skull</annotation>
+		<annotation cp='[๐Ÿ‘ป]' tts='ghost'>creature; face; fairy tale; fantasy; monster</annotation>
+		<annotation cp='[๐Ÿ‘ฝ]' tts='alien'>creature; extraterrestrial; face; fairy tale; fantasy; monster; space; ufo</annotation>
+		<annotation cp='[๐Ÿ‘พ]' tts='alien monster'>alien; creature; extraterrestrial; face; fairy tale; fantasy; monster; space; ufo</annotation>
+		<annotation cp='[๐Ÿค–]' tts='robot face'>face; monster; robot</annotation>
+		<annotation cp='[๐Ÿ’ฉ]' tts='pile of poo'>comic; dung; face; monster; poo; poop</annotation>
+		<annotation cp='[๐Ÿ˜บ]' tts='smiling cat face with open mouth'>cat; face; mouth; open; smile</annotation>
+		<annotation cp='[๐Ÿ˜ธ]' tts='grinning cat face with smiling eyes'>cat; eye; face; grin; smile</annotation>
+		<annotation cp='[๐Ÿ˜น]' tts='cat face with tears of joy'>cat; face; joy; tear</annotation>
+		<annotation cp='[๐Ÿ˜ป]' tts='smiling cat face with heart-shaped eyes'>cat; eye; face; heart; love; smile</annotation>
+		<annotation cp='[๐Ÿ˜ผ]' tts='cat face with wry smile'>cat; face; ironic; smile; wry</annotation>
+		<annotation cp='[๐Ÿ˜ฝ]' tts='kissing cat face with closed eyes'>cat; eye; face; kiss</annotation>
+		<annotation cp='[๐Ÿ™€]' tts='weary cat face'>cat; face; oh; surprised; weary</annotation>
+		<annotation cp='[๐Ÿ˜ฟ]' tts='crying cat face'>cat; cry; face; sad; tear</annotation>
+		<annotation cp='[๐Ÿ˜พ]' tts='pouting cat face'>cat; face; pouting</annotation>
+		<annotation cp='[๐Ÿ™ˆ]' tts='see-no-evil'>evil; face; forbidden; gesture; monkey; no; not; prohibited; see</annotation>
+		<annotation cp='[๐Ÿ™‰]' tts='hear-no-evil'>evil; face; forbidden; gesture; hear; monkey; no; not; prohibited</annotation>
+		<annotation cp='[๐Ÿ™Š]' tts='speak-no-evil'>evil; face; forbidden; gesture; monkey; no; not; prohibited; speak</annotation>
+		<annotation cp='[๐Ÿ‘ฆ]' tts='boy'>boy</annotation>
+		<annotation cp='[๐Ÿ‘ง]' tts='girl'>maiden; virgin; virgo; zodiac</annotation>
+		<annotation cp='[๐Ÿ‘จ]' tts='man'>man</annotation>
+		<annotation cp='[๐Ÿ‘ฉ]' tts='woman'>woman</annotation>
+		<annotation cp='[๐Ÿ‘ด]' tts='old man'>man; old</annotation>
+		<annotation cp='[๐Ÿ‘ต]' tts='old woman'>old; woman</annotation>
+		<annotation cp='[๐Ÿ‘ถ]' tts='baby'>baby</annotation>
+		<annotation cp='[๐Ÿ‘ฑ]' tts='person with blond hair'>blond</annotation>
+		<annotation cp='[๐Ÿ‘ฎ]' tts='police officer'>cop; officer; police</annotation>
+		<annotation cp='[๐Ÿ‘ฒ]' tts='man with chinese cap'>gua pi mao; hat; man</annotation>
+		<annotation cp='[๐Ÿ‘ณ]' tts='man with turban'>man; turban</annotation>
+		<annotation cp='[๐Ÿ‘ท]' tts='construction worker'>construction; hat; worker</annotation>
+		<annotation cp='[โ›‘]' tts='helmet with white cross'>aid; cross; face; hat; helmet</annotation>
+		<annotation cp='[๐Ÿ‘ธ]' tts='princess'>fairy tale; fantasy</annotation>
+		<annotation cp='[๐Ÿ’‚]' tts='guardsman'>guard</annotation>
+		<annotation cp='[๐Ÿ•ต]' tts='detective'>sleuth; spy</annotation>
+		<annotation cp='[๐ŸŽ…]' tts='santa claus'>celebration; christmas; fairy tale; fantasy; father; santa</annotation>
+		<annotation cp='[๐Ÿ‘ผ]' tts='baby angel'>angel; baby; face; fairy tale; fantasy</annotation>
+		<annotation cp='[๐Ÿ’†]' tts='face massage'>massage; salon</annotation>
+		<annotation cp='[๐Ÿ’‡]' tts='haircut'>barber; beauty; parlor</annotation>
+		<annotation cp='[๐Ÿ‘ฐ]' tts='bride with veil'>bride; veil; wedding</annotation>
+		<annotation cp='[๐Ÿ™]' tts='person frowning'>frown; gesture</annotation>
+		<annotation cp='[๐Ÿ™Ž]' tts='person pouting'>gesture; pouting</annotation>
+		<annotation cp='[๐Ÿ™…]' tts='gesturing no'>forbidden; gesture; hand; no; not; prohibited</annotation>
+		<annotation cp='[๐Ÿ™†]' tts='gesturing ok'>gesture; hand; ok</annotation>
+		<annotation cp='[๐Ÿ’]' tts='information desk person'>hand; help; information; sassy</annotation>
+		<annotation cp='[๐Ÿ™‹]' tts='happy person raising hand'>gesture; hand; happy; raised</annotation>
+		<annotation cp='[๐Ÿ™‡]' tts='person bowing'>apology; bow; gesture; sorry</annotation>
+		<annotation cp='[๐Ÿ™Œ]' tts='person raising hands'>body; celebration; gesture; hand; hooray; raised</annotation>
+		<annotation cp='[๐Ÿ™]' tts='folded hands'>ask; body; bow; folded; gesture; hand; please; pray; thanks</annotation>
+		<annotation cp='[๐Ÿ—ฃ]' tts='speaking head'>face; head; silhouette; speak; speaking</annotation>
+		<annotation cp='[๐Ÿ‘ค]' tts='bust in silhouette'>bust; silhouette</annotation>
+		<annotation cp='[๐Ÿ‘ฅ]' tts='busts in silhouette'>bust; silhouette</annotation>
+		<annotation cp='[๐Ÿšถ]' tts='pedestrian'>hike; walk; walking</annotation>
+		<annotation cp='[๐Ÿƒ]' tts='runner'>marathon; running</annotation>
+		<annotation cp='[๐Ÿ‘ฏ]' tts='women partying'>bunny; dancer; ear; girl; woman</annotation>
+		<annotation cp='[๐Ÿ’ƒ]' tts='dancer'>dancer</annotation>
+		<annotation cp='[๐Ÿ•ด]' tts='man in business suit levitating'>business; man; suit</annotation>
+		<annotation cp='[๐Ÿ’]' tts='kiss'>couple; romance</annotation>
+		<annotation cp='[๐Ÿ’‘]' tts='couple with heart'>couple; heart; love; romance</annotation>
+		<annotation cp='[๐Ÿ‘ช]' tts='family'>child; father; mother</annotation>
+		<annotation cp='[๐Ÿ‘ซ]' tts='man and woman holding hands'>couple; hand; hold; man; woman</annotation>
+		<annotation cp='[๐Ÿ‘ฌ]' tts='two men holding hands'>couple; gemini; hand; hold; man; twins; zodiac</annotation>
+		<annotation cp='[๐Ÿ‘ญ]' tts='two women holding hands'>couple; hand; hold; woman</annotation>
+		<annotation cp='[๐Ÿป]' tts='skin type-1-2'>emoji modifier; fitzpatrick; skin; tone</annotation>
+		<annotation cp='[๐Ÿผ]' tts='skin type-3'>emoji modifier; fitzpatrick; skin; tone</annotation>
+		<annotation cp='[๐Ÿฝ]' tts='skin type-4'>emoji modifier; fitzpatrick; skin; tone</annotation>
+		<annotation cp='[๐Ÿพ]' tts='skin type-5'>emoji modifier; fitzpatrick; skin; tone</annotation>
+		<annotation cp='[๐Ÿฟ]' tts='skin type-6'>emoji modifier; fitzpatrick; skin; tone</annotation>
+		<annotation cp='[๐Ÿ’ช]' tts='flexed biceps'>biceps; body; comic; flex; muscle</annotation>
+		<annotation cp='[๐Ÿ‘ˆ]' tts='backhand index pointing left'>backhand; body; finger; hand; index; point</annotation>
+		<annotation cp='[๐Ÿ‘‰]' tts='backhand index pointing right'>backhand; body; finger; hand; index; point</annotation>
+		<annotation cp='[โ˜]' tts='index pointing up'>body; finger; hand; index; point; up</annotation>
+		<annotation cp='[๐Ÿ‘†]' tts='backhand index pointing up'>backhand; body; finger; hand; index; point; up</annotation>
+		<annotation cp='[๐Ÿ–•]' tts='middle finger'>body; finger; hand</annotation>
+		<annotation cp='[๐Ÿ‘‡]' tts='backhand index pointing down'>backhand; body; down; finger; hand; index; point</annotation>
+		<annotation cp='[โœŒ]' tts='victory hand'>body; hand; v; victory</annotation>
+		<annotation cp='[๐Ÿ––]' tts='vulcan salute'>body; finger; hand; spock; vulcan</annotation>
+		<annotation cp='[๐Ÿค˜]' tts='sign of the horns'>body; finger; hand; horns; rock-on</annotation>
+		<annotation cp='[๐Ÿ–]' tts='raised hand with fingers splayed'>body; finger; hand; splayed</annotation>
+		<annotation cp='[โœ‹]' tts='raised hand'>body; hand</annotation>
+		<annotation cp='[๐Ÿ‘Œ]' tts='ok hand'>body; hand; ok</annotation>
+		<annotation cp='[๐Ÿ‘]' tts='thumbs up'>+1; body; hand; thumb; up</annotation>
+		<annotation cp='[๐Ÿ‘Ž]' tts='thumbs down'>-1; body; down; hand; thumb</annotation>
+		<annotation cp='[โœŠ]' tts='raised fist'>body; clenched; fist; hand; punch</annotation>
+		<annotation cp='[๐Ÿ‘Š]' tts='oncoming fist'>body; clenched; fist; hand; punch</annotation>
+		<annotation cp='[๐Ÿ‘‹]' tts='waving hand'>body; hand; wave; waving</annotation>
+		<annotation cp='[๐Ÿ‘]' tts='clapping hands'>body; clap; hand</annotation>
+		<annotation cp='[๐Ÿ‘]' tts='open hands'>body; hand; open</annotation>
+		<annotation cp='[โœ]' tts='writing hand'>body; hand; write</annotation>
+		<annotation cp='[๐Ÿ’…]' tts='nail polish'>body; care; cosmetics; manicure; nail; polish</annotation>
+		<annotation cp='[๐Ÿ‘‚]' tts='ear'>body</annotation>
+		<annotation cp='[๐Ÿ‘ƒ]' tts='nose'>body</annotation>
+		<annotation cp='[๐Ÿ‘ฃ]' tts='footprints'>body; clothing; footprint; print</annotation>
+		<annotation cp='[๐Ÿ‘€]' tts='eyes'>body; eye; face</annotation>
+		<annotation cp='[๐Ÿ‘]' tts='eye'>body</annotation>
+		<annotation cp='[๐Ÿ‘…]' tts='tongue'>body</annotation>
+		<annotation cp='[๐Ÿ‘„]' tts='mouth'>body; lips</annotation>
+		<annotation cp='[๐Ÿ’‹]' tts='kiss mark'>heart; kiss; lips; mark; romance</annotation>
+		<annotation cp='[๐Ÿ’˜]' tts='heart with arrow'>arrow; cupid; heart; romance</annotation>
+		<annotation cp='[โค]' tts='red heart'>heart</annotation>
+		<annotation cp='[๐Ÿ’“]' tts='beating heart'>beating; heart; heartbeat; pulsating</annotation>
+		<annotation cp='[๐Ÿ’”]' tts='broken heart'>break; broken; heart</annotation>
+		<annotation cp='[๐Ÿ’•]' tts='two hearts'>heart; love</annotation>
+		<annotation cp='[๐Ÿ’–]' tts='sparkling heart'>excited; heart; sparkle</annotation>
+		<annotation cp='[๐Ÿ’—]' tts='growing heart'>excited; growing; heart; heartpulse; nervous</annotation>
+		<annotation cp='[๐Ÿ’™]' tts='blue heart'>blue; heart</annotation>
+		<annotation cp='[๐Ÿ’š]' tts='green heart'>green; heart</annotation>
+		<annotation cp='[๐Ÿ’›]' tts='yellow heart'>heart; yellow</annotation>
+		<annotation cp='[๐Ÿ’œ]' tts='purple heart'>heart; purple</annotation>
+		<annotation cp='[๐Ÿ’]' tts='heart with ribbon'>heart; ribbon; valentine</annotation>
+		<annotation cp='[๐Ÿ’ž]' tts='revolving hearts'>heart; revolving</annotation>
+		<annotation cp='[๐Ÿ’Ÿ]' tts='heart decoration'>heart</annotation>
+		<annotation cp='[โฃ]' tts='heavy heart exclamation mark ornament'>exclamation; heart; mark; punctuation</annotation>
+		<annotation cp='[๐Ÿ’Œ]' tts='love letter'>heart; letter; love; mail; romance</annotation>
+		<annotation cp='[๐Ÿ’ค]' tts='zzz'>comic; sleep</annotation>
+		<annotation cp='[๐Ÿ’ข]' tts='anger symbol'>angry; comic; mad</annotation>
+		<annotation cp='[๐Ÿ’ฃ]' tts='bomb'>comic</annotation>
+		<annotation cp='[๐Ÿ’ฅ]' tts='collision'>boom; comic</annotation>
+		<annotation cp='[๐Ÿ’ฆ]' tts='sweat droplets'>comic; splashing; sweat</annotation>
+		<annotation cp='[๐Ÿ’จ]' tts='dashing'>comic; dash; running</annotation>
+		<annotation cp='[๐Ÿ’ซ]' tts='dizzy'>comic; star</annotation>
+		<annotation cp='[๐Ÿ’ฌ]' tts='speech balloon'>balloon; bubble; comic; dialog; speech</annotation>
+		<annotation cp='[๐Ÿ—จ]' tts='left speech bubble'>dialog; speech</annotation>
+		<annotation cp='[๐Ÿ—ฏ]' tts='right anger bubble'>angry; balloon; bubble; mad</annotation>
+		<annotation cp='[๐Ÿ’ญ]' tts='thought balloon'>balloon; bubble; comic; thought</annotation>
+		<annotation cp='[๐Ÿ•ณ]' tts='hole'>hole</annotation>
+		<annotation cp='[๐Ÿ‘“]' tts='glasses'>clothing; eye; eyeglasses; eyewear</annotation>
+		<annotation cp='[๐Ÿ•ถ]' tts='sunglasses'>dark; eye; eyewear; glasses</annotation>
+		<annotation cp='[๐Ÿ‘”]' tts='necktie'>clothing</annotation>
+		<annotation cp='[๐Ÿ‘•]' tts='t-shirt'>clothing; shirt; tshirt</annotation>
+		<annotation cp='[๐Ÿ‘–]' tts='jeans'>clothing; pants; trousers</annotation>
+		<annotation cp='[๐Ÿ‘—]' tts='dress'>clothing</annotation>
+		<annotation cp='[๐Ÿ‘˜]' tts='kimono'>clothing</annotation>
+		<annotation cp='[๐Ÿ‘™]' tts='bikini'>clothing; swim</annotation>
+		<annotation cp='[๐Ÿ‘š]' tts='womanโ€™s clothes'>clothing; woman</annotation>
+		<annotation cp='[๐Ÿ‘›]' tts='purse'>clothing; coin</annotation>
+		<annotation cp='[๐Ÿ‘œ]' tts='handbag'>bag; clothing</annotation>
+		<annotation cp='[๐Ÿ‘]' tts='pouch'>bag; clothing</annotation>
+		<annotation cp='[๐Ÿ›]' tts='shopping bags'>bag; hotel; shopping</annotation>
+		<annotation cp='[๐ŸŽ’]' tts='school backpack'>bag; satchel; school</annotation>
+		<annotation cp='[๐Ÿ‘ž]' tts='manโ€™s shoe'>clothing; man; shoe</annotation>
+		<annotation cp='[๐Ÿ‘Ÿ]' tts='running shoe'>athletic; clothing; shoe; sneaker</annotation>
+		<annotation cp='[๐Ÿ‘ ]' tts='high-heeled shoe'>clothing; heel; shoe; woman</annotation>
+		<annotation cp='[๐Ÿ‘ก]' tts='womanโ€™s sandal'>clothing; sandal; shoe; woman</annotation>
+		<annotation cp='[๐Ÿ‘ข]' tts='womanโ€™s boot'>boot; clothing; shoe; woman</annotation>
+		<annotation cp='[๐Ÿ‘‘]' tts='crown'>clothing; king; queen</annotation>
+		<annotation cp='[๐Ÿ‘’]' tts='womanโ€™s hat'>clothing; hat; woman</annotation>
+		<annotation cp='[๐ŸŽฉ]' tts='top hat'>clothing; hat; top; tophat</annotation>
+		<annotation cp='[๐ŸŽ“]' tts='graduation cap'>cap; celebration; clothing; graduation; hat</annotation>
+		<annotation cp='[๐Ÿ“ฟ]' tts='prayer beads'>beads; clothing; necklace; prayer; religion</annotation>
+		<annotation cp='[๐Ÿ’„]' tts='lipstick'>cosmetics; makeup</annotation>
+		<annotation cp='[๐Ÿ’]' tts='ring'>diamond; romance</annotation>
+		<annotation cp='[๐Ÿ’Ž]' tts='gem stone'>diamond; gem; jewel; romance</annotation>
+		<annotation cp='[๐Ÿต]' tts='monkey face'>face; monkey</annotation>
+		<annotation cp='[๐Ÿ’]' tts='monkey'>monkey</annotation>
+		<annotation cp='[๐Ÿถ]' tts='dog face'>dog; face; pet</annotation>
+		<annotation cp='[๐Ÿ•]' tts='dog'>pet</annotation>
+		<annotation cp='[๐Ÿฉ]' tts='poodle'>dog</annotation>
+		<annotation cp='[๐Ÿบ]' tts='wolf face'>face; wolf</annotation>
+		<annotation cp='[๐Ÿฑ]' tts='cat face'>cat; face; pet</annotation>
+		<annotation cp='[๐Ÿˆ]' tts='cat'>pet</annotation>
+		<annotation cp='[๐Ÿฆ]' tts='lion face'>face; leo; lion; zodiac</annotation>
+		<annotation cp='[๐Ÿฏ]' tts='tiger face'>face; tiger</annotation>
+		<annotation cp='[๐Ÿ…]' tts='tiger'>tiger</annotation>
+		<annotation cp='[๐Ÿ†]' tts='leopard'>leopard</annotation>
+		<annotation cp='[๐Ÿด]' tts='horse face'>face; horse</annotation>
+		<annotation cp='[๐ŸŽ]' tts='horse'>racehorse; racing</annotation>
+		<annotation cp='[๐Ÿฆ„]' tts='unicorn face'>face; unicorn</annotation>
+		<annotation cp='[๐Ÿฎ]' tts='cow face'>cow; face</annotation>
+		<annotation cp='[๐Ÿ‚]' tts='ox'>bull; taurus; zodiac</annotation>
+		<annotation cp='[๐Ÿƒ]' tts='water buffalo'>buffalo; water</annotation>
+		<annotation cp='[๐Ÿ„]' tts='cow'>cow</annotation>
+		<annotation cp='[๐Ÿท]' tts='pig face'>face; pig</annotation>
+		<annotation cp='[๐Ÿ–]' tts='pig'>sow</annotation>
+		<annotation cp='[๐Ÿ—]' tts='boar'>pig</annotation>
+		<annotation cp='[๐Ÿฝ]' tts='pig nose'>face; nose; pig</annotation>
+		<annotation cp='[๐Ÿ]' tts='ram'>aries; sheep; zodiac</annotation>
+		<annotation cp='[๐Ÿ‘]' tts='sheep'>ewe</annotation>
+		<annotation cp='[๐Ÿ]' tts='goat'>capricorn; zodiac</annotation>
+		<annotation cp='[๐Ÿช]' tts='camel'>dromedary; hump</annotation>
+		<annotation cp='[๐Ÿซ]' tts='two-hump camel'>bactrian; camel; hump</annotation>
+		<annotation cp='[๐Ÿ˜]' tts='elephant'>elephant</annotation>
+		<annotation cp='[๐Ÿญ]' tts='mouse face'>face; mouse</annotation>
+		<annotation cp='[๐Ÿ]' tts='mouse'>mouse</annotation>
+		<annotation cp='[๐Ÿ€]' tts='rat'>rat</annotation>
+		<annotation cp='[๐Ÿน]' tts='hamster face'>face; hamster; pet</annotation>
+		<annotation cp='[๐Ÿฐ]' tts='rabbit face'>bunny; face; pet; rabbit</annotation>
+		<annotation cp='[๐Ÿ‡]' tts='rabbit'>bunny; pet</annotation>
+		<annotation cp='[๐Ÿฟ]' tts='chipmunk'>chipmunk</annotation>
+		<annotation cp='[๐Ÿป]' tts='bear face'>bear; face</annotation>
+		<annotation cp='[๐Ÿจ]' tts='koala'>bear</annotation>
+		<annotation cp='[๐Ÿผ]' tts='panda face'>face; panda</annotation>
+		<annotation cp='[๐Ÿพ]' tts='paw prints'>feet; paw; print</annotation>
+		<annotation cp='[๐Ÿฆƒ]' tts='turkey'>turkey</annotation>
+		<annotation cp='[๐Ÿ”]' tts='chicken'>chicken</annotation>
+		<annotation cp='[๐Ÿ“]' tts='rooster'>rooster</annotation>
+		<annotation cp='[๐Ÿฃ]' tts='hatching chick'>baby; chick; hatching</annotation>
+		<annotation cp='[๐Ÿค]' tts='baby chick'>baby; chick</annotation>
+		<annotation cp='[๐Ÿฅ]' tts='front-facing baby chick'>baby; chick</annotation>
+		<annotation cp='[๐Ÿฆ]' tts='bird'>bird</annotation>
+		<annotation cp='[๐Ÿง]' tts='penguin'>penguin</annotation>
+		<annotation cp='[๐Ÿ•Š]' tts='dove'>bird; fly; peace</annotation>
+		<annotation cp='[๐Ÿธ]' tts='frog face'>face; frog</annotation>
+		<annotation cp='[๐ŸŠ]' tts='crocodile'>crocodile</annotation>
+		<annotation cp='[๐Ÿข]' tts='turtle'>turtle</annotation>
+		<annotation cp='[๐Ÿ]' tts='snake'>bearer; ophiuchus; serpent; zodiac</annotation>
+		<annotation cp='[๐Ÿฒ]' tts='dragon face'>dragon; face; fairy tale</annotation>
+		<annotation cp='[๐Ÿ‰]' tts='dragon'>fairy tale</annotation>
+		<annotation cp='[๐Ÿณ]' tts='spouting whale'>face; spouting; whale</annotation>
+		<annotation cp='[๐Ÿ‹]' tts='whale'>whale</annotation>
+		<annotation cp='[๐Ÿฌ]' tts='dolphin'>flipper</annotation>
+		<annotation cp='[๐ŸŸ]' tts='fish'>pisces; zodiac</annotation>
+		<annotation cp='[๐Ÿ ]' tts='tropical fish'>fish; tropical</annotation>
+		<annotation cp='[๐Ÿก]' tts='blowfish'>fish</annotation>
+		<annotation cp='[๐Ÿ™]' tts='octopus'>octopus</annotation>
+		<annotation cp='[๐Ÿš]' tts='spiral shell'>shell; spiral</annotation>
+		<annotation cp='[๐Ÿฆ€]' tts='crab'>cancer; zodiac</annotation>
+		<annotation cp='[๐ŸŒ]' tts='snail'>snail</annotation>
+		<annotation cp='[๐Ÿ›]' tts='bug'>insect</annotation>
+		<annotation cp='[๐Ÿœ]' tts='ant'>insect</annotation>
+		<annotation cp='[๐Ÿ]' tts='honeybee'>bee; insect</annotation>
+		<annotation cp='[๐Ÿž]' tts='lady beetle'>beetle; insect; ladybird; ladybug</annotation>
+		<annotation cp='[๐Ÿ•ท]' tts='spider'>insect</annotation>
+		<annotation cp='[๐Ÿ•ธ]' tts='spider web'>spider; web</annotation>
+		<annotation cp='[๐Ÿฆ‚]' tts='scorpion'>scorpio; scorpius; zodiac</annotation>
+		<annotation cp='[๐Ÿ’]' tts='bouquet'>flower; plant; romance</annotation>
+		<annotation cp='[๐ŸŒธ]' tts='cherry blossom'>blossom; cherry; flower; plant</annotation>
+		<annotation cp='[๐Ÿ’ฎ]' tts='white flower'>flower</annotation>
+		<annotation cp='[๐Ÿต]' tts='rosette'>plant</annotation>
+		<annotation cp='[๐ŸŒน]' tts='rose'>flower; plant</annotation>
+		<annotation cp='[๐ŸŒบ]' tts='hibiscus'>flower; plant</annotation>
+		<annotation cp='[๐ŸŒป]' tts='sunflower'>flower; plant; sun</annotation>
+		<annotation cp='[๐ŸŒผ]' tts='blossom'>flower; plant</annotation>
+		<annotation cp='[๐ŸŒท]' tts='tulip'>flower; plant</annotation>
+		<annotation cp='[๐ŸŒฑ]' tts='seedling'>plant; young</annotation>
+		<annotation cp='[๐ŸŒฒ]' tts='evergreen'>plant; tree</annotation>
+		<annotation cp='[๐ŸŒณ]' tts='deciduous tree'>deciduous; plant; shedding; tree</annotation>
+		<annotation cp='[๐ŸŒด]' tts='palm tree'>palm; plant; tree</annotation>
+		<annotation cp='[๐ŸŒต]' tts='cactus'>plant</annotation>
+		<annotation cp='[๐ŸŒพ]' tts='sheaf of rice'>ear; plant; rice</annotation>
+		<annotation cp='[๐ŸŒฟ]' tts='herb'>leaf; plant</annotation>
+		<annotation cp='[โ˜˜]' tts='shamrock'>plant</annotation>
+		<annotation cp='[๐Ÿ€]' tts='four leaf clover'>4; clover; four; leaf; plant</annotation>
+		<annotation cp='[๐Ÿ]' tts='maple leaf'>falling; leaf; maple; plant</annotation>
+		<annotation cp='[๐Ÿ‚]' tts='fallen leaf'>falling; leaf; plant</annotation>
+		<annotation cp='[๐Ÿƒ]' tts='leaf fluttering in wind'>blow; flutter; leaf; plant; wind</annotation>
+		<annotation cp='[๐Ÿ‡]' tts='grapes'>fruit; grape; plant</annotation>
+		<annotation cp='[๐Ÿˆ]' tts='melon'>fruit; plant</annotation>
+		<annotation cp='[๐Ÿ‰]' tts='watermelon'>fruit; plant</annotation>
+		<annotation cp='[๐ŸŠ]' tts='tangerine'>fruit; orange; plant</annotation>
+		<annotation cp='[๐Ÿ‹]' tts='lemon'>citrus; fruit; plant</annotation>
+		<annotation cp='[๐ŸŒ]' tts='banana'>fruit; plant</annotation>
+		<annotation cp='[๐Ÿ]' tts='pineapple'>fruit; plant</annotation>
+		<annotation cp='[๐ŸŽ]' tts='red apple'>apple; fruit; plant; red</annotation>
+		<annotation cp='[๐Ÿ]' tts='green apple'>apple; fruit; green; plant</annotation>
+		<annotation cp='[๐Ÿ]' tts='pear'>fruit; plant</annotation>
+		<annotation cp='[๐Ÿ‘]' tts='peach'>fruit; plant</annotation>
+		<annotation cp='[๐Ÿ’]' tts='cherries'>cherry; fruit; plant</annotation>
+		<annotation cp='[๐Ÿ“]' tts='strawberry'>berry; fruit; plant</annotation>
+		<annotation cp='[๐Ÿ…]' tts='tomato'>plant; vegetable</annotation>
+		<annotation cp='[๐Ÿ†]' tts='eggplant'>aubergine; plant; vegetable</annotation>
+		<annotation cp='[๐ŸŒฝ]' tts='ear of corn'>corn; ear; maize; maze; plant</annotation>
+		<annotation cp='[๐ŸŒถ]' tts='hot pepper'>hot; pepper; plant</annotation>
+		<annotation cp='[๐Ÿ„]' tts='mushroom'>plant</annotation>
+		<annotation cp='[๐ŸŒฐ]' tts='chestnut'>plant</annotation>
+		<annotation cp='[๐Ÿž]' tts='bread'>loaf</annotation>
+		<annotation cp='[๐Ÿง€]' tts='cheese wedge'>cheese</annotation>
+		<annotation cp='[๐Ÿ–]' tts='meat on bone'>bone; meat</annotation>
+		<annotation cp='[๐Ÿ—]' tts='poultry leg'>bone; chicken; leg; poultry</annotation>
+		<annotation cp='[๐Ÿ”]' tts='hamburger'>burger</annotation>
+		<annotation cp='[๐ŸŸ]' tts='french fries'>french; fries</annotation>
+		<annotation cp='[๐Ÿ•]' tts='pizza'>cheese; slice</annotation>
+		<annotation cp='[๐ŸŒญ]' tts='hot dog'>frankfurter; hotdog; sausage</annotation>
+		<annotation cp='[๐ŸŒฎ]' tts='taco'>mexican</annotation>
+		<annotation cp='[๐ŸŒฏ]' tts='burrito'>mexican</annotation>
+		<annotation cp='[๐Ÿฟ]' tts='popcorn'>popcorn</annotation>
+		<annotation cp='[๐Ÿฒ]' tts='pot of food'>pot; stew</annotation>
+		<annotation cp='[๐Ÿฑ]' tts='bento box'>bento; box</annotation>
+		<annotation cp='[๐Ÿ˜]' tts='rice cracker'>cracker; rice</annotation>
+		<annotation cp='[๐Ÿ™]' tts='rice ball'>ball; japanese; rice</annotation>
+		<annotation cp='[๐Ÿš]' tts='cooked rice'>cooked; rice</annotation>
+		<annotation cp='[๐Ÿ›]' tts='curry rice'>curry; rice</annotation>
+		<annotation cp='[๐Ÿœ]' tts='steaming bowl'>bowl; noodle; ramen; steaming</annotation>
+		<annotation cp='[๐Ÿ]' tts='spaghetti'>pasta</annotation>
+		<annotation cp='[๐Ÿ ]' tts='roasted sweet potato'>potato; roasted; sweet</annotation>
+		<annotation cp='[๐Ÿข]' tts='oden'>kebab; seafood; skewer; stick</annotation>
+		<annotation cp='[๐Ÿฃ]' tts='sushi'>sushi</annotation>
+		<annotation cp='[๐Ÿค]' tts='fried shrimp'>fried; prawn; shrimp; tempura</annotation>
+		<annotation cp='[๐Ÿฅ]' tts='fish cake with swirl'>cake; fish; pastry; swirl</annotation>
+		<annotation cp='[๐Ÿก]' tts='dango'>dessert; japanese; skewer; stick; sweet</annotation>
+		<annotation cp='[๐Ÿฆ]' tts='soft ice cream'>cream; dessert; ice; icecream; soft; sweet</annotation>
+		<annotation cp='[๐Ÿง]' tts='shaved ice'>dessert; ice; shaved; sweet</annotation>
+		<annotation cp='[๐Ÿจ]' tts='ice cream'>cream; dessert; ice; sweet</annotation>
+		<annotation cp='[๐Ÿฉ]' tts='doughnut'>dessert; donut; sweet</annotation>
+		<annotation cp='[๐Ÿช]' tts='cookie'>dessert; sweet</annotation>
+		<annotation cp='[๐ŸŽ‚]' tts='birthday cake'>birthday; cake; celebration; dessert; pastry; sweet</annotation>
+		<annotation cp='[๐Ÿฐ]' tts='shortcake'>cake; dessert; pastry; slice; sweet</annotation>
+		<annotation cp='[๐Ÿซ]' tts='chocolate bar'>bar; chocolate; dessert; sweet</annotation>
+		<annotation cp='[๐Ÿฌ]' tts='candy'>dessert; sweet</annotation>
+		<annotation cp='[๐Ÿญ]' tts='lollipop'>candy; dessert; sweet</annotation>
+		<annotation cp='[๐Ÿฎ]' tts='custard'>dessert; pudding; sweet</annotation>
+		<annotation cp='[๐Ÿฏ]' tts='honey pot'>honey; honeypot; pot; sweet</annotation>
+		<annotation cp='[๐Ÿผ]' tts='baby bottle'>baby; bottle; drink; milk</annotation>
+		<annotation cp='[โ˜•]' tts='hot beverage'>beverage; coffee; drink; hot; steaming; tea</annotation>
+		<annotation cp='[๐Ÿต]' tts='teacup without handle'>beverage; cup; drink; tea; teacup</annotation>
+		<annotation cp='[๐Ÿถ]' tts='sake'>bar; beverage; bottle; cup; drink</annotation>
+		<annotation cp='[๐Ÿพ]' tts='bottle with popping cork'>bar; bottle; cork; drink; popping</annotation>
+		<annotation cp='[๐Ÿท]' tts='wine glass'>bar; beverage; drink; glass; wine</annotation>
+		<annotation cp='[๐Ÿธ]' tts='cocktail glass'>bar; cocktail; drink; glass</annotation>
+		<annotation cp='[๐Ÿน]' tts='tropical drink'>bar; drink; tropical</annotation>
+		<annotation cp='[๐Ÿบ]' tts='beer mug'>bar; beer; drink; mug</annotation>
+		<annotation cp='[๐Ÿป]' tts='clinking beer mugs'>bar; beer; clink; drink; mug</annotation>
+		<annotation cp='[๐Ÿฝ]' tts='fork and knife with plate'>cooking; fork; knife; plate</annotation>
+		<annotation cp='[๐Ÿด]' tts='fork and knife'>cooking; fork; knife</annotation>
+		<annotation cp='[๐Ÿณ]' tts='cooking'>egg; frying; pan</annotation>
+		<annotation cp='[๐Ÿบ]' tts='amphora'>aquarius; cooking; drink; jug; tool; weapon; zodiac</annotation>
+		<annotation cp='[๐ŸŒ]' tts='globe showing europe-africa'>africa; earth; europe; globe; world</annotation>
+		<annotation cp='[๐ŸŒŽ]' tts='globe showing americas'>americas; earth; globe; world</annotation>
+		<annotation cp='[๐ŸŒ]' tts='globe showing asia-australia'>asia; australia; earth; globe; world</annotation>
+		<annotation cp='[๐ŸŒ]' tts='globe with meridians'>earth; globe; meridians; world</annotation>
+		<annotation cp='[๐Ÿ—บ]' tts='world map'>map; world</annotation>
+		<annotation cp='[๐Ÿ”]' tts='snow-capped mountain'>cold; mountain; snow</annotation>
+		<annotation cp='[โ›ฐ]' tts='mountain'>mountain</annotation>
+		<annotation cp='[๐ŸŒ‹]' tts='volcano'>eruption; mountain; weather</annotation>
+		<annotation cp='[๐Ÿ—ป]' tts='mount fuji'>fuji; mountain</annotation>
+		<annotation cp='[๐Ÿ•]' tts='camping'>camping</annotation>
+		<annotation cp='[๐Ÿ–]' tts='beach with umbrella'>beach; umbrella</annotation>
+		<annotation cp='[๐Ÿœ]' tts='desert'>desert</annotation>
+		<annotation cp='[๐Ÿ]' tts='desert island'>desert; island</annotation>
+		<annotation cp='[๐Ÿž]' tts='national park'>park</annotation>
+		<annotation cp='[๐ŸŸ]' tts='stadium'>stadium</annotation>
+		<annotation cp='[๐Ÿ›]' tts='classical building'>building; classical</annotation>
+		<annotation cp='[๐Ÿ—]' tts='building construction'>building; construction</annotation>
+		<annotation cp='[๐Ÿ˜]' tts='house buildings'>building; house</annotation>
+		<annotation cp='[๐Ÿ™]' tts='cityscape'>building; city</annotation>
+		<annotation cp='[๐Ÿš]' tts='derelict house building'>building; derelict; house</annotation>
+		<annotation cp='[๐Ÿ ]' tts='house building'>building; home; house</annotation>
+		<annotation cp='[๐Ÿก]' tts='house with garden'>building; garden; home; house</annotation>
+		<annotation cp='[โ›ช]' tts='church'>building; christian; cross; religion</annotation>
+		<annotation cp='[๐Ÿ•‹]' tts='kaaba'>islam; muslim; religion</annotation>
+		<annotation cp='[๐Ÿ•Œ]' tts='mosque'>islam; muslim; religion</annotation>
+		<annotation cp='[๐Ÿ•]' tts='synagogue'>jew; jewish; religion; temple</annotation>
+		<annotation cp='[โ›ฉ]' tts='shinto shrine'>religion; shinto; shrine</annotation>
+		<annotation cp='[๐Ÿข]' tts='office building'>building</annotation>
+		<annotation cp='[๐Ÿฃ]' tts='japanese post office'>building; japanese; post</annotation>
+		<annotation cp='[๐Ÿค]' tts='post office'>building; european; post</annotation>
+		<annotation cp='[๐Ÿฅ]' tts='hospital'>building; doctor; medicine</annotation>
+		<annotation cp='[๐Ÿฆ]' tts='bank'>building</annotation>
+		<annotation cp='[๐Ÿจ]' tts='hotel'>building</annotation>
+		<annotation cp='[๐Ÿฉ]' tts='love hotel'>building; hotel; love</annotation>
+		<annotation cp='[๐Ÿช]' tts='convenience store'>building; convenience; store</annotation>
+		<annotation cp='[๐Ÿซ]' tts='school'>building</annotation>
+		<annotation cp='[๐Ÿฌ]' tts='department store'>building; department; store</annotation>
+		<annotation cp='[๐Ÿญ]' tts='factory'>building</annotation>
+		<annotation cp='[๐Ÿฏ]' tts='japanese castle'>building; castle; japanese</annotation>
+		<annotation cp='[๐Ÿฐ]' tts='castle'>building; european</annotation>
+		<annotation cp='[๐Ÿ’’]' tts='wedding'>chapel; romance</annotation>
+		<annotation cp='[๐Ÿ—ผ]' tts='tokyo tower'>tokyo; tower</annotation>
+		<annotation cp='[๐Ÿ—ฝ]' tts='statue of liberty'>liberty; statue</annotation>
+		<annotation cp='[๐Ÿ—พ]' tts='map of japan'>japan; map</annotation>
+		<annotation cp='[โ›ฒ]' tts='fountain'>fountain</annotation>
+		<annotation cp='[โ›บ]' tts='tent'>camping</annotation>
+		<annotation cp='[๐ŸŒ]' tts='foggy'>fog; weather</annotation>
+		<annotation cp='[๐ŸŒƒ]' tts='night with stars'>night; star; weather</annotation>
+		<annotation cp='[๐ŸŒ„]' tts='sunrise over mountains'>morning; mountain; sun; sunrise; weather</annotation>
+		<annotation cp='[๐ŸŒ…]' tts='sunrise'>morning; sun; weather</annotation>
+		<annotation cp='[๐ŸŒ†]' tts='cityscape at dusk'>building; city; dusk; evening; landscape; sun; sunset; weather</annotation>
+		<annotation cp='[๐ŸŒ‡]' tts='sunset'>building; dusk; sun; weather</annotation>
+		<annotation cp='[๐ŸŒ‰]' tts='bridge at night'>bridge; night; weather</annotation>
+		<annotation cp='[โ™จ]' tts='hot springs'>hot; hotsprings; springs; steaming</annotation>
+		<annotation cp='[๐ŸŒŒ]' tts='milky way'>space; weather</annotation>
+		<annotation cp='[๐ŸŽ ]' tts='carousel horse'>carousel; horse</annotation>
+		<annotation cp='[๐ŸŽก]' tts='ferris wheel'>amusement park; ferris; wheel</annotation>
+		<annotation cp='[๐ŸŽข]' tts='roller coaster'>amusement park; coaster; roller</annotation>
+		<annotation cp='[๐Ÿ’ˆ]' tts='barber pole'>barber; haircut; pole</annotation>
+		<annotation cp='[๐ŸŽช]' tts='circus tent'>circus; tent</annotation>
+		<annotation cp='[๐ŸŽญ]' tts='performing arts'>art; mask; performing; theater; theatre</annotation>
+		<annotation cp='[๐Ÿ–ผ]' tts='frame with picture'>art; frame; museum; painting; picture</annotation>
+		<annotation cp='[๐ŸŽจ]' tts='artist palette'>art; museum; painting; palette</annotation>
+		<annotation cp='[๐ŸŽฐ]' tts='slot machine'>game; slot</annotation>
+		<annotation cp='[๐Ÿš‚]' tts='locomotive'>engine; railway; steam; train; vehicle</annotation>
+		<annotation cp='[๐Ÿšƒ]' tts='railway car'>car; electric; railway; train; tram; trolleybus; vehicle</annotation>
+		<annotation cp='[๐Ÿš„]' tts='high-speed train'>railway; shinkansen; speed; train; vehicle</annotation>
+		<annotation cp='[๐Ÿš…]' tts='high-speed train with bullet nose'>bullet; railway; shinkansen; speed; train; vehicle</annotation>
+		<annotation cp='[๐Ÿš†]' tts='train'>railway; vehicle</annotation>
+		<annotation cp='[๐Ÿš‡]' tts='metro'>subway; vehicle</annotation>
+		<annotation cp='[๐Ÿšˆ]' tts='light rail'>railway; vehicle</annotation>
+		<annotation cp='[๐Ÿš‰]' tts='station'>railway; train; vehicle</annotation>
+		<annotation cp='[๐ŸšŠ]' tts='tram'>trolleybus; vehicle</annotation>
+		<annotation cp='[๐Ÿš]' tts='monorail'>vehicle</annotation>
+		<annotation cp='[๐Ÿšž]' tts='mountain railway'>car; mountain; railway; vehicle</annotation>
+		<annotation cp='[๐Ÿš‹]' tts='tram car'>car; tram; trolleybus; vehicle</annotation>
+		<annotation cp='[๐ŸšŒ]' tts='bus'>vehicle</annotation>
+		<annotation cp='[๐Ÿš]' tts='oncoming bus'>bus; oncoming; vehicle</annotation>
+		<annotation cp='[๐ŸšŽ]' tts='trolleybus'>bus; tram; trolley; vehicle</annotation>
+		<annotation cp='[๐Ÿš]' tts='bus stop'>bus; busstop; stop</annotation>
+		<annotation cp='[๐Ÿš]' tts='minibus'>bus; vehicle</annotation>
+		<annotation cp='[๐Ÿš‘]' tts='ambulance'>vehicle</annotation>
+		<annotation cp='[๐Ÿš’]' tts='fire engine'>engine; fire; truck; vehicle</annotation>
+		<annotation cp='[๐Ÿš“]' tts='police car'>car; patrol; police; vehicle</annotation>
+		<annotation cp='[๐Ÿš”]' tts='oncoming police car'>car; oncoming; police; vehicle</annotation>
+		<annotation cp='[๐Ÿš•]' tts='taxi'>vehicle</annotation>
+		<annotation cp='[๐Ÿš–]' tts='oncoming taxi'>oncoming; taxi; vehicle</annotation>
+		<annotation cp='[๐Ÿš—]' tts='automobile'>car; vehicle</annotation>
+		<annotation cp='[๐Ÿš˜]' tts='oncoming automobile'>automobile; car; oncoming; vehicle</annotation>
+		<annotation cp='[๐Ÿš™]' tts='recreational vehicle'>recreational; rv; vehicle</annotation>
+		<annotation cp='[๐Ÿšš]' tts='delivery truck'>delivery; truck; vehicle</annotation>
+		<annotation cp='[๐Ÿš›]' tts='articulated lorry'>lorry; semi; truck; vehicle</annotation>
+		<annotation cp='[๐Ÿšœ]' tts='tractor'>vehicle</annotation>
+		<annotation cp='[๐Ÿšฒ]' tts='bicycle'>bike; vehicle</annotation>
+		<annotation cp='[โ›ฝ]' tts='fuel pump'>fuel; fuelpump; gas; pump; station</annotation>
+		<annotation cp='[๐Ÿ›ฃ]' tts='motorway'>highway; road</annotation>
+		<annotation cp='[๐Ÿ›ค]' tts='railway track'>railway; train</annotation>
+		<annotation cp='[๐Ÿšจ]' tts='police carโ€™s light'>beacon; car; light; police; revolving; vehicle</annotation>
+		<annotation cp='[๐Ÿšฅ]' tts='horizontal traffic light'>light; signal; traffic</annotation>
+		<annotation cp='[๐Ÿšฆ]' tts='vertical traffic light'>light; signal; traffic</annotation>
+		<annotation cp='[๐Ÿšง]' tts='construction'>barrier</annotation>
+		<annotation cp='[โš“]' tts='anchor'>ship; tool</annotation>
+		<annotation cp='[โ›ต]' tts='sailboat'>boat; resort; sea; vehicle; yacht</annotation>
+		<annotation cp='[๐Ÿšฃ]' tts='rowboat'>boat; vehicle</annotation>
+		<annotation cp='[๐Ÿšค]' tts='speedboat'>boat; vehicle</annotation>
+		<annotation cp='[๐Ÿ›ณ]' tts='passenger ship'>passenger; ship; vehicle</annotation>
+		<annotation cp='[โ›ด]' tts='ferry'>boat</annotation>
+		<annotation cp='[๐Ÿ›ฅ]' tts='motor boat'>boat; motorboat; vehicle</annotation>
+		<annotation cp='[๐Ÿšข]' tts='ship'>vehicle</annotation>
+		<annotation cp='[โœˆ]' tts='airplane'>vehicle</annotation>
+		<annotation cp='[๐Ÿ›ฉ]' tts='small airplane'>airplane; vehicle</annotation>
+		<annotation cp='[๐Ÿ›ซ]' tts='airplane departure'>airplane; check-in; departure; departures; vehicle</annotation>
+		<annotation cp='[๐Ÿ›ฌ]' tts='airplane arrival'>airplane; arrivals; arriving; landing; vehicle</annotation>
+		<annotation cp='[๐Ÿ’บ]' tts='seat'>chair</annotation>
+		<annotation cp='[๐Ÿš]' tts='helicopter'>vehicle</annotation>
+		<annotation cp='[๐ŸšŸ]' tts='suspension railway'>railway; suspension; vehicle</annotation>
+		<annotation cp='[๐Ÿš ]' tts='mountain cableway'>cable; gondola; mountain; vehicle</annotation>
+		<annotation cp='[๐Ÿšก]' tts='aerial tramway'>aerial; cable; car; gondola; ropeway; tramway; vehicle</annotation>
+		<annotation cp='[๐Ÿš€]' tts='rocket'>space; vehicle</annotation>
+		<annotation cp='[๐Ÿ›ฐ]' tts='satellite'>space; vehicle</annotation>
+		<annotation cp='[๐Ÿ›Ž]' tts='bellhop bell'>bell; bellhop; hotel</annotation>
+		<annotation cp='[๐Ÿšช]' tts='door'>door</annotation>
+		<annotation cp='[๐Ÿ›Œ]' tts='person in bed'>hotel; sleep</annotation>
+		<annotation cp='[๐Ÿ›]' tts='bed'>hotel; sleep</annotation>
+		<annotation cp='[๐Ÿ›‹]' tts='couch and lamp'>couch; hotel; lamp</annotation>
+		<annotation cp='[๐Ÿšฝ]' tts='toilet'>toilet</annotation>
+		<annotation cp='[๐Ÿšฟ]' tts='shower'>water</annotation>
+		<annotation cp='[๐Ÿ›€]' tts='person taking bath'>bathtub; bath</annotation>
+		<annotation cp='[๐Ÿ›]' tts='bathtub'>bath</annotation>
+		<annotation cp='[โŒ›]' tts='hourglass'>sand; timer</annotation>
+		<annotation cp='[โณ]' tts='hourglass with flowing sand'>hourglass; sand; timer</annotation>
+		<annotation cp='[โŒš]' tts='watch'>clock</annotation>
+		<annotation cp='[โฐ]' tts='alarm clock'>alarm; clock</annotation>
+		<annotation cp='[โฑ]' tts='stopwatch'>clock</annotation>
+		<annotation cp='[โฒ]' tts='timer clock'>clock; timer</annotation>
+		<annotation cp='[๐Ÿ•ฐ]' tts='mantelpiece clock'>clock</annotation>
+		<annotation cp='[๐Ÿ•›]' tts='twelve oโ€™clock'>00; 12; 12:00; clock; oโ€™clock; twelve</annotation>
+		<annotation cp='[๐Ÿ•ง]' tts='twelve-thirty'>12; 12:30; 30; clock; thirty; twelve</annotation>
+		<annotation cp='[๐Ÿ•]' tts='one oโ€™clock'>00; 1; 1:00; clock; oโ€™clock; one</annotation>
+		<annotation cp='[๐Ÿ•œ]' tts='one-thirty'>1; 1:30; 30; clock; one; thirty</annotation>
+		<annotation cp='[๐Ÿ•‘]' tts='two oโ€™clock'>00; 2; 2:00; clock; oโ€™clock; two</annotation>
+		<annotation cp='[๐Ÿ•]' tts='two-thirty'>2; 2:30; 30; clock; thirty; two</annotation>
+		<annotation cp='[๐Ÿ•’]' tts='three oโ€™clock'>00; 3; 3:00; clock; oโ€™clock; three</annotation>
+		<annotation cp='[๐Ÿ•ž]' tts='three-thirty'>3; 3:30; 30; clock; thirty; three</annotation>
+		<annotation cp='[๐Ÿ•“]' tts='four oโ€™clock'>00; 4; 4:00; clock; four; oโ€™clock</annotation>
+		<annotation cp='[๐Ÿ•Ÿ]' tts='four-thirty'>30; 4; 4:30; clock; four; thirty</annotation>
+		<annotation cp='[๐Ÿ•”]' tts='five oโ€™clock'>00; 5; 5:00; clock; five; oโ€™clock</annotation>
+		<annotation cp='[๐Ÿ• ]' tts='five-thirty'>30; 5; 5:30; clock; five; thirty</annotation>
+		<annotation cp='[๐Ÿ••]' tts='six oโ€™clock'>00; 6; 6:00; clock; oโ€™clock; six</annotation>
+		<annotation cp='[๐Ÿ•ก]' tts='six-thirty'>30; 6; 6:30; clock; six; thirty</annotation>
+		<annotation cp='[๐Ÿ•–]' tts='seven oโ€™clock'>00; 7; 7:00; clock; oโ€™clock; seven</annotation>
+		<annotation cp='[๐Ÿ•ข]' tts='seven-thirty'>30; 7; 7:30; clock; seven; thirty</annotation>
+		<annotation cp='[๐Ÿ•—]' tts='eight oโ€™clock'>00; 8; 8:00; clock; eight; oโ€™clock</annotation>
+		<annotation cp='[๐Ÿ•ฃ]' tts='eight-thirty'>30; 8; 8:30; clock; eight; thirty</annotation>
+		<annotation cp='[๐Ÿ•˜]' tts='nine oโ€™clock'>00; 9; 9:00; clock; nine; oโ€™clock</annotation>
+		<annotation cp='[๐Ÿ•ค]' tts='nine-thirty'>30; 9; 9:30; clock; nine; thirty</annotation>
+		<annotation cp='[๐Ÿ•™]' tts='ten oโ€™clock'>00; 10; 10:00; clock; oโ€™clock; ten</annotation>
+		<annotation cp='[๐Ÿ•ฅ]' tts='ten-thirty'>10; 10:30; 30; clock; ten; thirty</annotation>
+		<annotation cp='[๐Ÿ•š]' tts='eleven oโ€™clock'>00; 11; 11:00; clock; eleven; oโ€™clock</annotation>
+		<annotation cp='[๐Ÿ•ฆ]' tts='eleven-thirty'>11; 11:30; 30; clock; eleven; thirty</annotation>
+		<annotation cp='[๐ŸŒ‘]' tts='new moon'>dark; moon; space; weather</annotation>
+		<annotation cp='[๐ŸŒ’]' tts='waxing crescent moon'>crescent; moon; space; waxing; weather</annotation>
+		<annotation cp='[๐ŸŒ“]' tts='first quarter moon'>moon; quarter; space; weather</annotation>
+		<annotation cp='[๐ŸŒ”]' tts='waxing gibbous moon'>gibbous; moon; space; waxing; weather</annotation>
+		<annotation cp='[๐ŸŒ•]' tts='full moon'>full; moon; space; weather</annotation>
+		<annotation cp='[๐ŸŒ–]' tts='waning gibbous moon'>gibbous; moon; space; waning; weather</annotation>
+		<annotation cp='[๐ŸŒ—]' tts='last quarter moon'>moon; quarter; space; weather</annotation>
+		<annotation cp='[๐ŸŒ˜]' tts='waning crescent moon'>crescent; moon; space; waning; weather</annotation>
+		<annotation cp='[๐ŸŒ™]' tts='crescent moon'>crescent; moon; space; weather</annotation>
+		<annotation cp='[๐ŸŒš]' tts='new moon face'>face; moon; space; weather</annotation>
+		<annotation cp='[๐ŸŒ›]' tts='first quarter moon with face'>face; moon; quarter; space; weather</annotation>
+		<annotation cp='[๐ŸŒœ]' tts='last quarter moon with face'>face; moon; quarter; space; weather</annotation>
+		<annotation cp='[๐ŸŒก]' tts='thermometer'>weather</annotation>
+		<annotation cp='[โ˜€]' tts='sun'>bright; rays; space; sunny; weather</annotation>
+		<annotation cp='[๐ŸŒ]' tts='full moon with face'>bright; face; full; moon; space; weather</annotation>
+		<annotation cp='[๐ŸŒž]' tts='sun with face'>bright; face; space; sun; weather</annotation>
+		<annotation cp='[โญ]' tts='white medium star'>star</annotation>
+		<annotation cp='[๐ŸŒŸ]' tts='glowing star'>glittery; glow; shining; sparkle; star</annotation>
+		<annotation cp='[๐ŸŒ ]' tts='shooting star'>falling; shooting; space; star</annotation>
+		<annotation cp='[โ˜]' tts='cloud'>weather</annotation>
+		<annotation cp='[โ›…]' tts='sun behind cloud'>cloud; sun; weather</annotation>
+		<annotation cp='[โ›ˆ]' tts='cloud with lightning and rain'>cloud; rain; thunder; weather</annotation>
+		<annotation cp='[๐ŸŒค]' tts='sun behind small cloud'>cloud; sun; weather</annotation>
+		<annotation cp='[๐ŸŒฅ]' tts='sun behind large cloud'>cloud; sun; weather</annotation>
+		<annotation cp='[๐ŸŒฆ]' tts='sun behind cloud with rain'>cloud; rain; sun; weather</annotation>
+		<annotation cp='[๐ŸŒง]' tts='cloud with rain'>cloud; rain; weather</annotation>
+		<annotation cp='[๐ŸŒจ]' tts='cloud with snow'>cloud; cold; snow; weather</annotation>
+		<annotation cp='[๐ŸŒฉ]' tts='cloud with lightning'>cloud; lightning; weather</annotation>
+		<annotation cp='[๐ŸŒช]' tts='tornado'>cloud; weather; whirlwind</annotation>
+		<annotation cp='[๐ŸŒซ]' tts='fog'>cloud; weather</annotation>
+		<annotation cp='[๐ŸŒฌ]' tts='wind face'>blow; cloud; face; weather; wind</annotation>
+		<annotation cp='[๐ŸŒ€]' tts='cyclone'>dizzy; twister; typhoon; weather</annotation>
+		<annotation cp='[๐ŸŒˆ]' tts='rainbow'>rain; weather</annotation>
+		<annotation cp='[๐ŸŒ‚]' tts='closed umbrella'>clothing; rain; umbrella; weather</annotation>
+		<annotation cp='[โ˜‚]' tts='umbrella'>clothing; rain; weather</annotation>
+		<annotation cp='[โ˜”]' tts='umbrella with rain drops'>clothing; drop; rain; umbrella; weather</annotation>
+		<annotation cp='[โ›ฑ]' tts='umbrella on ground'>rain; sun; umbrella; weather</annotation>
+		<annotation cp='[โšก]' tts='high voltage'>danger; electric; electricity; lightning; voltage; zap</annotation>
+		<annotation cp='[โ„]' tts='snowflake'>cold; snow; weather</annotation>
+		<annotation cp='[โ˜ƒ]' tts='snowman'>cold; snow; weather</annotation>
+		<annotation cp='[โ›„]' tts='snowman without snow'>cold; snow; snowman; weather</annotation>
+		<annotation cp='[โ˜„]' tts='comet'>space</annotation>
+		<annotation cp='[๐Ÿ”ฅ]' tts='fire'>flame; tool</annotation>
+		<annotation cp='[๐Ÿ’ง]' tts='droplet'>cold; comic; drop; sweat; weather</annotation>
+		<annotation cp='[๐ŸŒŠ]' tts='water wave'>ocean; water; wave; weather</annotation>
+		<annotation cp='[๐ŸŽƒ]' tts='jack-o-lantern'>celebration; halloween; jack; lantern</annotation>
+		<annotation cp='[๐ŸŽ„]' tts='christmas tree'>celebration; christmas; tree</annotation>
+		<annotation cp='[๐ŸŽ†]' tts='fireworks'>celebration</annotation>
+		<annotation cp='[๐ŸŽ‡]' tts='sparkler'>celebration; fireworks; sparkle</annotation>
+		<annotation cp='[โœจ]' tts='sparkles'>sparkle; star</annotation>
+		<annotation cp='[๐ŸŽˆ]' tts='balloon'>celebration</annotation>
+		<annotation cp='[๐ŸŽ‰]' tts='party popper'>celebration; party; popper; tada</annotation>
+		<annotation cp='[๐ŸŽŠ]' tts='confetti ball'>ball; celebration; confetti</annotation>
+		<annotation cp='[๐ŸŽ‹]' tts='tanabata tree'>banner; celebration; japanese; tree</annotation>
+		<annotation cp='[๐ŸŽŒ]' tts='crossed flags'>celebration; cross; crossed; japanese</annotation>
+		<annotation cp='[๐ŸŽ]' tts='pine decoration'>bamboo; celebration; japanese; pine; plant</annotation>
+		<annotation cp='[๐ŸŽŽ]' tts='japanese dolls'>celebration; doll; festival; japanese</annotation>
+		<annotation cp='[๐ŸŽ]' tts='carp streamer'>carp; celebration; streamer</annotation>
+		<annotation cp='[๐ŸŽ]' tts='wind chime'>bell; celebration; chime; wind</annotation>
+		<annotation cp='[๐ŸŽ‘]' tts='moon ceremony'>celebration; ceremony; moon</annotation>
+		<annotation cp='[๐ŸŽ€]' tts='ribbon'>celebration</annotation>
+		<annotation cp='[๐ŸŽ]' tts='wrapped present'>box; celebration; gift; present; wrapped</annotation>
+		<annotation cp='[๐ŸŽ–]' tts='military medal'>celebration; medal; military</annotation>
+		<annotation cp='[๐ŸŽ—]' tts='reminder ribbon'>celebration; reminder; ribbon</annotation>
+		<annotation cp='[๐ŸŽž]' tts='film frames'>cinema; film; frames; movie</annotation>
+		<annotation cp='[๐ŸŽŸ]' tts='admission tickets'>admission; ticket</annotation>
+		<annotation cp='[๐ŸŽซ]' tts='ticket'>admission</annotation>
+		<annotation cp='[๐Ÿท]' tts='label'>label</annotation>
+		<annotation cp='[โšฝ]' tts='soccer ball'>ball; soccer</annotation>
+		<annotation cp='[โšพ]' tts='baseball'>ball</annotation>
+		<annotation cp='[๐Ÿ€]' tts='basketball'>ball; hoop</annotation>
+		<annotation cp='[๐Ÿˆ]' tts='american football'>american; ball; football</annotation>
+		<annotation cp='[๐Ÿ‰]' tts='rugby football'>ball; football; rugby</annotation>
+		<annotation cp='[๐ŸŽพ]' tts='tennis'>ball; racquet</annotation>
+		<annotation cp='[๐ŸŽฑ]' tts='billiards'>8; 8 ball; ball; billiard; eight; game</annotation>
+		<annotation cp='[๐ŸŽณ]' tts='bowling'>ball; game</annotation>
+		<annotation cp='[โ›ณ]' tts='flag in hole'>golf; hole</annotation>
+		<annotation cp='[๐ŸŒ]' tts='golfer'>ball; golf</annotation>
+		<annotation cp='[โ›ธ]' tts='ice skate'>ice; skate</annotation>
+		<annotation cp='[๐ŸŽฃ]' tts='fishing pole'>fish; pole</annotation>
+		<annotation cp='[๐ŸŽฝ]' tts='running shirt'>running; sash; shirt</annotation>
+		<annotation cp='[๐ŸŽฟ]' tts='skis'>ski; snow</annotation>
+		<annotation cp='[โ›ท]' tts='skier'>ski; snow</annotation>
+		<annotation cp='[๐Ÿ‚]' tts='snowboarder'>ski; snow; snowboard</annotation>
+		<annotation cp='[๐Ÿ„]' tts='surfer'>surfing</annotation>
+		<annotation cp='[๐Ÿ‡]' tts='horse racing'>horse; jockey; racehorse; racing</annotation>
+		<annotation cp='[๐ŸŠ]' tts='swimmer'>swim</annotation>
+		<annotation cp='[โ›น]' tts='person with ball'>ball</annotation>
+		<annotation cp='[๐Ÿ‹]' tts='weight lifter'>lifter; weight</annotation>
+		<annotation cp='[๐Ÿšด]' tts='bicyclist'>bicycle; bike; cyclist</annotation>
+		<annotation cp='[๐Ÿšต]' tts='mountain biker'>bicycle; bicyclist; bike; cyclist; mountain</annotation>
+		<annotation cp='[๐ŸŽ]' tts='racing car'>car; racing</annotation>
+		<annotation cp='[๐Ÿ]' tts='motorcycle'>racing</annotation>
+		<annotation cp='[๐Ÿ…]' tts='sports medal'>medal</annotation>
+		<annotation cp='[๐Ÿ†]' tts='trophy'>prize</annotation>
+		<annotation cp='[๐Ÿ]' tts='cricket'>ball; bat; game</annotation>
+		<annotation cp='[๐Ÿ]' tts='volleyball'>ball; game</annotation>
+		<annotation cp='[๐Ÿ‘]' tts='field hockey'>ball; field; game; hockey; stick</annotation>
+		<annotation cp='[๐Ÿ’]' tts='ice hockey stick and puck'>game; hockey; ice; puck; stick</annotation>
+		<annotation cp='[๐Ÿ“]' tts='ping pong'>ball; bat; game; paddle; table tennis</annotation>
+		<annotation cp='[๐Ÿธ]' tts='badminton'>birdie; game; racquet; shuttlecock</annotation>
+		<annotation cp='[๐ŸŽฏ]' tts='direct hit'>bull; bullseye; dart; eye; game; hit; target</annotation>
+		<annotation cp='[๐ŸŽฎ]' tts='video game'>controller; game</annotation>
+		<annotation cp='[๐Ÿ•น]' tts='joystick'>game; video game</annotation>
+		<annotation cp='[๐ŸŽฒ]' tts='game die'>dice; die; game</annotation>
+		<annotation cp='[โ™ ]' tts='spade suit'>card; game; spade; suit</annotation>
+		<annotation cp='[โ™ฅ]' tts='heart suit'>card; game; heart; hearts; suit</annotation>
+		<annotation cp='[โ™ฆ]' tts='diamond suit'>card; diamond; diamonds; game; suit</annotation>
+		<annotation cp='[โ™ฃ]' tts='club suit'>card; club; clubs; game; suit</annotation>
+		<annotation cp='[๐Ÿƒ]' tts='joker'>card; game; playing</annotation>
+		<annotation cp='[๐Ÿ€„]' tts='mahjong red dragon'>game; mahjong; red</annotation>
+		<annotation cp='[๐ŸŽด]' tts='flower playing cards'>card; flower; game; japanese; playing</annotation>
+		<annotation cp='[๐Ÿ”‡]' tts='speaker off'>mute; quiet; silent; speaker; volume</annotation>
+		<annotation cp='[๐Ÿ”ˆ]' tts='speaker'>volume</annotation>
+		<annotation cp='[๐Ÿ”‰]' tts='speaker on'>low; speaker; volume; wave</annotation>
+		<annotation cp='[๐Ÿ”Š]' tts='speaker loud'>3; high; loud; speaker; three; volume</annotation>
+		<annotation cp='[๐Ÿ“ข]' tts='loudspeaker'>loud; public address</annotation>
+		<annotation cp='[๐Ÿ“ฃ]' tts='megaphone'>cheering</annotation>
+		<annotation cp='[๐Ÿ“ฏ]' tts='postal horn'>horn; post; postal</annotation>
+		<annotation cp='[๐Ÿ””]' tts='bell'>bell</annotation>
+		<annotation cp='[๐Ÿ”•]' tts='bell with slash'>bell; forbidden; mute; no; not; prohibited; quiet; silent</annotation>
+		<annotation cp='[๐ŸŽผ]' tts='musical score'>music; score</annotation>
+		<annotation cp='[๐ŸŽต]' tts='musical note'>music; note</annotation>
+		<annotation cp='[๐ŸŽถ]' tts='musical notes'>music; note; notes</annotation>
+		<annotation cp='[๐ŸŽ™]' tts='studio microphone'>mic; microphone; music; studio</annotation>
+		<annotation cp='[๐ŸŽš]' tts='level slider'>level; music; slider</annotation>
+		<annotation cp='[๐ŸŽ›]' tts='control knobs'>control; knobs; music</annotation>
+		<annotation cp='[๐ŸŽค]' tts='microphone'>karaoke; mic</annotation>
+		<annotation cp='[๐ŸŽง]' tts='headphone'>earbud</annotation>
+		<annotation cp='[๐ŸŽท]' tts='saxophone'>instrument; music; sax</annotation>
+		<annotation cp='[๐ŸŽธ]' tts='guitar'>instrument; music</annotation>
+		<annotation cp='[๐ŸŽน]' tts='musical keyboard'>instrument; keyboard; music; piano</annotation>
+		<annotation cp='[๐ŸŽบ]' tts='trumpet'>instrument; music</annotation>
+		<annotation cp='[๐ŸŽป]' tts='violin'>instrument; music</annotation>
+		<annotation cp='[๐Ÿ“ป]' tts='radio'>video</annotation>
+		<annotation cp='[๐Ÿ“ฑ]' tts='mobile phone'>cell; mobile; phone; telephone</annotation>
+		<annotation cp='[๐Ÿ“ฒ]' tts='mobile phone with arrow'>arrow; call; cell; mobile; phone; receive; telephone</annotation>
+		<annotation cp='[โ˜Ž]' tts='telephone'>phone</annotation>
+		<annotation cp='[๐Ÿ“ž]' tts='telephone receiver'>phone; receiver; telephone</annotation>
+		<annotation cp='[๐Ÿ“Ÿ]' tts='pager'>pager</annotation>
+		<annotation cp='[๐Ÿ“ ]' tts='fax machine'>fax</annotation>
+		<annotation cp='[๐Ÿ”‹]' tts='battery'>battery</annotation>
+		<annotation cp='[๐Ÿ”Œ]' tts='electric plug'>electric; electricity; plug</annotation>
+		<annotation cp='[๐Ÿ’ป]' tts='laptop computer'>computer; pc; personal</annotation>
+		<annotation cp='[๐Ÿ–ฅ]' tts='desktop computer'>computer; desktop</annotation>
+		<annotation cp='[๐Ÿ–จ]' tts='printer'>computer</annotation>
+		<annotation cp='[โŒจ]' tts='keyboard'>computer</annotation>
+		<annotation cp='[๐Ÿ–ฑ]' tts='computer mouse'>3; button; computer; mouse; three</annotation>
+		<annotation cp='[๐Ÿ–ฒ]' tts='trackball'>computer</annotation>
+		<annotation cp='[๐Ÿ’ฝ]' tts='minidisc'>computer; disk; minidisk; optical</annotation>
+		<annotation cp='[๐Ÿ’พ]' tts='floppy disk'>computer; disk; floppy</annotation>
+		<annotation cp='[๐Ÿ’ฟ]' tts='optical disc'>dvd; blu-ray; cd; computer; disk; optical</annotation>
+		<annotation cp='[๐Ÿ“€]' tts='dvd'>blu-ray; cd; computer; disk; optical</annotation>
+		<annotation cp='[๐ŸŽฅ]' tts='movie camera'>camera; cinema; movie</annotation>
+		<annotation cp='[๐ŸŽฌ]' tts='clapper board'>clapper; movie</annotation>
+		<annotation cp='[๐Ÿ“ฝ]' tts='film projector'>cinema; film; movie; projector; video</annotation>
+		<annotation cp='[๐Ÿ“บ]' tts='television'>tv; video</annotation>
+		<annotation cp='[๐Ÿ“ท]' tts='camera'>video</annotation>
+		<annotation cp='[๐Ÿ“ธ]' tts='camera with flash'>camera; flash; video</annotation>
+		<annotation cp='[๐Ÿ“น]' tts='video camera'>camera; video</annotation>
+		<annotation cp='[๐Ÿ“ผ]' tts='videocassette'>tape; vhs; video</annotation>
+		<annotation cp='[๐Ÿ”]' tts='left-pointing magnifying glass'>glass; magnifying; search; tool</annotation>
+		<annotation cp='[๐Ÿ”Ž]' tts='right-pointing magnifying glass'>glass; magnifying; search; tool</annotation>
+		<annotation cp='[๐Ÿ”ฌ]' tts='microscope'>tool</annotation>
+		<annotation cp='[๐Ÿ”ญ]' tts='telescope'>tool</annotation>
+		<annotation cp='[๐Ÿ“ก]' tts='satellite antenna'>antenna; dish; satellite</annotation>
+		<annotation cp='[๐Ÿ•ฏ]' tts='candle'>light</annotation>
+		<annotation cp='[๐Ÿ’ก]' tts='light bulb'>bulb; comic; electric; idea; light</annotation>
+		<annotation cp='[๐Ÿ”ฆ]' tts='flashlight'>electric; light; tool; torch</annotation>
+		<annotation cp='[๐Ÿฎ]' tts='red paper lantern'>bar; japanese; lantern; light; red</annotation>
+		<annotation cp='[๐Ÿ“”]' tts='notebook with decorative cover'>book; cover; decorated; notebook</annotation>
+		<annotation cp='[๐Ÿ“•]' tts='closed book'>book; closed</annotation>
+		<annotation cp='[๐Ÿ“–]' tts='open book'>book; open</annotation>
+		<annotation cp='[๐Ÿ“—]' tts='green book'>book; green</annotation>
+		<annotation cp='[๐Ÿ“˜]' tts='blue book'>blue; book</annotation>
+		<annotation cp='[๐Ÿ“™]' tts='orange book'>book; orange</annotation>
+		<annotation cp='[๐Ÿ“š]' tts='books'>book</annotation>
+		<annotation cp='[๐Ÿ““]' tts='notebook'>notebook</annotation>
+		<annotation cp='[๐Ÿ“’]' tts='ledger'>notebook</annotation>
+		<annotation cp='[๐Ÿ“ƒ]' tts='page with curl'>curl; document; page</annotation>
+		<annotation cp='[๐Ÿ“œ]' tts='scroll'>paper</annotation>
+		<annotation cp='[๐Ÿ“„]' tts='page facing up'>document; page</annotation>
+		<annotation cp='[๐Ÿ“ฐ]' tts='newspaper'>news; paper</annotation>
+		<annotation cp='[๐Ÿ—ž]' tts='rolled-up newspaper'>news; newspaper; paper; rolled</annotation>
+		<annotation cp='[๐Ÿ“‘]' tts='bookmark tabs'>bookmark; mark; marker; tabs</annotation>
+		<annotation cp='[๐Ÿ”–]' tts='bookmark'>mark</annotation>
+		<annotation cp='[๐Ÿ’ฐ]' tts='money bag'>bag; dollar; money; moneybag</annotation>
+		<annotation cp='[๐Ÿ’ด]' tts='yen banknote'>bank; banknote; bill; currency; money; note; yen</annotation>
+		<annotation cp='[๐Ÿ’ต]' tts='dollar banknote'>bank; banknote; bill; currency; dollar; money; note</annotation>
+		<annotation cp='[๐Ÿ’ถ]' tts='euro banknote'>bank; banknote; bill; currency; euro; money; note</annotation>
+		<annotation cp='[๐Ÿ’ท]' tts='pound banknote'>bank; banknote; bill; currency; money; note; pound</annotation>
+		<annotation cp='[๐Ÿ’ธ]' tts='money with wings'>bank; banknote; bill; dollar; fly; money; note; wings</annotation>
+		<annotation cp='[๐Ÿ’ณ]' tts='credit card'>bank; card; credit; money</annotation>
+		<annotation cp='[๐Ÿ’น]' tts='chart increasing with yen'>bank; chart; currency; graph; growth; market; money; rise; trend; upward; yen</annotation>
+		<annotation cp='[โœ‰]' tts='envelope'>e-mail; email</annotation>
+		<annotation cp='[๐Ÿ“ง]' tts='e-mail'>email; letter; mail</annotation>
+		<annotation cp='[๐Ÿ“จ]' tts='incoming envelope'>e-mail; email; envelope; incoming; letter; mail; receive</annotation>
+		<annotation cp='[๐Ÿ“ฉ]' tts='envelope with arrow'>arrow; down; e-mail; email; envelope; letter; mail; outgoing; sent</annotation>
+		<annotation cp='[๐Ÿ“ค]' tts='outbox tray'>box; letter; mail; outbox; sent; tray</annotation>
+		<annotation cp='[๐Ÿ“ฅ]' tts='inbox tray'>box; inbox; letter; mail; receive; tray</annotation>
+		<annotation cp='[๐Ÿ“ฆ]' tts='package'>box; parcel</annotation>
+		<annotation cp='[๐Ÿ“ซ]' tts='closed mailbox with raised flag'>closed; mail; mailbox; postbox</annotation>
+		<annotation cp='[๐Ÿ“ช]' tts='closed mailbox with lowered flag'>closed; lowered; mail; mailbox; postbox</annotation>
+		<annotation cp='[๐Ÿ“ฌ]' tts='open mailbox with raised flag'>mail; mailbox; open; postbox</annotation>
+		<annotation cp='[๐Ÿ“ญ]' tts='open mailbox with lowered flag'>lowered; mail; mailbox; open; postbox</annotation>
+		<annotation cp='[๐Ÿ“ฎ]' tts='postbox'>mail; mailbox</annotation>
+		<annotation cp='[๐Ÿ—ณ]' tts='ballot box with ballot'>ballot; box</annotation>
+		<annotation cp='[โœ]' tts='pencil'>pencil</annotation>
+		<annotation cp='[โœ’]' tts='black nib'>nib; pen</annotation>
+		<annotation cp='[๐Ÿ–‹]' tts='fountain pen'>fountain; pen</annotation>
+		<annotation cp='[๐Ÿ–Š]' tts='pen'>ballpoint</annotation>
+		<annotation cp='[๐Ÿ–Œ]' tts='paintbrush'>painting</annotation>
+		<annotation cp='[๐Ÿ–]' tts='crayon'>crayon</annotation>
+		<annotation cp='[๐Ÿ“]' tts='memo'>pencil</annotation>
+		<annotation cp='[๐Ÿ’ผ]' tts='briefcase'>briefcase</annotation>
+		<annotation cp='[๐Ÿ“]' tts='file folder'>file; folder</annotation>
+		<annotation cp='[๐Ÿ“‚]' tts='open file folder'>file; folder; open</annotation>
+		<annotation cp='[๐Ÿ—‚]' tts='card index dividers'>card; dividers; index</annotation>
+		<annotation cp='[๐Ÿ“…]' tts='calendar'>date</annotation>
+		<annotation cp='[๐Ÿ“†]' tts='tear-off calendar'>calendar</annotation>
+		<annotation cp='[๐Ÿ—’]' tts='spiral notepad'>note; pad; spiral</annotation>
+		<annotation cp='[๐Ÿ—“]' tts='spiral calendar'>calendar; pad; spiral</annotation>
+		<annotation cp='[๐Ÿ“‡]' tts='card index'>card; index; rolodex</annotation>
+		<annotation cp='[๐Ÿ“ˆ]' tts='chart increasing'>chart; graph; growth; trend; upward</annotation>
+		<annotation cp='[๐Ÿ“‰]' tts='chart decreasing'>chart; down; graph; trend</annotation>
+		<annotation cp='[๐Ÿ“Š]' tts='bar chart'>bar; chart; graph</annotation>
+		<annotation cp='[๐Ÿ“‹]' tts='clipboard'>clipboard</annotation>
+		<annotation cp='[๐Ÿ“Œ]' tts='pushpin'>pin</annotation>
+		<annotation cp='[๐Ÿ“]' tts='round pushpin'>pin; pushpin</annotation>
+		<annotation cp='[๐Ÿ“Ž]' tts='paperclip'>paperclip</annotation>
+		<annotation cp='[๐Ÿ–‡]' tts='linked paperclips'>link; paperclip</annotation>
+		<annotation cp='[๐Ÿ“]' tts='straight ruler'>ruler; straight edge</annotation>
+		<annotation cp='[๐Ÿ“]' tts='triangular ruler'>ruler; set; triangle</annotation>
+		<annotation cp='[โœ‚]' tts='scissors'>tool</annotation>
+		<annotation cp='[๐Ÿ—ƒ]' tts='card file box'>box; card; file</annotation>
+		<annotation cp='[๐Ÿ—„]' tts='file cabinet'>cabinet; file</annotation>
+		<annotation cp='[๐Ÿ—‘]' tts='wastebasket'>wastebasket</annotation>
+		<annotation cp='[๐Ÿ”’]' tts='lock'>closed</annotation>
+		<annotation cp='[๐Ÿ”“]' tts='open lock'>lock; open; unlock</annotation>
+		<annotation cp='[๐Ÿ”]' tts='lock with pen'>ink; lock; nib; pen; privacy</annotation>
+		<annotation cp='[๐Ÿ”]' tts='closed lock with key'>closed; key; lock; secure</annotation>
+		<annotation cp='[๐Ÿ”‘]' tts='key'>lock; password</annotation>
+		<annotation cp='[๐Ÿ—]' tts='old key'>clue; key; lock; old</annotation>
+		<annotation cp='[๐Ÿ”จ]' tts='hammer'>tool</annotation>
+		<annotation cp='[โ›]' tts='pick'>mining; tool</annotation>
+		<annotation cp='[โš’]' tts='hammer and pick'>hammer; pick; tool</annotation>
+		<annotation cp='[๐Ÿ› ]' tts='hammer and wrench'>hammer; tool; wrench</annotation>
+		<annotation cp='[๐Ÿ”ง]' tts='wrench'>tool</annotation>
+		<annotation cp='[๐Ÿ”ฉ]' tts='nut and bolt'>bolt; nut; tool</annotation>
+		<annotation cp='[โš™]' tts='gear'>tool</annotation>
+		<annotation cp='[๐Ÿ—œ]' tts='compression'>tool; vice</annotation>
+		<annotation cp='[โš—]' tts='alembic'>chemistry; tool</annotation>
+		<annotation cp='[โš–]' tts='balance scale'>balance; justice; libra; scales; tool; weight; zodiac</annotation>
+		<annotation cp='[๐Ÿ”—]' tts='link'>link</annotation>
+		<annotation cp='[โ›“]' tts='chains'>chain</annotation>
+		<annotation cp='[๐Ÿ’‰]' tts='syringe'>doctor; medicine; needle; shot; sick; tool</annotation>
+		<annotation cp='[๐Ÿ’Š]' tts='pill'>doctor; medicine; sick</annotation>
+		<annotation cp='[๐Ÿ—ก]' tts='dagger'>knife; weapon</annotation>
+		<annotation cp='[๐Ÿ”ช]' tts='kitchen knife'>cooking; hocho; knife; tool; weapon</annotation>
+		<annotation cp='[โš”]' tts='crossed swords'>crossed; swords; weapon</annotation>
+		<annotation cp='[๐Ÿ”ซ]' tts='pistol'>gun; handgun; revolver; tool; weapon</annotation>
+		<annotation cp='[๐Ÿ›ก]' tts='shield'>weapon</annotation>
+		<annotation cp='[๐Ÿน]' tts='bow and arrow'>archer; arrow; bow; sagittarius; tool; weapon; zodiac</annotation>
+		<annotation cp='[๐Ÿ]' tts='chequered flag'>checkered; chequered; racing</annotation>
+		<annotation cp='[๐Ÿณ]' tts='waving white flag'>waving</annotation>
+		<annotation cp='[๐Ÿด]' tts='waving black flag'>waving</annotation>
+		<annotation cp='[๐Ÿšฉ]' tts='triangular flag'>post</annotation>
+		<annotation cp='[๐Ÿšฌ]' tts='smoking'>smoking</annotation>
+		<annotation cp='[โšฐ]' tts='coffin'>death</annotation>
+		<annotation cp='[โšฑ]' tts='funeral urn'>death; funeral; urn</annotation>
+		<annotation cp='[๐Ÿ—ฟ]' tts='moai'>face; moyai; statue</annotation>
+		<annotation cp='[๐Ÿ›ข]' tts='oil drum'>drum; oil</annotation>
+		<annotation cp='[๐Ÿ”ฎ]' tts='crystal ball'>ball; crystal; fairy tale; fantasy; fortune; tool</annotation>
+		<annotation cp='[๐Ÿง]' tts='ATM sign'>atm; automated; bank; teller</annotation>
+		<annotation cp='[๐Ÿšฎ]' tts='litter in bin sign'>litter; litterbox</annotation>
+		<annotation cp='[๐Ÿšฐ]' tts='potable water'>drink; potable; water</annotation>
+		<annotation cp='[โ™ฟ]' tts='wheelchair'>access</annotation>
+		<annotation cp='[๐Ÿšน]' tts='menโ€™s room'>lavatory; man; restroom; wc</annotation>
+		<annotation cp='[๐Ÿšบ]' tts='womenโ€™s room'>lavatory; restroom; wc; woman</annotation>
+		<annotation cp='[๐Ÿšป]' tts='restroom'>lavatory; wc</annotation>
+		<annotation cp='[๐Ÿšผ]' tts='baby symbol'>baby; changing</annotation>
+		<annotation cp='[๐Ÿšพ]' tts='water closet'>closet; lavatory; restroom; water; wc</annotation>
+		<annotation cp='[๐Ÿ›‚]' tts='passport control'>control; passport</annotation>
+		<annotation cp='[๐Ÿ›ƒ]' tts='customs'>customs</annotation>
+		<annotation cp='[๐Ÿ›„]' tts='baggage claim'>baggage; claim</annotation>
+		<annotation cp='[๐Ÿ›…]' tts='left luggage'>baggage; locker; luggage</annotation>
+		<annotation cp='[โš ]' tts='warning'>warning</annotation>
+		<annotation cp='[๐Ÿšธ]' tts='children crossing'>child; crossing; pedestrian; traffic</annotation>
+		<annotation cp='[โ›”]' tts='no entry'>entry; forbidden; no; not; prohibited; traffic</annotation>
+		<annotation cp='[๐Ÿšซ]' tts='prohibited'>entry; forbidden; no; not</annotation>
+		<annotation cp='[๐Ÿšณ]' tts='no bicycles'>bicycle; bike; forbidden; no; not; prohibited; vehicle</annotation>
+		<annotation cp='[๐Ÿšญ]' tts='no smoking'>forbidden; no; not; prohibited; smoking</annotation>
+		<annotation cp='[๐Ÿšฏ]' tts='no littering'>forbidden; litter; no; not; prohibited</annotation>
+		<annotation cp='[๐Ÿšฑ]' tts='non-potable water'>drink; forbidden; no; not; potable; prohibited; water</annotation>
+		<annotation cp='[๐Ÿšท]' tts='no pedestrians'>forbidden; no; not; pedestrian; prohibited</annotation>
+		<annotation cp='[โ˜ข]' tts='radioactive'>radioactive</annotation>
+		<annotation cp='[โ˜ฃ]' tts='biohazard'>biohazard</annotation>
+		<annotation cp='[โฌ†]' tts='up arrow'>arrow; cardinal; direction; north</annotation>
+		<annotation cp='[โ†—]' tts='up-right arrow'>arrow; direction; intercardinal; northeast</annotation>
+		<annotation cp='[โžก]' tts='right arrow'>arrow; cardinal; direction; east</annotation>
+		<annotation cp='[โ†˜]' tts='down-right arrow'>arrow; direction; intercardinal; southeast</annotation>
+		<annotation cp='[โฌ‡]' tts='down arrow'>arrow; cardinal; direction; down; south</annotation>
+		<annotation cp='[โ†™]' tts='down-left arrow'>arrow; direction; intercardinal; southwest</annotation>
+		<annotation cp='[โฌ…]' tts='left arrow'>arrow; cardinal; direction; west</annotation>
+		<annotation cp='[โ†–]' tts='up-left arrow'>arrow; direction; intercardinal; northwest</annotation>
+		<annotation cp='[โ†•]' tts='up-down arrow'>arrow</annotation>
+		<annotation cp='[โ†”]' tts='left-right arrow'>arrow</annotation>
+		<annotation cp='[โ†ฉ]' tts='right arrow curving left'>arrow</annotation>
+		<annotation cp='[โ†ช]' tts='left arrow curving right'>arrow</annotation>
+		<annotation cp='[โคด]' tts='right arrow curving up'>arrow</annotation>
+		<annotation cp='[โคต]' tts='right arrow curving down'>arrow; down</annotation>
+		<annotation cp='[๐Ÿ”ƒ]' tts='clockwise vertical arrows'>arrow; clockwise; reload</annotation>
+		<annotation cp='[๐Ÿ”„]' tts='anticlockwise arrows button'>anticlockwise; arrow; counterclockwise; withershins</annotation>
+		<annotation cp='[๐Ÿ”™]' tts='back arrow'>arrow; back</annotation>
+		<annotation cp='[๐Ÿ”š]' tts='end arrow'>arrow; end</annotation>
+		<annotation cp='[๐Ÿ”›]' tts='on! arrow'>arrow; mark; on</annotation>
+		<annotation cp='[๐Ÿ”œ]' tts='soon arrow'>arrow; soon</annotation>
+		<annotation cp='[๐Ÿ”]' tts='top arrow'>arrow; top; up</annotation>
+		<annotation cp='[๐Ÿ›]' tts='place of worship'>religion; worship</annotation>
+		<annotation cp='[โš›]' tts='atom symbol'>atheist; atom</annotation>
+		<annotation cp='[๐Ÿ•‰]' tts='om'>hindu; religion</annotation>
+		<annotation cp='[โœก]' tts='star of david'>david; jew; jewish; religion; star</annotation>
+		<annotation cp='[โ˜ธ]' tts='wheel of dharma'>buddhist; dharma; religion; wheel</annotation>
+		<annotation cp='[โ˜ฏ]' tts='yin yang'>religion; tao; taoist; yang; yin</annotation>
+		<annotation cp='[โœ]' tts='latin cross'>christian; cross; religion</annotation>
+		<annotation cp='[โ˜ฆ]' tts='orthodox cross'>christian; cross; religion</annotation>
+		<annotation cp='[โ˜ช]' tts='star and crescent'>islam; muslim; religion</annotation>
+		<annotation cp='[โ˜ฎ]' tts='peace symbol'>peace</annotation>
+		<annotation cp='[๐Ÿ•Ž]' tts='menorah'>candelabrum; candlestick; religion</annotation>
+		<annotation cp='[๐Ÿ”ฏ]' tts='dotted six-pointed star'>fortune; star</annotation>
+		<annotation cp='[โ™ป]' tts='recycling symbol'>recycle</annotation>
+		<annotation cp='[๐Ÿ“›]' tts='name badge'>badge; name</annotation>
+		<annotation cp='[โšœ]' tts='fleur-de-lis'>fleur-de-lis</annotation>
+		<annotation cp='[๐Ÿ”ฐ]' tts='japanese symbol for beginner'>beginner; chevron; green; japanese; leaf; tool; yellow</annotation>
+		<annotation cp='[๐Ÿ”ฑ]' tts='trident emblem'>anchor; emblem; ship; tool; trident</annotation>
+		<annotation cp='[โญ•]' tts='heavy large circle'>circle; o</annotation>
+		<annotation cp='[โœ…]' tts='white heavy check mark'>check; mark</annotation>
+		<annotation cp='[โ˜‘]' tts='ballot box with check'>ballot; box; check</annotation>
+		<annotation cp='[โœ”]' tts='heavy check mark'>check; mark</annotation>
+		<annotation cp='[โœ–]' tts='heavy multiplication x'>cancel; multiplication; multiply; x</annotation>
+		<annotation cp='[โŒ]' tts='cross mark'>cancel; mark; multiplication; multiply; x</annotation>
+		<annotation cp='[โŽ]' tts='cross mark button'>mark; square</annotation>
+		<annotation cp='[โž•]' tts='heavy plus sign'>math; plus</annotation>
+		<annotation cp='[โž–]' tts='heavy minus sign'>math; minus</annotation>
+		<annotation cp='[โž—]' tts='heavy division sign'>division; math</annotation>
+		<annotation cp='[โžฐ]' tts='curly loop'>curl; loop</annotation>
+		<annotation cp='[โžฟ]' tts='double curly loop'>curl; double; loop</annotation>
+		<annotation cp='[ใ€ฝ]' tts='part alternation mark'>mark; part</annotation>
+		<annotation cp='[โœณ]' tts='eight-spoked asterisk'>asterisk</annotation>
+		<annotation cp='[โœด]' tts='eight-pointed star'>star</annotation>
+		<annotation cp='[โ‡]' tts='sparkle'>sparkle</annotation>
+		<annotation cp='[๐Ÿ’ฑ]' tts='currency exchange'>bank; currency; exchange; money</annotation>
+		<annotation cp='[๐Ÿ’ฒ]' tts='heavy dollar sign'>currency; dollar; money</annotation>
+		<annotation cp='[โ€ผ]' tts='double exclamation mark'>bangbang; exclamation; mark; punctuation</annotation>
+		<annotation cp='[โ‰]' tts='exclamation question mark'>exclamation; interrobang; mark; punctuation; question</annotation>
+		<annotation cp='[โ“]' tts='question mark'>mark; punctuation; question</annotation>
+		<annotation cp='[โ”]' tts='white question mark'>mark; outlined; punctuation; question</annotation>
+		<annotation cp='[โ•]' tts='white exclamation mark'>exclamation; mark; outlined; punctuation</annotation>
+		<annotation cp='[โ—]' tts='exclamation mark'>exclamation; mark; punctuation</annotation>
+		<annotation cp='[ใ€ฐ]' tts='wavy dash'>dash; punctuation; wavy</annotation>
+		<annotation cp='[ยฉ]' tts='copyright'>copyright</annotation>
+		<annotation cp='[ยฎ]' tts='registered'>registered</annotation>
+		<annotation cp='[โ„ข]' tts='trade mark'>mark; tm; trademark</annotation>
+		<annotation cp='[โ™ˆ]' tts='aries'>ram; zodiac</annotation>
+		<annotation cp='[โ™‰]' tts='taurus'>bull; ox; zodiac</annotation>
+		<annotation cp='[โ™Š]' tts='gemini'>twins; zodiac</annotation>
+		<annotation cp='[โ™‹]' tts='cancer'>crab; zodiac</annotation>
+		<annotation cp='[โ™Œ]' tts='leo'>lion; zodiac</annotation>
+		<annotation cp='[โ™]' tts='virgo'>maiden; virgin; zodiac</annotation>
+		<annotation cp='[โ™Ž]' tts='libra'>balance; justice; scales; zodiac</annotation>
+		<annotation cp='[โ™]' tts='scorpius'>scorpio; scorpion; zodiac</annotation>
+		<annotation cp='[โ™]' tts='sagittarius'>archer; zodiac</annotation>
+		<annotation cp='[โ™‘]' tts='capricorn'>goat; zodiac</annotation>
+		<annotation cp='[โ™’]' tts='aquarius'>bearer; water; zodiac</annotation>
+		<annotation cp='[โ™“]' tts='pisces'>fish; zodiac</annotation>
+		<annotation cp='[โ›Ž]' tts='ophiuchus'>bearer; serpent; snake; zodiac</annotation>
+		<annotation cp='[๐Ÿ”€]' tts='shuffle tracks button'>arrow; crossed</annotation>
+		<annotation cp='[๐Ÿ”]' tts='repeat button'>arrow; clockwise; repeat</annotation>
+		<annotation cp='[๐Ÿ”‚]' tts='repeat single button'>arrow; clockwise; once</annotation>
+		<annotation cp='[โ–ถ]' tts='play button'>arrow; play; right; triangle</annotation>
+		<annotation cp='[โฉ]' tts='fast-forword button'>arrow; double; fast; forward</annotation>
+		<annotation cp='[โญ]' tts='next track button'>arrow; next scene; next track; triangle</annotation>
+		<annotation cp='[โฏ]' tts='play or pause button'>arrow; pause; play; right; triangle</annotation>
+		<annotation cp='[โ—€]' tts='reverse button'>arrow; left; reverse; triangle</annotation>
+		<annotation cp='[โช]' tts='fast reverse button'>arrow; double; rewind</annotation>
+		<annotation cp='[โฎ]' tts='last track button'>arrow; previous scene; previous track; triangle</annotation>
+		<annotation cp='[๐Ÿ”ผ]' tts='up button'>arrow; button; red</annotation>
+		<annotation cp='[โซ]' tts='fast up button'>arrow; double</annotation>
+		<annotation cp='[๐Ÿ”ฝ]' tts='down button'>arrow; button; down; red</annotation>
+		<annotation cp='[โฌ]' tts='fast down button'>arrow; double; down</annotation>
+		<annotation cp='[โธ]' tts='pause button'>bar; double; pause; vertical</annotation>
+		<annotation cp='[โน]' tts='stop button'>square; stop</annotation>
+		<annotation cp='[โบ]' tts='record button'>circle; record</annotation>
+		<annotation cp='[โ]' tts='eject button'>eject</annotation>
+		<annotation cp='[๐ŸŽฆ]' tts='cinema'>camera; film; movie</annotation>
+		<annotation cp='[๐Ÿ”…]' tts='dim button'>brightness; dim; low</annotation>
+		<annotation cp='[๐Ÿ”†]' tts='bright button'>bright; brightness</annotation>
+		<annotation cp='[๐Ÿ“ถ]' tts='antenna bars'>antenna; bar; cell; mobile; phone; signal; telephone</annotation>
+		<annotation cp='[๐Ÿ“ต]' tts='no mobile phones'>cell; forbidden; mobile; no; not; phone; prohibited; telephone</annotation>
+		<annotation cp='[๐Ÿ“ณ]' tts='vibration mode'>cell; mobile; mode; phone; telephone; vibration</annotation>
+		<annotation cp='[๐Ÿ“ด]' tts='mobile phone off'>cell; mobile; off; phone; telephone</annotation>
+		<annotation cp='[{#โƒฃ}]' tts='keycap number'>hash; keycap; pound</annotation>
+		<annotation cp='[{*โƒฃ}]' tts='keycap asterisk'>asterisk; keycap; star</annotation>
+		<annotation cp='[{0โƒฃ}]' tts='keycap digit zero'>0; keycap; zero</annotation>
+		<annotation cp='[{1โƒฃ}]' tts='keycap digit one'>1; keycap; one</annotation>
+		<annotation cp='[{2โƒฃ}]' tts='keycap digit two'>2; keycap; two</annotation>
+		<annotation cp='[{3โƒฃ}]' tts='keycap digit three'>3; keycap; three</annotation>
+		<annotation cp='[{4โƒฃ}]' tts='keycap digit four'>4; four; keycap</annotation>
+		<annotation cp='[{5โƒฃ}]' tts='keycap digit five'>5; five; keycap</annotation>
+		<annotation cp='[{6โƒฃ}]' tts='keycap digit six'>6; keycap; six</annotation>
+		<annotation cp='[{7โƒฃ}]' tts='keycap digit seven'>7; keycap; seven</annotation>
+		<annotation cp='[{8โƒฃ}]' tts='keycap digit eight'>8; eight; keycap</annotation>
+		<annotation cp='[{9โƒฃ}]' tts='keycap digit nine'>9; keycap; nine</annotation>
+		<annotation cp='[๐Ÿ”Ÿ]' tts='keycap ten'>10; keycap; ten</annotation>
+		<annotation cp='[๐Ÿ’ฏ]' tts='hundred points'>100; full; hundred; score</annotation>
+		<annotation cp='[๐Ÿ”ž]' tts='no one under eighteen'>18; age restriction; eighteen; forbidden; no; not; prohibited; underage</annotation>
+		<annotation cp='[๐Ÿ” ]' tts='input latin uppercase'>input; latin; letters; uppercase</annotation>
+		<annotation cp='[๐Ÿ”ก]' tts='input latin lowercase'>abcd; input; latin; letters; lowercase</annotation>
+		<annotation cp='[๐Ÿ”ข]' tts='input numbers'>1234; input; numbers</annotation>
+		<annotation cp='[๐Ÿ”ฃ]' tts='input symbols'>input</annotation>
+		<annotation cp='[๐Ÿ”ค]' tts='input latin letters'>abc; alphabet; input; latin; letters</annotation>
+		<annotation cp='[๐Ÿ…ฐ]' tts='a button'>a; blood</annotation>
+		<annotation cp='[๐Ÿ†Ž]' tts='ab button'>ab; blood</annotation>
+		<annotation cp='[๐Ÿ…ฑ]' tts='b button'>b; blood</annotation>
+		<annotation cp='[๐Ÿ†‘]' tts='squared cl'>cl</annotation>
+		<annotation cp='[๐Ÿ†’]' tts='squared cool'>cool</annotation>
+		<annotation cp='[๐Ÿ†“]' tts='squared free'>free</annotation>
+		<annotation cp='[โ„น]' tts='information source'>i; information</annotation>
+		<annotation cp='[๐Ÿ†”]' tts='squared id'>id; identity</annotation>
+		<annotation cp='[โ“‚]' tts='circled letter m'>circle; m</annotation>
+		<annotation cp='[๐Ÿ†•]' tts='squared new'>new</annotation>
+		<annotation cp='[๐Ÿ†–]' tts='squared ng'>ng</annotation>
+		<annotation cp='[๐Ÿ…พ]' tts='o button'>blood; o</annotation>
+		<annotation cp='[๐Ÿ†—]' tts='squared ok'>ok</annotation>
+		<annotation cp='[๐Ÿ…ฟ]' tts='p button'>parking</annotation>
+		<annotation cp='[๐Ÿ†˜]' tts='squared sos'>help; sos</annotation>
+		<annotation cp='[๐Ÿ†™]' tts='up! button'>mark; up</annotation>
+		<annotation cp='[๐Ÿ†š]' tts='squared vs'>versus; vs</annotation>
+		<annotation cp='[๐Ÿˆ]' tts='squared katakana koko'>japanese</annotation>
+		<annotation cp='[๐Ÿˆ‚]' tts='squared katakana sa'>japanese</annotation>
+		<annotation cp='[๐Ÿˆท]' tts='squared moon ideograph'>japanese</annotation>
+		<annotation cp='[๐Ÿˆถ]' tts='squared exist ideograph'>japanese</annotation>
+		<annotation cp='[๐Ÿˆฏ]' tts='squared finger ideograph'>japanese</annotation>
+		<annotation cp='[๐Ÿ‰]' tts='circled advantage ideograph'>japanese</annotation>
+		<annotation cp='[๐Ÿˆน]' tts='squared divide ideograph'>japanese</annotation>
+		<annotation cp='[๐Ÿˆš]' tts='squared negation ideograph'>japanese</annotation>
+		<annotation cp='[๐Ÿˆฒ]' tts='squared prohibit ideograph'>japanese</annotation>
+		<annotation cp='[๐Ÿ‰‘]' tts='circled accept ideograph'>chinese</annotation>
+		<annotation cp='[๐Ÿˆธ]' tts='squared apply ideograph'>chinese</annotation>
+		<annotation cp='[๐Ÿˆด]' tts='squared together ideograph'>chinese</annotation>
+		<annotation cp='[๐Ÿˆณ]' tts='squared empty ideograph'>chinese</annotation>
+		<annotation cp='[ใŠ—]' tts='circled congratulate ideograph'>chinese; congratulation; congratulations; ideograph</annotation>
+		<annotation cp='[ใŠ™]' tts='circled secret ideograph'>chinese; ideograph; secret</annotation>
+		<annotation cp='[๐Ÿˆบ]' tts='squared operating ideograph'>chinese</annotation>
+		<annotation cp='[๐Ÿˆต]' tts='squared fullness ideograph'>chinese</annotation>
+		<annotation cp='[โ–ช]' tts='black small square'>geometric; square</annotation>
+		<annotation cp='[โ–ซ]' tts='white small square'>geometric; square</annotation>
+		<annotation cp='[โ—ป]' tts='white medium square'>geometric; square</annotation>
+		<annotation cp='[โ—ผ]' tts='black medium square'>geometric; square</annotation>
+		<annotation cp='[โ—ฝ]' tts='white medium-small square'>geometric; square</annotation>
+		<annotation cp='[โ—พ]' tts='black medium-small square'>geometric; square</annotation>
+		<annotation cp='[โฌ›]' tts='black large square'>geometric; square</annotation>
+		<annotation cp='[โฌœ]' tts='white large square'>geometric; square</annotation>
+		<annotation cp='[๐Ÿ”ถ]' tts='large orange diamond'>diamond; geometric; orange</annotation>
+		<annotation cp='[๐Ÿ”ท]' tts='large blue diamond'>blue; diamond; geometric</annotation>
+		<annotation cp='[๐Ÿ”ธ]' tts='small orange diamond'>diamond; geometric; orange</annotation>
+		<annotation cp='[๐Ÿ”น]' tts='small blue diamond'>blue; diamond; geometric</annotation>
+		<annotation cp='[๐Ÿ”บ]' tts='red triangle pointed up'>geometric; red</annotation>
+		<annotation cp='[๐Ÿ”ป]' tts='red triangle pointed down'>down; geometric; red</annotation>
+		<annotation cp='[๐Ÿ’ ]' tts='diamond with a dot'>comic; diamond; geometric; inside</annotation>
+		<annotation cp='[๐Ÿ”˜]' tts='radio button'>button; geometric; radio</annotation>
+		<annotation cp='[๐Ÿ”ฒ]' tts='black square button'>button; geometric; square</annotation>
+		<annotation cp='[๐Ÿ”ณ]' tts='white square button'>button; geometric; outlined; square</annotation>
+		<annotation cp='[โšช]' tts='white circle'>circle; geometric</annotation>
+		<annotation cp='[โšซ]' tts='black circle'>circle; geometric</annotation>
+		<annotation cp='[๐Ÿ”ด]' tts='red circle'>circle; geometric; red</annotation>
+		<annotation cp='[๐Ÿ”ต]' tts='blue circle'>blue; circle; geometric</annotation>
+	</annotations>
+</ldml>
\ No newline at end of file
diff --git a/ibus.spec.in b/ibus.spec.in
index 7fdaccb..40aead1 100644
--- a/ibus.spec.in
+++ b/ibus.spec.in
@@ -5,6 +5,7 @@
 
 # Build flags
 %define build_python_library 0
+%define build_emoji_dictionary 1
 
 %define glib_ver %([ -a %{_libdir}/pkgconfig/glib-2.0.pc ] && pkg-config --modversion glib-2.0 | cut -d. -f 1,2 || echo -n "999")
 %define gconf2_version 2.12.0
@@ -40,6 +41,10 @@ BuildRequires:  dconf-devel
 BuildRequires:  pygobject2-devel
 BuildRequires:  intltool
 BuildRequires:  iso-codes-devel
+%if %build_emoji_dictionary
+BuildRequires:  nodejs-emojione
+BuildRequires:  json-glib
+%endif
 
 Requires:   %{name}-libs = %{version}-%{release}
 Requires:   %{name}-gtk2 = %{version}-%{release}
@@ -151,6 +156,12 @@ OPTIONS="$OPTIONS --enable-python-library"
 %else
 OPTIONS="$OPTIONS --disable-python-library"
 %endif
+%if %build_emoji_dictionary
+OPTIONS="$OPTIONS --enable-emoji-dict"
+%else
+OPTIONS="$OPTIONS --disable-emoji-dict"
+%endif
+
 
 %configure $OPTIONS
 
@@ -258,6 +269,9 @@ dconf update &> /dev/null || :
 %{_bindir}/ibus-setup
 %{_datadir}/ibus/component/gtkpanel.xml
 %{_datadir}/ibus/component/simple.xml
+%if %build_emoji_dictionary
+%{_datadir}/ibus/dicts
+%endif
 %{_datadir}/ibus/keymaps/*
 %{_datadir}/ibus/setup/*
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 22e031f..b58ab95 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -29,15 +29,6 @@ endif
 
 SUBDIRS = . $(TESTS_DIR)
 
-IBUS_V_wget = $(ibus__v_wget_@AM_V@)
-ibus__v_wget_ = $(ibus__v_wget_@AM_DEFAULT_V@)
-ibus__v_wget_0 = -nv
-ibus__v_wget_1 =
-IBUS_V_diff = $(ibus__v_diff_@AM_V@)
-ibus__v_diff_ = $(ibus__v_diff_@AM_DEFAULT_V@)
-ibus__v_diff_0 = -q
-ibus__v_diff_1 =
-
 # libibus = libibus-@IBUS_API_VERSION@.la
 libibus = libibus-1.0.la
 
@@ -248,37 +239,25 @@ dict_DATA = emoji.dict
 
 noinst_PROGRAMS = emoji-parser
 
-emoji-list.html:
-	$(AM_V_at)wget $(IBUS_V_wget) \
-                http://ibus.github.io/files/ibus/emoji-list.html
-	$(AM_V_at)wget $(IBUS_V_wget) \
-                http://unicode.org/emoji/charts/emoji-list.html \
-	        -O latest-emoji-list.html
-	$(AM_V_at)diff $(IBUS_V_diff) emoji-list.html latest-emoji-list.html; \
-	if test $$? -ne 0; then \
-	    echo "#### WARNING: emoji-list.html is old." >&2; \
-	fi; \
-	rm latest-emoji-list.html;
-
-emoji.dict: emoji-parser emoji-list.html
-	$(builddir)/emoji-parser emoji-list.html $@
+emoji.dict: emoji-parser
+	$(builddir)/emoji-parser --xml $(srcdir)/../data/annotations/en.xml \
+	--json $(EMOJI_JSON_FILE) --out $@
 
 emoji_parser_SOURCES =          \
     emoji-parser.c              \
     $(NULL)
 emoji_parser_CFLAGS =           \
     $(GLIB2_CFLAGS)             \
-    $(LIBXML2_CFLAGS)           \
+    $(JSON_GLIB1_CFLAGS)        \
     $(NULL)
 emoji_parser_LDADD =            \
     $(GLIB2_LIBS)               \
-    $(LIBXML2_LIBS)             \
+    $(JSON_GLIB1_LIBS)          \
     $(libibus)                  \
     $(NULL)
 
 CLEANFILES +=                   \
     $(dict_DATA)                \
-    emoji-list.html             \
     $(NULL)
 endif
 
diff --git a/src/emoji-parser.c b/src/emoji-parser.c
index cf92fee..e97f266 100644
--- a/src/emoji-parser.c
+++ b/src/emoji-parser.c
@@ -20,47 +20,59 @@
  * USA
  */
 
-/* Convert http://www.unicode.org/emoji/charts/emoji-list.html
+/* Convert ../data/annotations/en.xml and
+ * /usr/lib/node_modules/emojione/emoji.json
  * to the dictionary file which look up the Emoji from the annotation.
+ * Get emoji.json with 'npm install -g emojione'.
+ * en.xml is used for the Unicode annotations and emoji.json is used
+ * for the aliases_ascii, e.g. ":)", and category, e.g. "people".
  */
 
 #include <glib.h>
-#include <libxml/HTMLparser.h>
-#include <libgen.h>
+#include <json-glib/json-glib.h>
+
+#include <string.h>
 
 #include "ibusutil.h"
 
 typedef struct _EmojiData EmojiData;
 struct _EmojiData {
-    gchar      *class;
     gchar      *emoji;
-    GSList     *annotates;
-    GSList     *prev_annotates;
+    GSList     *annotations;
+    gboolean    is_annotation;
     GHashTable *dict;
 };
 
-const gchar *progname;
-
-static gboolean         parse_node             (xmlNode     *node,
-                                                gboolean     is_child,
-                                                const gchar *prop_name,
-                                                EmojiData   *data);
-
 static void
-usage (void)
+reset_emoji_element (EmojiData *data)
 {
-    g_print ("%s emoji-list.html emoji.dict\n", progname);
+    g_assert (data != NULL);
+
+    g_clear_pointer (&data->emoji, g_free);
+    g_slist_free_full (data->annotations, g_free);
+    data->annotations = NULL;
 }
 
 static void
-reset_emoji_element (EmojiData *data)
+update_emoji_dict (EmojiData *data)
 {
-    g_clear_pointer (&data->class, g_free);
-    g_clear_pointer (&data->emoji, g_free);
-    if (data->annotates) {
-        g_slist_free_full (data->prev_annotates, g_free);
-        data->prev_annotates = data->annotates;
-        data->annotates = NULL;
+    GSList *annotations = data->annotations;
+    while (annotations) {
+        const gchar *annotation = (const gchar *) annotations->data;
+        GSList *emojis = g_hash_table_lookup (data->dict, annotation);
+        if (emojis) {
+            GSList *duplicated = g_slist_find_custom (emojis,
+                                                      data->emoji,
+                                                      (GCompareFunc) g_strcmp0);
+            if (duplicated != NULL)
+                 continue;
+            emojis = g_slist_copy_deep (emojis, (GCopyFunc) g_strdup, NULL);
+        }
+        emojis = g_slist_append (emojis, g_strdup (data->emoji));
+        g_hash_table_replace (data->dict,
+                              g_strdup (annotation),
+                              emojis);
+        annotations = annotations->next;
     }
 }
 
@@ -70,147 +82,486 @@ free_dict_words (gpointer list)
     g_slist_free_full (list, g_free);
 }
 
-static gboolean
-parse_attr (xmlAttr   *attr,
-            EmojiData *data)
-{
-    if (g_strcmp0 ((const gchar *) attr->name, "class") == 0 && attr->children)
-        parse_node (attr->children, TRUE, (const gchar *) attr->name, data);
-    if (g_strcmp0 ((const gchar *) attr->name, "target") == 0 && attr->children)
-        parse_node (attr->children, TRUE, (const gchar *) attr->name, data);
-    if (attr->next)
-        parse_attr (attr->next, data);
-    return TRUE;
-}
+static void
+unicode_annotations_start_element_cb (GMarkupParseContext *context,
+                                      const gchar         *element_name,
+                                      const gchar        **attribute_names,
+                                      const gchar        **attribute_values,
+                                      gpointer             user_data,
+                                      GError             **error)
+{
+    EmojiData *data = (EmojiData *) user_data;
+    int i;
+    const gchar *attribute;
+    const gchar *value;
 
-static gboolean
-parse_node (xmlNode     *node,
-            gboolean     is_child,
-            const gchar *prop_name,
-            EmojiData   *data)
-{
-    if (g_strcmp0 ((const gchar *) node->name, "tr") == 0) {
-        GSList *annotates = data->annotates;
-        while (annotates) {
-            GSList *emojis = g_hash_table_lookup (data->dict, annotates->data);
-            if (emojis) {
-                emojis = g_slist_copy_deep (emojis, (GCopyFunc) g_strdup, NULL);
+    g_assert (data != NULL);
+
+    if (g_strcmp0 (element_name, "annotation") != 0)
+        return;
+
+    reset_emoji_element (data);
+
+    for (i = 0; (attribute = attribute_names[i]) != NULL; i++) {
+        value = attribute_values[i];
+
+        if (g_strcmp0 (attribute, "cp") == 0) {
+            if (value == NULL || *value == '\0') {
+                g_warning ("cp='' in unicode.org annotations file");
+                return;
+            } else if (value[0] != '[' || value[strlen(value) - 1] != ']') {
+                g_warning ("cp!='[emoji]' in unicode.org annotations file");
+                return;
             }
-            emojis = g_slist_append (emojis, g_strdup (data->emoji));
-            g_hash_table_replace (data->dict,
-                                  g_strdup (annotates->data),
-                                  emojis);
-            annotates = annotates->next;
+            data->emoji = g_strndup (value + 1, strlen(value) - 2);
         }
-        reset_emoji_element (data);
-    }
-    /* if node->name is "text" and is_child is FALSE,
-     * it's '\n' or Space between <td> and <td>.
-     */
-    if (g_strcmp0 ((const gchar *) node->name, "text") == 0 && is_child) {
-        /* Get "chars" in <td class="chars"> */
-        if (g_strcmp0 (prop_name, "class") == 0) {
-            if (g_strcmp0 (data->class, (const gchar *) node->content) != 0) {
-                g_clear_pointer (&data->class, g_free);
-                data->class = g_strdup ((const gchar *) node->content);
+        else if (g_strcmp0 (attribute, "tts") == 0) {
+            GSList *duplicated = g_slist_find_custom (data->annotations,
+                                                      value,
+                                                      (GCompareFunc) g_strcmp0);
+            if (duplicated == NULL) {
+                data->annotations = g_slist_prepend (data->annotations,
+                                                     g_strdup (value));
             }
         }
-        /* Get "annotate" in <td class="name"><a target="annotate"> */
-        if (g_strcmp0 (prop_name, "target") == 0 &&
-            g_strcmp0 (data->class, "name") == 0) {
-            g_clear_pointer (&data->class, g_free);
-            data->class = g_strdup ((const gchar *) node->content);
-        }
-        /* Get "emoji" in <td class="chars">emoji</td> */
-        if (g_strcmp0 (prop_name, "td") == 0 &&
-            g_strcmp0 (data->class, "chars") == 0) {
-            data->emoji = g_strdup ((const gchar *) node->content);
-        }
-        /* We ignore "NAME" for <td class="name">NAME</td> but
-         * takes "ANNOTATE" for
-         * <td class="name"><a target="annotate">ANNOTATE</a></td>
-         */
-        if (g_strcmp0 (prop_name, "td") == 0 &&
-            g_strcmp0 (data->class, "name") == 0) {
-            g_slist_free_full (data->annotates, g_free);
-            data->annotates = NULL;
+    }
+
+    data->is_annotation = TRUE;
+}
+
+static void
+unicode_annotations_end_element_cb (GMarkupParseContext *context,
+                                    const gchar         *element_name,
+                                    gpointer             user_data,
+                                    GError             **error)
+{
+    EmojiData *data = (EmojiData *) user_data;
+
+    g_assert (data != NULL);
+    if (!data->is_annotation)
+        return;
+
+    update_emoji_dict (data);
+    data->is_annotation = FALSE;
+}
+
+void
+unicode_annotations_text_cb (GMarkupParseContext *context,
+                             const gchar         *text,
+                             gsize                text_len,
+                             gpointer             user_data,
+                             GError             **error)
+{
+    EmojiData *data = (EmojiData *) user_data;
+    gchar **annotations = NULL;
+    const gchar *annotation;
+    int i;
+
+    g_assert (data != NULL);
+    if (!data->is_annotation)
+        return;
+    annotations = g_strsplit (text, "; ", -1);
+    for (i = 0; (annotation = annotations[i]) != NULL; i++) {
+        GSList *duplicated = g_slist_find_custom (data->annotations,
+                                                  annotation,
+                                                  (GCompareFunc) g_strcmp0);
+        if (duplicated == NULL) {
+            data->annotations = g_slist_prepend (data->annotations,
+                                                 g_strdup (annotation));
         }
-        /* Get "ANNOTATE" in
-         * <td class="name"><a target="annotate">ANNOTATE</a></td>
-         */
-        if (g_strcmp0 (prop_name, "a") == 0 &&
-            g_strcmp0 (data->class, "annotate") == 0) {
-            data->annotates =
-                    g_slist_append (data->annotates,
-                                    g_strdup ((const gchar *) node->content));
+    }
+    g_strfreev (annotations);
+}
+
+static gboolean
+unicode_annotations_parse_xml_file (const gchar *filename,
+                                    GHashTable  *dict)
+{
+    gchar *content = NULL;
+    gsize length = 0;
+    GError *error = NULL;
+    const static GMarkupParser parser = {
+        unicode_annotations_start_element_cb,
+        unicode_annotations_end_element_cb,
+        unicode_annotations_text_cb,
+        NULL,
+        NULL
+    };
+    GMarkupParseContext *context = NULL;
+    EmojiData data = { 0, };
+
+    g_return_val_if_fail (filename != NULL, FALSE);
+    g_return_val_if_fail (dict != NULL, FALSE);
+
+    if (!g_file_get_contents (filename, &content, &length, &error)) {
+        g_warning ("Failed to load %s: %s", filename, error->message);
+        goto failed_to_parse_unicode_annotations;
+    }
+
+    data.dict = dict;
+
+    context = g_markup_parse_context_new (&parser, 0, &data, NULL);
+    if (!g_markup_parse_context_parse (context, content, length, &error)) {
+        g_warning ("Failed to parse %s: %s", filename, error->message);
+        goto failed_to_parse_unicode_annotations;
+    }
+
+    reset_emoji_element (&data);
+    g_markup_parse_context_free (context);
+    g_free (content);
+    return TRUE;
+
+failed_to_parse_unicode_annotations:
+    if (error)
+        g_error_free (error);
+    if (data.dict)
+        g_hash_table_destroy (data.dict);
+    if (context)
+        g_markup_parse_context_free (context);
+    g_free (content);
+    return FALSE;
+}
+
+static gboolean
+parse_emojione_unicode (JsonNode  *node,
+                        EmojiData *data)
+{
+    const gchar *str, *unicode;
+    gchar *endptr = NULL;
+    guint32 uch;
+    static gchar outbuf[8] = { 0, };
+    GString *emoji;
+
+    if (json_node_get_node_type (node) != JSON_NODE_VALUE) {
+        g_warning ("'unicode' element is not string");
+        return FALSE;
+    }
+
+    emoji = g_string_new (NULL);
+    str = unicode = json_node_get_string (node);
+    while (str && *str) {
+        uch = g_ascii_strtoull (str, &endptr, 16);
+        outbuf[g_unichar_to_utf8 (uch, outbuf)] = '\0';
+        g_string_append (emoji, outbuf);
+        if (*endptr == '\0') {
+            break;
+        } else {
+            switch (*endptr) {
+            case '-':
+                endptr++;
+                break;
+            default:
+                g_warning ("Failed to parse unicode %s", unicode);
+            }
         }
+        str = endptr;
+        endptr = NULL;
+    }
+
+    data->emoji = g_string_free (emoji, FALSE);
+
+    return TRUE;
+}
+
+static gboolean
+parse_emojione_shortname (JsonNode  *node,
+                          EmojiData *data)
+{
+#if 0
+    const gchar *shortname;
+    gchar *head, *s;
+    int length;
+    GSList *duplicated;
+
+    if (json_node_get_node_type (node) != JSON_NODE_VALUE) {
+        g_warning ("'shortname' element is not string");
+        return FALSE;
     }
-    /* Get "foo" in <td class="foo"> */
-    if (g_strcmp0 ((const gchar *) node->name, "td") == 0 &&
-        node->properties != NULL) {
-        parse_attr (node->properties, data);
+
+    /* The format is ':short_name:' */
+    shortname = json_node_get_string (node);
+    if (shortname == 0 || *shortname == '\0')
+        return TRUE;
+    if (*shortname != ':') {
+        g_warning ("'shortname' format is different: %s", shortname);
+        return FALSE;
     }
-    /* Get "foo" in <a target="foo"> */
-    if (g_strcmp0 ((const gchar *) node->name, "a") == 0 &&
-        node->properties != NULL) {
-        parse_attr (node->properties, data);
+
+    length = strlen (shortname);
+    head  = g_new0 (gchar, length);
+    strcpy (head, shortname + 1);
+    for (s = head; *s; s++) {
+        if (*s == ':') {
+            *s = '\0';
+            break;
+        } else if (*s == '_') {
+            *s = ' ';
+        }
     }
-    if (node->children) {
-        parse_node (node->children, TRUE, (const gchar *) node->name, data);
+
+    if (head == NULL || *head == '\0') {
+        g_warning ("'shortname' format is different: %s", shortname);
+        g_free (head);
+        return FALSE;
+    }
+
+    duplicated = g_slist_find_custom (data->annotations,
+                                      head,
+                                      (GCompareFunc) g_strcmp0);
+    if (duplicated == NULL) {
+        data->annotations = g_slist_prepend (data->annotations,
+                                             head);
     } else {
-        /* If annotate is NULL likes <td class="name"></td>,
-         * the previous emoji cell has the same annotate.
-         */
-        if (g_strcmp0 ((const gchar *) node->name, "td") == 0 &&
-            g_strcmp0 (data->class, "name") == 0) {
-            data->annotates = g_slist_copy_deep (data->prev_annotates,
-                                                 (GCopyFunc) g_strdup,
-                                                 NULL);
+       g_free (head);
+    }
+
+#endif
+    return TRUE;
+}
+
+static gboolean
+parse_emojione_category (JsonNode  *node,
+                         EmojiData *data)
+{
+    const gchar *category;
+    GSList *duplicated;
+
+    if (json_node_get_node_type (node) != JSON_NODE_VALUE) {
+        g_warning ("'category' element is not string");
+        return FALSE;
+    }
+
+    category = json_node_get_string (node);
+
+    if (category == NULL || *category == '\0')
+        return TRUE;
+
+    duplicated = g_slist_find_custom (data->annotations,
+                                      category,
+                                      (GCompareFunc) g_strcmp0);
+    if (duplicated == NULL) {
+        data->annotations = g_slist_prepend (data->annotations,
+                                             g_strdup (category));
+    }
+
+    return TRUE;
+}
+
+static gboolean
+parse_emojione_aliases_ascii (JsonNode  *node,
+                              EmojiData *data)
+{
+    JsonArray *aliases_ascii;
+    guint i, length;
+
+    if (json_node_get_node_type (node) != JSON_NODE_ARRAY) {
+        g_warning ("'aliases_ascii' element is not array");
+        return FALSE;
+    }
+
+    aliases_ascii = json_node_get_array (node);
+    length = json_array_get_length (aliases_ascii);
+    for (i = 0; i < length; i++) {
+        const gchar *alias = json_array_get_string_element (aliases_ascii, i);
+        GSList *duplicated = g_slist_find_custom (data->annotations,
+                                                  alias,
+                                                  (GCompareFunc) g_strcmp0);
+        if (duplicated == NULL) {
+            data->annotations = g_slist_prepend (data->annotations,
+                                                 g_strdup (alias));
         }
     }
-    if (node->next)
-        parse_node (node->next, FALSE, (const gchar *) node->name, data);
 
     return TRUE;
 }
 
-static GHashTable *
-parse_html (const gchar *filename)
+static gboolean
+parse_emojione_keywords (JsonNode  *node,
+                         EmojiData *data)
 {
-    xmlDoc *doc = htmlParseFile (filename, "utf-8");
-    EmojiData data = { 0, };
+#if 0
+    JsonArray *keywords;
+    guint i, length;
 
-    if (doc == NULL || doc->children == NULL) {
-        g_warning ("Parse Error in document type: %x",
-                   doc ? doc->type : 0);
+    if (json_node_get_node_type (node) != JSON_NODE_ARRAY) {
+        g_warning ("'keywords' element is not array");
         return FALSE;
     }
 
-    data.dict = g_hash_table_new_full (g_str_hash,
-                                       g_str_equal,
-                                       g_free,
-                                       free_dict_words);
-    parse_node (doc->children, TRUE, (const gchar *) doc->name, &data);
+    keywords = json_node_get_array (node);
+    length = json_array_get_length (keywords);
+    for (i = 0; i < length; i++) {
+        const gchar *keyword = json_array_get_string_element (keywords, i);
+        GSList *duplicated = g_slist_find_custom (data->annotations,
+                                                  keyword,
+                                                  (GCompareFunc) g_strcmp0);
+        if (duplicated == NULL) {
+            data->annotations = g_slist_prepend (data->annotations,
+                                                 g_strdup (keyword));
+        }
+    }
 
+#endif
+    return TRUE;
+}
+
+static gboolean
+parse_emojione_emoji_data (JsonNode    *node,
+                           const gchar *member,
+                           EmojiData   *data)
+{
+    if (g_strcmp0 (member, "unicode") == 0)
+        return parse_emojione_unicode (node, data);
+    else if (g_strcmp0 (member, "shortname") == 0)
+        return parse_emojione_shortname (node, data);
+    else if (g_strcmp0 (member, "category") == 0)
+        return parse_emojione_category (node, data);
+    else if (g_strcmp0 (member, "aliases_ascii") == 0)
+        return parse_emojione_aliases_ascii (node, data);
+    else if (g_strcmp0 (member, "keywords") == 0)
+        return parse_emojione_keywords (node, data);
+    return TRUE;
+}
+
+static gboolean
+parse_emojione_element (JsonNode  *node,
+                        EmojiData *data)
+{
+    JsonObject *object;
+    GList *members, *m;
+
+    if (json_node_get_node_type (node) != JSON_NODE_OBJECT) {
+            return FALSE;
+    }
+
+    reset_emoji_element (data);
+
+    object = json_node_get_object (node);
+    m = members = json_object_get_members (object);
+    while (m) {
+       const gchar *member = (const gchar *) m->data;
+       if (!parse_emojione_emoji_data (json_object_get_member (object, member),
+                                       member,
+                                       data)) {
+           g_list_free (members);
+           return FALSE;
+       }
+       m = m->next;
+    }
+    g_list_free (members);
+
+    update_emoji_dict (data);
+
+    return TRUE;
+}
+
+static gboolean
+emojione_parse_json_file (const gchar *filename,
+                          GHashTable  *dict)
+{
+    JsonParser *parser = json_parser_new ();
+    JsonNode *node;
+    JsonObject *object;
+    GList *members, *m;
+    GError *error = NULL;
+    EmojiData data = { 0, };
+
+    g_return_val_if_fail (filename != NULL, FALSE);
+    g_return_val_if_fail (dict != NULL, FALSE);
+
+    if (!json_parser_load_from_file (parser, filename, &error)) {
+        g_error ("%s", error->message);
+        g_error_free (error);
+        goto fail_to_json_file;
+    }
+
+    node = json_parser_get_root (parser);
+    if (json_node_get_node_type (node) != JSON_NODE_OBJECT) {
+        g_warning ("Json file does not have Json object %s", filename);
+        goto fail_to_json_file;
+    }
+
+    object = json_node_get_object (node);
+    members = json_object_get_members (object);
+    data.dict = dict;
+
+    m = members;
+    while (m) {
+       const gchar *member = (const gchar *) m->data;
+       if (!parse_emojione_element (json_object_get_member (object, member),
+                                    &data)) {
+           g_warning ("Failed to parse member '%s' in %s", member, filename);
+       }
+       m = m->next;
+    }
+
+    g_list_free (members);
     reset_emoji_element (&data);
-    g_slist_free_full (data.prev_annotates, g_free);
+    g_object_unref (parser);
+
+    return TRUE;
 
-    return data.dict;
+fail_to_json_file:
+    g_object_unref (parser);
+    return FALSE;
 }
 
 int
 main (int argc, char *argv[])
 {
+    gchar *prgname;
+    gchar *json_file = NULL;
+    gchar *xml_file = NULL;
+    gchar *output = NULL;
+    GOptionEntry     entries[] = {
+        { "json", 'j', 0, G_OPTION_ARG_STRING, &json_file,
+          "Parse Emoji One JSON file",
+          "JSON"
+        },
+        { "out", 'o', 0, G_OPTION_ARG_STRING, &output,
+          "Save the emoji dictionary as FILE",
+          "FILE"
+        },
+        { "xml", 'x', 0, G_OPTION_ARG_STRING, &xml_file,
+          "Parse Unocode.org ANNOTATIONS file",
+          "ANNOTATIONS"
+        },
+        { NULL }
+    };
+    GOptionContext *context;
+    GError *error = NULL;
     GHashTable *dict;
-    progname = basename (argv[0]);
+
+    prgname = g_path_get_basename (argv[0]);
+    g_set_prgname (prgname);
+    g_free (prgname);
+
+    context = g_option_context_new (NULL);
+    g_option_context_add_main_entries (context, entries, NULL);
 
     if (argc < 3) {
-        usage ();
+        g_print ("%s", g_option_context_get_help (context, TRUE, NULL));
+        g_option_context_free (context);
+        return -1;
+    }
+
+    if (!g_option_context_parse (context, &argc, &argv, &error)) {
+        g_warning ("Failed options: %s", error->message);
+        g_error_free (error);
         return -1;
     }
+    g_option_context_free (context);
 
-    dict = parse_html (argv[1]);
-    ibus_emoji_dict_save (argv[2], dict);
+    dict = g_hash_table_new_full (g_str_hash,
+                                  g_str_equal,
+                                  g_free,
+                                  free_dict_words);
+    if (xml_file)
+        unicode_annotations_parse_xml_file (xml_file, dict);
+    if (json_file)
+        emojione_parse_json_file (json_file, dict);
+    if (g_hash_table_size (dict) > 0 && output)
+        ibus_emoji_dict_save (output, dict);
     g_hash_table_destroy (dict);
 
     return 0;
-- 
2.7.4

From f88c48750538eaaf7c7b182ba3763b45c2745074 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
Date: Wed, 20 Jul 2016 11:43:49 +0900
Subject: [PATCH 4/4] Fix typo in configure.ac

R=shawn.p.huang@gmail.com

Review URL: https://codereview.appspot.com/303110043
---
 configure.ac | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index f789819..76897f0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -647,7 +647,7 @@ engine/Makefile
 util/Makefile
 util/IMdkit/Makefile
 data/Makefile
-data/annotations/Makefile.am
+data/annotations/Makefile
 data/icons/Makefile
 data/keymaps/Makefile
 data/dconf/Makefile
-- 
2.7.4